def test_api_stats(self, client: FlaskClient, faker: Faker) -> None: # setup the test env ( admin_headers, uuid_group_A, user_A1_uuid, user_A1_headers, uuid_group_B, user_B1_uuid, user_B1_headers, user_B2_uuid, user_B2_headers, study1_uuid, study2_uuid, ) = create_test_env(client, faker, study=True) # create a dataset for group A dataset_A = {"name": faker.pystr(), "description": faker.pystr()} r = client.post( f"{API_URI}/study/{study2_uuid}/datasets", headers=user_A1_headers, data=dataset_A, ) assert r.status_code == 200 dataset_A_uuid = self.get_content(r) assert isinstance(dataset_A_uuid, str) # create a dataset for group B dataset_B = {"name": faker.pystr(), "description": faker.pystr()} r = client.post( f"{API_URI}/study/{study1_uuid}/datasets", headers=user_B1_headers, data=dataset_B, ) assert r.status_code == 200 dataset_B_uuid = self.get_content(r) assert isinstance(dataset_B_uuid, str) # init an upload in dataset A fake_filename = f"{faker.pystr()}_R1" fake_file = { "name": f"{fake_filename}.fastq.gz", "mimeType": "application/gzip", "size": faker.pyint(), "lastModified": faker.pyint(), } r = client.post( f"{API_URI}/dataset/{dataset_A_uuid}/files/upload", headers=user_A1_headers, data=fake_file, ) assert r.status_code == 201 # init an upload in dataset B r = client.post( f"{API_URI}/dataset/{dataset_B_uuid}/files/upload", headers=user_B1_headers, data=fake_file, ) assert r.status_code == 201 # test without group filter # public stats NIGEndpoint.GROUPS_TO_FILTER = [] r = client.get(f"{API_URI}/stats/public", ) assert r.status_code == 200 full_public_stats = self.get_content(r) assert isinstance(full_public_stats, dict) assert full_public_stats["num_users"] > 0 assert full_public_stats["num_studies"] > 0 assert full_public_stats["num_datasets"] > 0 assert full_public_stats["num_files"] > 0 # private stats r = client.get( f"{API_URI}/stats/private", headers=user_B1_headers, ) private_stats = self.get_content(r) assert isinstance(private_stats, dict) assert private_stats["num_users"] > 0 assert private_stats["num_studies"] > 0 assert private_stats["num_datasets"] > 0 assert private_stats["num_files"] > 0 # exclude test group NIGEndpoint.GROUPS_TO_FILTER = ["Default group"] # test public stats r = client.get(f"{API_URI}/stats/public", ) assert r.status_code == 200 public_stats = self.get_content(r) assert isinstance(public_stats, dict) assert public_stats["num_users"] == 3 assert public_stats["num_studies"] == 2 assert public_stats["num_datasets"] == 2 assert public_stats["num_files"] == 2 # test authentication for private stats r = client.get(f"{API_URI}/stats/private", ) assert r.status_code == 401 # test private stats r = client.get( f"{API_URI}/stats/private", headers=user_B1_headers, ) private_stats = self.get_content(r) assert isinstance(private_stats, dict) assert private_stats["num_users"] == 3 assert private_stats["num_studies"] == 2 assert private_stats["num_datasets"] == 2 assert private_stats["num_files"] == 2 # get group fullnames graph = neo4j.get_instance() group_A = graph.Group.nodes.get_or_none(uuid=uuid_group_A) group_A_fullname = group_A.fullname group_B = graph.Group.nodes.get_or_none(uuid=uuid_group_B) group_B_fullname = group_B.fullname assert private_stats["num_datasets_per_group"][group_A_fullname] == 1 assert private_stats["num_datasets_per_group"][group_B_fullname] == 1 # check the excluded group not in responses assert "Default group" not in private_stats["num_datasets_per_group"] # test empty stats NIGEndpoint.GROUPS_TO_FILTER.append(group_A_fullname) NIGEndpoint.GROUPS_TO_FILTER.append(group_B_fullname) # public r = client.get(f"{API_URI}/stats/public", ) assert r.status_code == 200 public_stats = self.get_content(r) assert isinstance(public_stats, dict) assert public_stats["num_users"] == 0 assert public_stats["num_studies"] == 0 assert public_stats["num_datasets"] == 0 assert public_stats["num_files"] == 0 # private r = client.get( f"{API_URI}/stats/private", headers=user_B1_headers, ) private_stats = self.get_content(r) assert isinstance(private_stats, dict) assert private_stats["num_users"] == 0 assert private_stats["num_studies"] == 0 assert private_stats["num_datasets"] == 0 assert private_stats["num_files"] == 0 assert group_A_fullname not in private_stats["num_datasets_per_group"] assert group_B_fullname not in private_stats["num_datasets_per_group"] # delete all the elements used by the test delete_test_env( client, user_A1_headers, user_B1_headers, user_B1_uuid, user_B2_uuid, user_A1_uuid, uuid_group_A, uuid_group_B, study1_uuid=study1_uuid, study2_uuid=study2_uuid, )
def test_api_phenotype(self, client: FlaskClient, faker: Faker) -> None: # setup the test env ( admin_headers, uuid_group_A, user_A1_uuid, user_A1_headers, uuid_group_B, user_B1_uuid, user_B1_headers, user_B2_uuid, user_B2_headers, study1_uuid, study2_uuid, ) = create_test_env(client, faker, study=True) # create a new phenotype with wrong age phenotype1 = { "name": faker.pystr(), "age": -2, "sex": "male", } r = client.post( f"{API_URI}/study/{study1_uuid}/phenotypes", headers=user_B1_headers, data=phenotype1, ) assert r.status_code == 400 # create a new phenotype phenotype1["age"] = faker.pyint(0, 100) r = client.post( f"{API_URI}/study/{study1_uuid}/phenotypes", headers=user_B1_headers, data=phenotype1, ) assert r.status_code == 200 phenotype1_uuid = self.get_content(r) assert isinstance(phenotype1_uuid, str) # create a new phenotype in a study of an other group r = client.post( f"{API_URI}/study/{study2_uuid}/phenotypes", headers=user_B1_headers, data=phenotype1, ) assert r.status_code == 404 # create a new phenotype as admin not belonging to study group phenotype2 = { "name": faker.pystr(), "age": faker.pyint(0, 100), "sex": "female", } r = client.post( f"{API_URI}/study/{study1_uuid}/phenotypes", headers=admin_headers, data=phenotype2, ) assert r.status_code == 404 # create a phenotype with a geodata and a list of hpo graph = neo4j.get_instance() geodata_nodes = graph.GeoData.nodes geodata_uuid = geodata_nodes[0].uuid hpo_nodes = graph.HPO.nodes hpo1_id = hpo_nodes[0].hpo_id hpo2_id = hpo_nodes[1].hpo_id phenotype2["birth_place"] = geodata_uuid phenotype2["hpo"] = [hpo1_id, hpo2_id] phenotype2["hpo"] = json.dumps(phenotype2["hpo"]) r = client.post( f"{API_URI}/study/{study1_uuid}/phenotypes", headers=user_B1_headers, data=phenotype2, ) assert r.status_code == 200 phenotype2_uuid = self.get_content(r) assert isinstance(phenotype2_uuid, str) # test phenotype access # test phenotype list response r = client.get(f"{API_URI}/study/{study1_uuid}/phenotypes", headers=user_B1_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, list) assert len(response) == 2 # test phenotype list response for a study you don't have access r = client.get(f"{API_URI}/study/{study2_uuid}/phenotypes", headers=user_B1_headers) assert r.status_code == 404 # test phenotype list response for admin r = client.get(f"{API_URI}/study/{study1_uuid}/phenotypes", headers=admin_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, list) assert len(response) == 2 # test empty list of phenotypes in a study r = client.get(f"{API_URI}/study/{study2_uuid}/phenotypes", headers=user_A1_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, list) assert not response # study owner r = client.get(f"{API_URI}/phenotype/{phenotype1_uuid}", headers=user_B1_headers) assert r.status_code == 200 # same group of the study owner r = client.get(f"{API_URI}/phenotype/{phenotype2_uuid}", headers=user_B2_headers) assert r.status_code == 200 # check hpo and geodata were correctly linked response = self.get_content(r) assert isinstance(response, dict) assert response["birth_place"]["uuid"] == geodata_uuid assert len(response["hpo"]) == 2 hpo_list = [] for el in response["hpo"]: hpo_list.append(el["hpo_id"]) assert hpo1_id in hpo_list assert hpo2_id in hpo_list # phenotype owned by an other group r = client.get(f"{API_URI}/phenotype/{phenotype1_uuid}", headers=user_A1_headers) assert r.status_code == 404 not_authorized_message = self.get_content(r) assert isinstance(not_authorized_message, str) # admin access r = client.get(f"{API_URI}/phenotype/{phenotype1_uuid}", headers=admin_headers) assert r.status_code == 200 # test phenotype modification # modify a non existent phenotype random_phenotype = faker.pystr() r = client.put( f"{API_URI}/phenotype/{random_phenotype}", headers=user_A1_headers, data={ "name": faker.pystr(), "sex": "female" }, ) assert r.status_code == 404 # modify a phenotype you do not own r = client.put( f"{API_URI}/phenotype/{phenotype1_uuid}", headers=user_A1_headers, data={ "name": faker.pystr(), "sex": "female" }, ) assert r.status_code == 404 # modify a phenotype using a wrong age phenotype1["age"] = -8 r = client.put( f"{API_URI}/phenotype/{phenotype1_uuid}", headers=user_B1_headers, data=phenotype1, ) assert r.status_code == 400 # modify a phenotype you own phenotype1["age"] = faker.pyint(0, 100) r = client.put( f"{API_URI}/phenotype/{phenotype1_uuid}", headers=user_B1_headers, data=phenotype1, ) assert r.status_code == 204 # admin modify a phenotype of a group he don't belongs r = client.put( f"{API_URI}/phenotype/{phenotype1_uuid}", headers=admin_headers, data={ "name": faker.pystr(), "sex": "female" }, ) assert r.status_code == 404 # add a new hpo and change the previous geodata hpo3_id = hpo_nodes[2].hpo_id geodata2_uuid = geodata_nodes[1].uuid phenotype2["name"] = faker.pystr() phenotype2["sex"] = "male" phenotype2["birth_place"] = geodata2_uuid phenotype2["hpo"] = [hpo1_id, hpo2_id, hpo3_id] phenotype2["hpo"] = json.dumps(phenotype2["hpo"]) r = client.put( f"{API_URI}/phenotype/{phenotype2_uuid}", headers=user_B1_headers, data=phenotype2, ) assert r.status_code == 204 r = client.get(f"{API_URI}/phenotype/{phenotype2_uuid}", headers=user_B2_headers) res = self.get_content(r) assert isinstance(res, dict) assert res["birth_place"]["uuid"] == geodata2_uuid assert len(res["hpo"]) == 3 # delete all hpo and geodata data: Dict[str, Any] = {**phenotype2} data.pop("birth_place", None) data.pop("hpo", None) r = client.put(f"{API_URI}/phenotype/{phenotype2_uuid}", headers=user_B1_headers, data=data) assert r.status_code == 204 r = client.get(f"{API_URI}/phenotype/{phenotype2_uuid}", headers=user_B2_headers) response = self.get_content(r) assert isinstance(response, dict) assert "birth_place" not in response assert not response["hpo"] # add a no existing geodata phenotype2["birth_place"] = faker.pystr() r = client.put( f"{API_URI}/phenotype/{phenotype2_uuid}", headers=user_B1_headers, data=phenotype2, ) assert r.status_code == 400 # delete a phenotype # delete a phenotype that does not exists r = client.delete(f"{API_URI}/phenotype/{random_phenotype}", headers=user_A1_headers) assert r.status_code == 404 # delete a phenotype in a study you do not own r = client.delete(f"{API_URI}/phenotype/{phenotype1_uuid}", headers=user_A1_headers) assert r.status_code == 404 # admin delete a phenotype of a group he don't belong r = client.delete(f"{API_URI}/phenotype/{phenotype1_uuid}", headers=admin_headers) assert r.status_code == 404 # delete a phenotype in a study you own r = client.delete(f"{API_URI}/phenotype/{phenotype1_uuid}", headers=user_B1_headers) assert r.status_code == 204 # delete a phenotype in a study own by your group r = client.delete(f"{API_URI}/phenotype/{phenotype2_uuid}", headers=user_B2_headers) assert r.status_code == 204 # check phenotype deletion r = client.get(f"{API_URI}/phenotype/{phenotype1_uuid}", headers=user_B1_headers) assert r.status_code == 404 not_existent_message = self.get_content(r) assert isinstance(not_existent_message, str) assert not_existent_message == not_authorized_message # delete all the elements used by the test delete_test_env( client, user_A1_headers, user_B1_headers, user_B1_uuid, user_B2_uuid, user_A1_uuid, uuid_group_A, uuid_group_B, study1_uuid=study1_uuid, study2_uuid=study2_uuid, )
def test_api_family(self, client: FlaskClient, faker: Faker) -> None: # setup the test env ( admin_headers, uuid_group_A, user_A1_uuid, user_A1_headers, uuid_group_B, user_B1_uuid, user_B1_headers, user_B2_uuid, user_B2_headers, study1_uuid, study2_uuid, ) = create_test_env(client, faker, study=True) # create new phenotypes phenotype_father = { "name": faker.pystr(), "age": faker.pyint(0, 100), "sex": "male", } r = client.post( f"{API_URI}/study/{study1_uuid}/phenotypes", headers=user_B1_headers, data=phenotype_father, ) assert r.status_code == 200 phenotype_father_uuid = self.get_content(r) assert isinstance(phenotype_father_uuid, str) phenotype_mother = { "name": faker.pystr(), "age": faker.pyint(0, 100), "sex": "female", } r = client.post( f"{API_URI}/study/{study1_uuid}/phenotypes", headers=user_B1_headers, data=phenotype_mother, ) assert r.status_code == 200 phenotype_mother_uuid = self.get_content(r) assert isinstance(phenotype_mother_uuid, str) phenotype_son_B = { "name": faker.pystr(), "age": faker.pyint(0, 100), "sex": "female", } r = client.post( f"{API_URI}/study/{study1_uuid}/phenotypes", headers=user_B1_headers, data=phenotype_son_B, ) assert r.status_code == 200 phenotype_son_B_uuid = self.get_content(r) assert isinstance(phenotype_son_B_uuid, str) phenotype_son_A = { "name": faker.pystr(), "age": faker.pyint(0, 100), "sex": "female", } r = client.post( f"{API_URI}/study/{study2_uuid}/phenotypes", headers=user_A1_headers, data=phenotype_son_A, ) assert r.status_code == 200 phenotype_son_A_uuid = self.get_content(r) assert isinstance(phenotype_son_A_uuid, str) # create a relationship # father case r = client.post( f"{API_URI}/phenotype/{phenotype_son_B_uuid}/relationships/{phenotype_father_uuid}", headers=user_B1_headers, ) assert r.status_code == 200 graph = neo4j.get_instance() phenotype_father_node = graph.Phenotype.nodes.get_or_none( uuid=phenotype_father_uuid) phenotype_son_node = graph.Phenotype.nodes.get_or_none( uuid=phenotype_son_B_uuid) assert phenotype_father_node.son.is_connected(phenotype_son_node) assert phenotype_son_node.father.is_connected(phenotype_father_node) # test relationships in get phenotype list response r = client.get(f"{API_URI}/study/{study1_uuid}/phenotypes", headers=user_B1_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, list) for el in response: if el["uuid"] == phenotype_son_B_uuid: assert el["relationships"]["father"][ "uuid"] == phenotype_father_uuid if el["uuid"] == phenotype_father_uuid: assert el["relationships"]["sons"][0][ "uuid"] == phenotype_son_B_uuid # test relationships in get single phenotype response r = client.get(f"{API_URI}/phenotype/{phenotype_son_B_uuid}", headers=user_B1_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, dict) assert response["relationships"]["father"][ "uuid"] == phenotype_father_uuid r = client.get(f"{API_URI}/phenotype/{phenotype_father_uuid}", headers=user_B1_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, dict) assert response["relationships"]["sons"][0][ "uuid"] == phenotype_son_B_uuid # create a relationship for two phenotypes in an other study r = client.post( f"{API_URI}/phenotype/{phenotype_son_B_uuid}/relationships/{phenotype_mother_uuid}", headers=user_A1_headers, ) assert r.status_code == 404 # admin creates a relationship r = client.post( f"{API_URI}/phenotype/{phenotype_son_B_uuid}/relationships/{phenotype_mother_uuid}", headers=admin_headers, ) assert r.status_code == 404 # a user of the same group of the owner create a relationship # mother case r = client.post( f"{API_URI}/phenotype/{phenotype_son_B_uuid}/relationships/{phenotype_mother_uuid}", headers=user_B2_headers, ) assert r.status_code == 200 graph = neo4j.get_instance() phenotype_mother_node = graph.Phenotype.nodes.get_or_none( uuid=phenotype_mother_uuid) phenotype_son_node = graph.Phenotype.nodes.get_or_none( uuid=phenotype_son_B_uuid) assert phenotype_mother_node.son.is_connected(phenotype_son_node) assert phenotype_son_node.mother.is_connected(phenotype_mother_node) # test relationships in get phenotype list response r = client.get(f"{API_URI}/study/{study1_uuid}/phenotypes", headers=user_B1_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, list) for el in response: if el["uuid"] == phenotype_son_B_uuid: assert el["relationships"]["mother"][ "uuid"] == phenotype_mother_uuid if el["uuid"] == phenotype_mother_uuid: assert el["relationships"]["sons"][0][ "uuid"] == phenotype_son_B_uuid # test relationships in get single phenotype response r = client.get(f"{API_URI}/phenotype/{phenotype_son_B_uuid}", headers=user_B1_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, dict) assert response["relationships"]["mother"][ "uuid"] == phenotype_mother_uuid # relationship between phenotype from different studies r = client.post( f"{API_URI}/phenotype/{phenotype_son_A_uuid}/relationships/{phenotype_father_uuid}", headers=user_B1_headers, ) assert r.status_code == 404 # relationship with a random phenotype as son random_phenotype_uuid = faker.pystr() r = client.post( f"{API_URI}/phenotype/{random_phenotype_uuid}/relationships/{phenotype_father_uuid}", headers=user_B1_headers, ) assert r.status_code == 404 # relationship with a random phenotype as father r = client.post( f"{API_URI}/phenotype/{phenotype_son_B_uuid}/relationships/{random_phenotype_uuid}", headers=user_B1_headers, ) assert r.status_code == 404 # relationship with itself r = client.post( f"{API_URI}/phenotype/{phenotype_father_uuid}/relationships/{phenotype_father_uuid}", headers=user_B1_headers, ) assert r.status_code == 400 # delete a relationship # father case r = client.delete( f"{API_URI}/phenotype/{phenotype_son_B_uuid}/relationships/{phenotype_father_uuid}", headers=user_B1_headers, ) assert r.status_code == 204 graph = neo4j.get_instance() phenotype_father_node = graph.Phenotype.nodes.get_or_none( uuid=phenotype_father_uuid) phenotype_son_node = graph.Phenotype.nodes.get_or_none( uuid=phenotype_son_B_uuid) assert not phenotype_father_node.son.single() assert not phenotype_son_node.father.single() # delete a relationship for two phenotypes in an other study r = client.delete( f"{API_URI}/phenotype/{phenotype_son_B_uuid}/relationships/{phenotype_mother_uuid}", headers=user_A1_headers, ) assert r.status_code == 404 # admin delete a relationship r = client.delete( f"{API_URI}/phenotype/{phenotype_son_B_uuid}/relationships/{phenotype_mother_uuid}", headers=admin_headers, ) assert r.status_code == 404 # a user of the same group of the owner delete a relationship # mother case r = client.delete( f"{API_URI}/phenotype/{phenotype_son_B_uuid}/relationships/{phenotype_mother_uuid}", headers=user_B2_headers, ) assert r.status_code == 204 graph = neo4j.get_instance() phenotype_mother_node = graph.Phenotype.nodes.get_or_none( uuid=phenotype_mother_uuid) phenotype_son_node = graph.Phenotype.nodes.get_or_none( uuid=phenotype_son_B_uuid) assert not phenotype_mother_node.son.single() assert not phenotype_son_node.mother.single() # delete relationship between phenotype from different studies r = client.delete( f"{API_URI}/phenotype/{phenotype_son_A_uuid}/relationships/{phenotype_father_uuid}", headers=user_B1_headers, ) assert r.status_code == 404 # delete relationship with a random phenotype as son r = client.delete( f"{API_URI}/phenotype/{random_phenotype_uuid}/relationships/{phenotype_father_uuid}", headers=user_B1_headers, ) assert r.status_code == 404 # delete relationship with a random phenotype as father r = client.delete( f"{API_URI}/phenotype/{phenotype_son_B_uuid}/relationships/{random_phenotype_uuid}", headers=user_B1_headers, ) assert r.status_code == 404 r = client.post( f"{API_URI}/phenotype/{phenotype_son_B_uuid}/relationships/{phenotype_father_uuid}", headers=user_B1_headers, ) assert r.status_code == 200 r = client.post( f"{API_URI}/phenotype/{phenotype_son_B_uuid}/relationships/{phenotype_mother_uuid}", headers=user_B1_headers, ) assert r.status_code == 200 # delete a son relationship r = client.delete( f"{API_URI}/phenotype/{phenotype_mother_uuid}/relationships/{phenotype_son_B_uuid}", headers=user_B1_headers, ) assert r.status_code == 204 graph = neo4j.get_instance() phenotype_mother_node = graph.Phenotype.nodes.get_or_none( uuid=phenotype_mother_uuid) phenotype_son_node = graph.Phenotype.nodes.get_or_none( uuid=phenotype_son_B_uuid) assert not phenotype_mother_node.son.single() assert not phenotype_son_node.mother.single() r = client.delete( f"{API_URI}/phenotype/{phenotype_father_uuid}/relationships/{phenotype_son_B_uuid}", headers=user_B1_headers, ) assert r.status_code == 204 graph = neo4j.get_instance() phenotype_father_node = graph.Phenotype.nodes.get_or_none( uuid=phenotype_father_uuid) phenotype_son_node = graph.Phenotype.nodes.get_or_none( uuid=phenotype_son_B_uuid) assert not phenotype_father_node.son.single() assert not phenotype_son_node.father.single() # delete all the elements used by the test delete_test_env( client, user_A1_headers, user_B1_headers, user_B1_uuid, user_B2_uuid, user_A1_uuid, uuid_group_A, uuid_group_B, study1_uuid=study1_uuid, study2_uuid=study2_uuid, )
def test_api_study(self, client: FlaskClient, faker: Faker) -> None: # setup the test env ( admin_headers, uuid_group_A, user_A1_uuid, user_A1_headers, uuid_group_B, user_B1_uuid, user_B1_headers, user_B2_uuid, user_B2_headers, study1_uuid, study2_uuid, ) = create_test_env(client, faker, study=False) # create a new study for the group B random_name = faker.pystr() study1 = {"name": random_name, "description": faker.pystr()} r = client.post(f"{API_URI}/study", headers=user_B1_headers, data=study1) assert r.status_code == 200 study1_uuid = self.get_content(r) assert isinstance(study1_uuid, str) # create a new study for the group A random_name2 = faker.pystr() study2 = {"name": random_name2, "description": faker.pystr()} r = client.post(f"{API_URI}/study", headers=user_A1_headers, data=study2) assert r.status_code == 200 study2_uuid = self.get_content(r) assert isinstance(study2_uuid, str) # check the directory was created dir_path = INPUT_ROOT.joinpath(uuid_group_A, study2_uuid) assert dir_path.is_dir() # test study access # test study list response r = client.get(f"{API_URI}/study", headers=user_B1_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, list) assert len(response) == 1 # test admin access r = client.get(f"{API_URI}/study/{study1_uuid}", headers=admin_headers) assert r.status_code == 200 # study owner r = client.get(f"{API_URI}/study/{study1_uuid}", headers=user_B1_headers) assert r.status_code == 200 # other component of the group r = client.get(f"{API_URI}/study/{study1_uuid}", headers=user_B2_headers) assert r.status_code == 200 # study own by an other group r = client.get(f"{API_URI}/study/{study1_uuid}", headers=user_A1_headers) assert r.status_code == 404 not_authorized_message = self.get_content(r) assert isinstance(not_authorized_message, str) # test study modification # modify a study you do not own r = client.put( f"{API_URI}/study/{study1_uuid}", headers=user_A1_headers, data={"description": faker.pystr()}, ) assert r.status_code == 404 # modify a study you own r = client.put( f"{API_URI}/study/{study1_uuid}", headers=user_B1_headers, data={"description": faker.pystr()}, ) assert r.status_code == 204 # delete a study # delete a study you do not own r = client.delete(f"{API_URI}/study/{study1_uuid}", headers=user_A1_headers) assert r.status_code == 404 # delete a study you own # create a new dataset to test if it's deleted with the study dataset = {"name": faker.pystr(), "description": faker.pystr()} r = client.post( f"{API_URI}/study/{study2_uuid}/datasets", headers=user_A1_headers, data=dataset, ) assert r.status_code == 200 dataset_uuid = self.get_content(r) assert isinstance(dataset_uuid, str) dataset_path = dir_path.joinpath(dataset_uuid) assert dataset_path.is_dir() # create a new file to test if it's deleted with the study filename = f"{faker.pystr()}_R1" file_data = { "name": f"{filename}.fastq.gz", "mimeType": "application/gzip", "size": faker.pyint(), "lastModified": faker.pyint(), } r = client.post( f"{API_URI}/dataset/{dataset_uuid}/files/upload", headers=user_A1_headers, data=file_data, ) assert r.status_code == 201 # get the file uuid r = client.get( f"{API_URI}/dataset/{dataset_uuid}/files", headers=user_A1_headers, ) assert r.status_code == 200 file_list = self.get_content(r) assert isinstance(file_list, list) file_uuid = file_list[0]["uuid"] # create a new technical to test if it's deleted with the study techmeta = {"name": faker.pystr()} r = client.post( f"{API_URI}/study/{study2_uuid}/technicals", headers=user_A1_headers, data=techmeta, ) assert r.status_code == 200 techmeta_uuid = self.get_content(r) assert isinstance(techmeta_uuid, str) # create a new phenotype to test if it's deleted with the study phenotype = {"name": faker.pystr(), "sex": "male"} r = client.post( f"{API_URI}/study/{study2_uuid}/phenotypes", headers=user_A1_headers, data=phenotype, ) assert r.status_code == 200 phenotype_uuid = self.get_content(r) assert isinstance(phenotype_uuid, str) # simulate the study has an output directory # create the output directory in the same way is created in launch pipeline task output_path = OUTPUT_ROOT.joinpath( dataset_path.relative_to(INPUT_ROOT)) output_path.mkdir(parents=True) assert output_path.is_dir() # delete the study r = client.delete(f"{API_URI}/study/{study2_uuid}", headers=user_A1_headers) assert r.status_code == 204 assert not dir_path.is_dir() assert not dataset_path.is_dir() # check the dataset was deleted r = client.get(f"{API_URI}/dataset/{dataset_uuid}", headers=user_A1_headers) assert r.status_code == 404 # check the file was deleted r = client.get(f"{API_URI}/file/{file_uuid}", headers=user_A1_headers) assert r.status_code == 404 # check the technical was deleted r = client.get(f"{API_URI}/technical/{techmeta_uuid}", headers=user_A1_headers) assert r.status_code == 404 # check the phenotype was deleted r = client.get(f"{API_URI}/phenotype/{phenotype_uuid}", headers=user_A1_headers) assert r.status_code == 404 # check the output dir was deleted assert not output_path.is_dir() # delete a study own by your group r = client.delete(f"{API_URI}/study/{study1_uuid}", headers=user_B2_headers) assert r.status_code == 204 # check study deletion r = client.get(f"{API_URI}/study/{study1_uuid}", headers=user_B1_headers) assert r.status_code == 404 not_existent_message = self.get_content(r) assert isinstance(not_existent_message, str) assert not_existent_message == not_authorized_message # delete all the elements used by the test delete_test_env( client, user_A1_headers, user_B1_headers, user_B1_uuid, user_B2_uuid, user_A1_uuid, uuid_group_A, uuid_group_B, )
def test_api_techmeta(self, client: FlaskClient, faker: Faker) -> None: # setup the test env ( admin_headers, uuid_group_A, user_A1_uuid, user_A1_headers, uuid_group_B, user_B1_uuid, user_B1_headers, user_B2_uuid, user_B2_headers, study1_uuid, study2_uuid, ) = create_test_env(client, faker, study=True) # create a new techmeta techmeta1 = { "name": faker.pystr(), "sequencing_date": faker.date(), "platform": "Other", } r = client.post( f"{API_URI}/study/{study1_uuid}/technicals", headers=user_B1_headers, data=techmeta1, ) assert r.status_code == 200 techmeta1_uuid = self.get_content(r) assert isinstance(techmeta1_uuid, str) # create a new techmeta in a study of an other group r = client.post( f"{API_URI}/study/{study2_uuid}/technicals", headers=user_B1_headers, data=techmeta1, ) assert r.status_code == 404 # create a new technical as admin not belonging to study group techmeta2 = { "name": faker.pystr(), "sequencing_date": faker.date(), "platform": "Other", } r = client.post( f"{API_URI}/study/{study1_uuid}/technicals", headers=admin_headers, data=techmeta2, ) assert r.status_code == 404 r = client.post( f"{API_URI}/study/{study1_uuid}/technicals", headers=user_B1_headers, data=techmeta2, ) assert r.status_code == 200 techmeta2_uuid = self.get_content(r) assert isinstance(techmeta2_uuid, str) # test technical access # test technical list response r = client.get(f"{API_URI}/study/{study1_uuid}/technicals", headers=user_B1_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, list) assert len(response) == 2 # test technical list response for a study you don't have access r = client.get(f"{API_URI}/study/{study2_uuid}/technicals", headers=user_B1_headers) assert r.status_code == 404 # test technical list response for admin r = client.get(f"{API_URI}/study/{study1_uuid}/technicals", headers=admin_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, list) assert len(response) == 2 # test empty list of technicals in a study r = client.get(f"{API_URI}/study/{study2_uuid}/technicals", headers=user_A1_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, list) assert not response # study owner r = client.get(f"{API_URI}/technical/{techmeta1_uuid}", headers=user_B1_headers) assert r.status_code == 200 # same group of the study owner r = client.get(f"{API_URI}/technical/{techmeta1_uuid}", headers=user_B2_headers) assert r.status_code == 200 # technical owned by an other group r = client.get(f"{API_URI}/technical/{techmeta1_uuid}", headers=user_A1_headers) assert r.status_code == 404 not_authorized_message = self.get_content(r) assert isinstance(not_authorized_message, str) # admin access r = client.get(f"{API_URI}/technical/{techmeta1_uuid}", headers=admin_headers) assert r.status_code == 200 # test technical modification # modify a non existent technical random_technical = faker.pystr() r = client.put( f"{API_URI}/technical/{random_technical}", headers=user_A1_headers, data={"name": faker.pystr()}, ) assert r.status_code == 404 # modify a technical you do not own r = client.put( f"{API_URI}/technical/{techmeta1_uuid}", headers=user_A1_headers, data={"name": faker.pystr()}, ) assert r.status_code == 404 # modify a technical you own r = client.put( f"{API_URI}/technical/{techmeta1_uuid}", headers=user_B1_headers, data={ "name": faker.pystr(), "sequencing_date": faker.date() }, ) assert r.status_code == 204 # admin modify a technical of a group he don't belongs r = client.put( f"{API_URI}/technical/{techmeta1_uuid}", headers=admin_headers, data={"name": faker.pystr()}, ) assert r.status_code == 404 # delete a technical # delete a technical that does not exists r = client.delete(f"{API_URI}/technical/{random_technical}", headers=user_A1_headers) assert r.status_code == 404 # delete a technical in a study you do not own r = client.delete(f"{API_URI}/technical/{techmeta1_uuid}", headers=user_A1_headers) assert r.status_code == 404 # admin delete a technical of a group he don't belong r = client.delete(f"{API_URI}/technical/{techmeta1_uuid}", headers=admin_headers) assert r.status_code == 404 # delete a technical in a study you own r = client.delete(f"{API_URI}/technical/{techmeta1_uuid}", headers=user_B1_headers) assert r.status_code == 204 # delete a technical in a study own by your group r = client.delete(f"{API_URI}/technical/{techmeta2_uuid}", headers=user_B2_headers) assert r.status_code == 204 # check technical deletion r = client.get(f"{API_URI}/technical/{techmeta1_uuid}", headers=user_B1_headers) assert r.status_code == 404 not_existent_message = self.get_content(r) assert isinstance(not_existent_message, str) assert not_existent_message == not_authorized_message # delete all the elements used by the test delete_test_env( client, user_A1_headers, user_B1_headers, user_B1_uuid, user_B2_uuid, user_A1_uuid, uuid_group_A, uuid_group_B, study1_uuid=study1_uuid, study2_uuid=study2_uuid, )
def test_api_file(self, client: FlaskClient, faker: Faker) -> None: # setup the test env ( admin_headers, uuid_group_A, user_A1_uuid, user_A1_headers, uuid_group_B, user_B1_uuid, user_B1_headers, user_B2_uuid, user_B2_headers, study1_uuid, study2_uuid, ) = create_test_env(client, faker, study=True) # create a new dataset dataset_B = {"name": faker.pystr(), "description": faker.pystr()} r = client.post( f"{API_URI}/study/{study1_uuid}/datasets", headers=user_B1_headers, data=dataset_B, ) assert r.status_code == 200 dataset_B_uuid = self.get_content(r) assert isinstance(dataset_B_uuid, str) # check accesses for post request # upload a new file in a dataset of an other group fake_file = { "name": f"{faker.pystr()}_R1.fastq.gz", "mimeType": "application/gzip", "size": faker.pyint(), "lastModified": faker.pyint(), } r = client.post( f"{API_URI}/dataset/{dataset_B_uuid}/files/upload", headers=user_A1_headers, data=fake_file, ) assert r.status_code == 404 # upload a new file as admin not belonging to study group r = client.post( f"{API_URI}/dataset/{dataset_B_uuid}/files/upload", headers=admin_headers, data=fake_file, ) assert r.status_code == 404 # try to upload a file with a non allowed format fake_format = { "name": f"{faker.pystr()}_R1.txt", "mimeType": "text/plain", "size": faker.pyint(), "lastModified": faker.pyint(), } r = client.post( f"{API_URI}/dataset/{dataset_B_uuid}/files/upload", headers=user_B1_headers, data=fake_format, ) assert r.status_code == 400 # try to upload a file with a wrong nomenclature fake_nomencl_file = { "name": f"{faker.pystr()}.{faker.pystr()}_R1.fastq.gz.{faker.pystr()}", "mimeType": "text/plain", "size": faker.pyint(), "lastModified": faker.pyint(), } r = client.post( f"{API_URI}/dataset/{dataset_B_uuid}/files/upload", headers=user_B1_headers, data=fake_nomencl_file, ) assert r.status_code == 400 fake_nomencl_file2 = { "name": f"{faker.pystr()}.{faker.pystr()}_R1.fastq.gz", "mimeType": "text/plain", "size": faker.pyint(), "lastModified": faker.pyint(), } r = client.post( f"{API_URI}/dataset/{dataset_B_uuid}/files/upload", headers=user_B1_headers, data=fake_nomencl_file2, ) assert r.status_code == 400 valid_fcontent = f"@SEQ_ID\n{faker.pystr(max_chars=12)}\n+{faker.pystr()}\n{faker.pystr(max_chars=12)}" # invalid header, @ is missing invalid_header = f"SEQ_ID\n{faker.pystr(max_chars=12)}\n+{faker.pystr()}\n{faker.pystr(max_chars=12)}" # CASE invalid separator invalid_separator = f"@SEQ_ID\n{faker.pystr(max_chars=12)}\n{faker.pystr()}\n{faker.pystr(max_chars=12)}" # len of sequence != len of quality invalid_sequence = f"@SEQ_ID\n{faker.pystr(max_chars=12)}\n+{faker.pystr()}\n{faker.pystr(max_chars=8)}" # invalid second header invalid_header2 = f"@SEQ_ID\n{faker.pystr(max_chars=12)}\n+{faker.pystr()}\n{faker.pystr(max_chars=12)}\n{faker.pystr()}" # create a file to upload fastq = self.create_fastq_gz(faker, valid_fcontent) # upload a file response = self.upload_file(client, user_B1_headers, fastq, dataset_B_uuid, stream=True) assert response.status_code == 200 # check the file exists and have the expected size filename = fastq.name filesize = fastq.stat().st_size filepath = INPUT_ROOT.joinpath(uuid_group_B, study1_uuid, dataset_B_uuid, filename) assert filepath.is_file() assert filepath.stat().st_size == filesize # upload the same file twice response = self.upload_file(client, user_B2_headers, fastq, dataset_B_uuid, stream=True) assert response.status_code == 409 # upload the same file in a different dataset # create a new dataset dataset_B2 = {"name": faker.pystr(), "description": faker.pystr()} r = client.post( f"{API_URI}/study/{study1_uuid}/datasets", headers=user_B1_headers, data=dataset_B2, ) assert r.status_code == 200 dataset_B2_uuid = self.get_content(r) assert isinstance(dataset_B2_uuid, str) response = self.upload_file(client, user_B2_headers, fastq, dataset_B2_uuid, stream=True) assert response.status_code == 200 # check error if final file size is different from the expected # rename the file to upload fastq2 = fastq.parent.joinpath(f"{faker.pystr()}_R1.fastq.gz") fastq.rename(fastq2) # upload without streaming response = self.upload_file( client, user_B1_headers, fastq2, dataset_B_uuid, stream=False, ) assert response.status_code == 500 error_message = self.get_content(response) assert isinstance(error_message, str) assert ( error_message == "File has not been uploaded correctly: final size does not correspond to total size. Please try a new upload" ) # check uncomplete file has been removed check_filepath = INPUT_ROOT.joinpath( uuid_group_B, study1_uuid, dataset_B_uuid, fastq2.name, ) assert not check_filepath.is_file() # check file validation # upload an empty file empty_file = self.create_fastq_gz(faker, "") response = self.upload_file( client, user_B1_headers, empty_file, dataset_B_uuid, stream=True, ) assert response.status_code == 400 # check the empty file has been removed check_filepath = INPUT_ROOT.joinpath( uuid_group_B, study1_uuid, dataset_B_uuid, empty_file.name, ) assert not check_filepath.is_file() empty_file.unlink() # upload a file with not valid content # CASE wrong gzip file wrong_gzip = Path(tempfile.gettempdir(), f"{faker.pystr()}_R1.fastq.gz") # Directly write the gz => it is an ascii file and not a valid gz with open(wrong_gzip, "w") as f: f.write(valid_fcontent) response = self.upload_file( client, user_B1_headers, wrong_gzip, dataset_B_uuid, stream=True, ) assert response.status_code == 400 error_message = self.get_content(response) assert isinstance(error_message, str) assert "gzipped" in error_message # check the empty file has been removed check_filepath = INPUT_ROOT.joinpath( uuid_group_B, study1_uuid, dataset_B_uuid, wrong_gzip.name, ) assert not check_filepath.is_file() wrong_gzip.unlink() # CASE binary file instead of a text file binary_file = self.create_fastq_gz(faker, faker.binary(), mode="wb") response = self.upload_file( client, user_B1_headers, binary_file, dataset_B_uuid, stream=True, ) assert response.status_code == 400 error_message = self.get_content(response) assert isinstance(error_message, str) assert "binary" in error_message check_filepath = INPUT_ROOT.joinpath( uuid_group_B, study1_uuid, dataset_B_uuid, binary_file.name, ) assert not check_filepath.is_file() binary_file.unlink() # CASE invalid header invalid_fastq = self.create_fastq_gz(faker, invalid_header) response = self.upload_file( client, user_B1_headers, invalid_fastq, dataset_B_uuid, stream=True, ) assert response.status_code == 400 error_message = self.get_content(response) assert isinstance(error_message, str) assert "header" in error_message check_filepath = INPUT_ROOT.joinpath( uuid_group_B, study1_uuid, dataset_B_uuid, invalid_fastq.name, ) assert not check_filepath.is_file() invalid_fastq.unlink() # CASE invalid separator invalid_fastq = self.create_fastq_gz(faker, invalid_separator) response = self.upload_file( client, user_B1_headers, invalid_fastq, dataset_B_uuid, stream=True, ) assert response.status_code == 400 error_message = self.get_content(response) assert isinstance(error_message, str) assert "separator" in error_message check_filepath = INPUT_ROOT.joinpath( uuid_group_B, study1_uuid, dataset_B_uuid, invalid_fastq.name, ) assert not check_filepath.is_file() invalid_fastq.unlink() # CASE invalid sequence line invalid_fastq = self.create_fastq_gz(faker, invalid_sequence) response = self.upload_file( client, user_B1_headers, invalid_fastq, dataset_B_uuid, stream=True, ) assert response.status_code == 400 error_message = self.get_content(response) assert isinstance(error_message, str) assert "lines lengths differ" in error_message check_filepath = INPUT_ROOT.joinpath( uuid_group_B, study1_uuid, dataset_B_uuid, invalid_fastq.name, ) assert not check_filepath.is_file() invalid_fastq.unlink() # CASE invalid header for the second read invalid_fastq = self.create_fastq_gz(faker, invalid_header2) response = self.upload_file( client, user_B1_headers, invalid_fastq, dataset_B_uuid, stream=True, ) assert response.status_code == 400 error_message = self.get_content(response) assert isinstance(error_message, str) assert "header" in error_message check_filepath = INPUT_ROOT.joinpath( uuid_group_B, study1_uuid, dataset_B_uuid, invalid_fastq.name, ) assert not check_filepath.is_file() invalid_fastq.unlink() # check accesses on put endpoint # put on a file in a dataset of an other group r = client.put( f"{API_URI}/dataset/{dataset_B_uuid}/files/upload/{filename}", headers=user_A1_headers, ) assert r.status_code == 404 # put a file as admin not belonging to study group r = client.put( f"{API_URI}/dataset/{dataset_B_uuid}/files/upload/{filename}", headers=admin_headers, ) assert r.status_code == 404 # put of a ton existent file r = client.put( f"{API_URI}/dataset/{dataset_B_uuid}/files/upload/{fastq2}.txt.gz", headers=user_B1_headers, ) assert r.status_code == 404 # test file access # test file list response r = client.get(f"{API_URI}/dataset/{dataset_B_uuid}/files", headers=user_B1_headers) assert r.status_code == 200 file_list = self.get_content(r) assert isinstance(file_list, list) assert len(file_list) == 1 file_uuid = file_list[0]["uuid"] # test file list response for a dataset you don't have access r = client.get(f"{API_URI}/dataset/{dataset_B_uuid}/files", headers=user_A1_headers) assert r.status_code == 404 # test file list response for admin r = client.get(f"{API_URI}/dataset/{dataset_B_uuid}/files", headers=admin_headers) assert r.status_code == 200 file_list = self.get_content(r) assert isinstance(file_list, list) assert len(file_list) == 1 # check use case of file not in the folder # rename the file in the folder as it will not be found temporary_filepath = filepath.with_suffix(".fastq.tmp") filepath.rename(temporary_filepath) r = client.get(f"{API_URI}/dataset/{dataset_B_uuid}/files", headers=user_B1_headers) assert r.status_code == 200 file_list = self.get_content(r) assert isinstance(file_list, list) assert file_list[0]["status"] == "unknown" # create an empty file with the original name # test status from unknown to importing filepath.touch() r = client.get(f"{API_URI}/dataset/{dataset_B_uuid}/files", headers=user_B1_headers) assert r.status_code == 200 file_list = self.get_content(r) assert isinstance(file_list, list) assert file_list[0]["status"] == "importing" # restore the original file filepath.unlink() r = client.get(f"{API_URI}/file/{file_uuid}", headers=user_B1_headers) assert r.status_code == 200 file_response = self.get_content(r) assert isinstance(file_response, dict) assert file_response["status"] == "unknown" temporary_filepath.rename(filepath) r = client.get(f"{API_URI}/dataset/{dataset_B_uuid}/files", headers=user_B1_headers) assert r.status_code == 200 file_list = self.get_content(r) assert isinstance(file_list, list) assert file_list[0]["status"] == "uploaded" # dataset owner r = client.get(f"{API_URI}/file/{file_uuid}", headers=user_B1_headers) assert r.status_code == 200 # same group of the dataset owner r = client.get(f"{API_URI}/file/{file_uuid}", headers=user_B2_headers) assert r.status_code == 200 # file owned by an other group r = client.get(f"{API_URI}/file/{file_uuid}", headers=user_A1_headers) assert r.status_code == 404 not_authorized_message = self.get_content(r) assert isinstance(not_authorized_message, str) # admin access r = client.get(f"{API_URI}/file/{file_uuid}", headers=admin_headers) assert r.status_code == 200 # check use case of file not in the folder # rename the file in the folder as it will not be found filepath.rename(temporary_filepath) r = client.get(f"{API_URI}/file/{file_uuid}", headers=user_B1_headers) assert r.status_code == 200 # create an empty file with the original name # test status from unknown to importing filepath.touch() r = client.get(f"{API_URI}/file/{file_uuid}", headers=user_B1_headers) assert r.status_code == 200 file_res = self.get_content(r) assert isinstance(file_res, dict) assert file_res["status"] == "importing" # restore the original file filepath.unlink() r = client.get(f"{API_URI}/file/{file_uuid}", headers=user_B1_headers) assert r.status_code == 200 temporary_filepath.rename(filepath) r = client.get(f"{API_URI}/file/{file_uuid}", headers=user_B1_headers) assert r.status_code == 200 file_res = self.get_content(r) assert isinstance(file_res, dict) assert file_res["status"] == "uploaded" # delete a file # delete a file that does not exists fake_filename = f"{faker.pystr()}_R1" r = client.delete(f"{API_URI}/file/{fake_filename}", headers=user_A1_headers) assert r.status_code == 404 # delete a file in a dataset you do not own r = client.delete(f"{API_URI}/file/{file_uuid}", headers=user_A1_headers) assert r.status_code == 404 # admin delete a file of a dataset he don't belong r = client.delete(f"{API_URI}/file/{file_uuid}", headers=admin_headers) assert r.status_code == 404 # delete a file in a dataset you own r = client.delete(f"{API_URI}/file/{file_uuid}", headers=user_B1_headers) assert r.status_code == 204 # delete a file in a dataset own by your group r = client.get(f"{API_URI}/dataset/{dataset_B2_uuid}/files", headers=user_B2_headers) file_list = self.get_content(r) assert isinstance(file_list, list) file2_uuid = file_list[0]["uuid"] r = client.delete(f"{API_URI}/file/{file2_uuid}", headers=user_B2_headers) assert r.status_code == 204 # check file deletion r = client.get(f"{API_URI}/file/{file_uuid}", headers=user_B1_headers) assert r.status_code == 404 not_existent_message = self.get_content(r) assert isinstance(not_existent_message, str) assert not_existent_message == not_authorized_message # check physical deletion from the folder assert not filepath.is_file() if fastq.exists(): fastq.unlink() if fastq2.exists(): fastq2.unlink() # delete all the elements used by the test delete_test_env( client, user_A1_headers, user_B1_headers, user_B1_uuid, user_B2_uuid, user_A1_uuid, uuid_group_A, uuid_group_B, study1_uuid=study1_uuid, study2_uuid=study2_uuid, )
def test_api_dataset(self, client: FlaskClient, faker: Faker) -> None: # setup the test env ( admin_headers, uuid_group_A, user_A1_uuid, user_A1_headers, uuid_group_B, user_B1_uuid, user_B1_headers, user_B2_uuid, user_B2_headers, study1_uuid, study2_uuid, ) = create_test_env(client, faker, study=True) # create a new dataset dataset1 = {"name": faker.pystr(), "description": faker.pystr()} r = client.post( f"{API_URI}/study/{study1_uuid}/datasets", headers=user_B1_headers, data=dataset1, ) assert r.status_code == 200 dataset1_uuid = self.get_content(r) assert isinstance(dataset1_uuid, str) # check the directory exists dir_path = INPUT_ROOT.joinpath(uuid_group_B, study1_uuid, dataset1_uuid) assert dir_path.is_dir() # create a new dataset in a study of an other group r = client.post( f"{API_URI}/study/{study2_uuid}/datasets", headers=user_B1_headers, data=dataset1, ) assert r.status_code == 404 # create a technical r = client.post( f"{API_URI}/study/{study1_uuid}/technicals", headers=user_B1_headers, data={"name": faker.pystr()}, ) assert r.status_code == 200 technical_uuid = self.get_content(r) assert isinstance(technical_uuid, str) # create a phenotype r = client.post( f"{API_URI}/study/{study1_uuid}/phenotypes", headers=user_B1_headers, data={ "name": faker.pystr(), "sex": "male" }, ) assert r.status_code == 200 phenotype_uuid = self.get_content(r) assert isinstance(phenotype_uuid, str) # create a new dataset as admin not belonging to study group dataset2 = { "name": faker.pystr(), "description": faker.pystr(), "phenotype": phenotype_uuid, "technical": technical_uuid, } r = client.post( f"{API_URI}/study/{study1_uuid}/datasets", headers=admin_headers, data=dataset2, ) assert r.status_code == 404 r = client.post( f"{API_URI}/study/{study1_uuid}/datasets", headers=user_B1_headers, data=dataset2, ) assert r.status_code == 200 dataset2_uuid = self.get_content(r) assert isinstance(dataset2_uuid, str) # test dataset access # test dataset list response r = client.get(f"{API_URI}/study/{study1_uuid}/datasets", headers=user_B1_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, list) assert len(response) == 2 # test dataset list response for a study you don't have access r = client.get(f"{API_URI}/study/{study2_uuid}/datasets", headers=user_B1_headers) assert r.status_code == 404 # test dataset list response for admin r = client.get(f"{API_URI}/study/{study1_uuid}/datasets", headers=admin_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, list) assert len(response) == 2 # test empty list of datasets in a study r = client.get(f"{API_URI}/study/{study2_uuid}/datasets", headers=user_A1_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, list) assert not response # dataset owner r = client.get(f"{API_URI}/dataset/{dataset1_uuid}", headers=user_B1_headers) assert r.status_code == 200 # same group of the owner r = client.get(f"{API_URI}/dataset/{dataset1_uuid}", headers=user_B2_headers) assert r.status_code == 200 # dataset owned by an other group r = client.get(f"{API_URI}/dataset/{dataset1_uuid}", headers=user_A1_headers) assert r.status_code == 404 not_authorized_message = self.get_content(r) assert isinstance(not_authorized_message, str) # admin access r = client.get(f"{API_URI}/dataset/{dataset1_uuid}", headers=admin_headers) assert r.status_code == 200 # test technical and phenoype assignation when a new dataset is created r = client.get(f"{API_URI}/dataset/{dataset2_uuid}", headers=user_B1_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, dict) assert "technical" in response assert "phenotype" in response assert response["technical"]["uuid"] == technical_uuid # check phenotype was correctly assigned assert response["phenotype"]["uuid"] == phenotype_uuid # test dataset changing status r = client.patch( f"{API_URI}/dataset/{dataset1_uuid}", headers=user_B1_headers, data={"status": "UPLOAD COMPLETED"}, ) assert r.status_code == 204 # check new status in get response r = client.get(f"{API_URI}/dataset/{dataset1_uuid}", headers=user_B1_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, dict) assert "status" in response # delete status r = client.patch( f"{API_URI}/dataset/{dataset1_uuid}", headers=user_B1_headers, data={"status": "-1"}, ) assert r.status_code == 204 # check status has been removed r = client.get(f"{API_URI}/dataset/{dataset1_uuid}", headers=user_B1_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, dict) assert not response["status"] # try to modify a status when the dataset is running graph = neo4j.get_instance() dataset = graph.Dataset.nodes.get_or_none(uuid=dataset1_uuid) dataset.status = "RUNNING" dataset.save() r = client.patch( f"{API_URI}/dataset/{dataset1_uuid}", headers=user_B1_headers, data={"status": "UPLOAD COMPLETED"}, ) assert r.status_code == 400 # admin tries to modify a status when the dataset is running r = client.patch( f"{API_URI}/dataset/{dataset1_uuid}", headers=admin_headers, data={"status": "UPLOAD COMPLETED"}, ) assert r.status_code == 204 # test dataset modification # modify a dataset you do not own r = client.put( f"{API_URI}/dataset/{dataset1_uuid}", headers=user_A1_headers, data={"description": faker.pystr()}, ) assert r.status_code == 404 # modify a dataset you own r = client.put( f"{API_URI}/dataset/{dataset1_uuid}", headers=user_B1_headers, data={"description": faker.pystr()}, ) assert r.status_code == 204 # modify a dataset of your group assigning a technical and a phenotype r = client.put( f"{API_URI}/dataset/{dataset1_uuid}", headers=user_B2_headers, data={ "name": faker.pystr(), "technical": technical_uuid, "phenotype": phenotype_uuid, }, ) assert r.status_code == 204 # check technical was correctly assigned r = client.get(f"{API_URI}/dataset/{dataset1_uuid}", headers=user_B2_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, dict) assert "technical" in response assert "phenotype" in response assert response["technical"]["uuid"] == technical_uuid # check phenotype was correctly assigned assert response["phenotype"]["uuid"] == phenotype_uuid # modify a dataset of your group removing a technical and a phenotype r = client.put( f"{API_URI}/dataset/{dataset1_uuid}", headers=user_B2_headers, data={ "technical": "-1", "phenotype": "-1" }, ) assert r.status_code == 204 # check technical was correctly removed r = client.get(f"{API_URI}/dataset/{dataset1_uuid}", headers=user_B2_headers) assert r.status_code == 200 response = self.get_content(r) assert isinstance(response, dict) assert response["technical"] is None # check phenotype was correctly removed assert response["phenotype"] is None # admin modify a dataset of a group he don't belongs r = client.put( f"{API_URI}/dataset/{dataset1_uuid}", headers=admin_headers, data={"description": faker.pystr()}, ) assert r.status_code == 404 # simulate the dataset has an output directory # create the output directory in the same way is created in launch pipeline task output_path = OUTPUT_ROOT.joinpath(dir_path.relative_to(INPUT_ROOT)) output_path.mkdir(parents=True) assert output_path.is_dir() # delete a dataset # delete a dataset you do not own r = client.delete(f"{API_URI}/dataset/{dataset1_uuid}", headers=user_A1_headers) assert r.status_code == 404 # admin delete a dataset of a group he don't belong r = client.delete(f"{API_URI}/dataset/{dataset1_uuid}", headers=admin_headers) assert r.status_code == 404 # delete a dataset you own r = client.delete(f"{API_URI}/dataset/{dataset1_uuid}", headers=user_B1_headers) assert r.status_code == 204 assert not dir_path.is_dir() # delete a study own by your group r = client.delete(f"{API_URI}/dataset/{dataset2_uuid}", headers=user_B2_headers) assert r.status_code == 204 # check dataset deletion r = client.get(f"{API_URI}/dataset/{dataset1_uuid}", headers=user_B1_headers) assert r.status_code == 404 not_existent_message = self.get_content(r) assert isinstance(not_existent_message, str) assert not_existent_message == not_authorized_message # check directory deletion assert not dir_path.is_dir() assert not output_path.is_dir() # delete all the elements used by the test delete_test_env( client, user_A1_headers, user_B1_headers, user_B1_uuid, user_B2_uuid, user_A1_uuid, uuid_group_A, uuid_group_B, study1_uuid=study1_uuid, study2_uuid=study2_uuid, )