def all_orders_to_submit( balsamic_order_to_submit, fastq_order_to_submit, metagenome_order_to_submit, microbial_order_to_submit, mip_order_to_submit, mip_rna_order_to_submit, rml_order_to_submit, sarscov2_order_to_submit, ): return { OrderType.BALSAMIC: OrderIn.parse_obj(balsamic_order_to_submit, project=OrderType.BALSAMIC), OrderType.FASTQ: OrderIn.parse_obj(fastq_order_to_submit, project=OrderType.FASTQ), OrderType.FLUFFY: OrderIn.parse_obj(rml_order_to_submit, project=OrderType.FLUFFY), OrderType.METAGENOME: OrderIn.parse_obj(metagenome_order_to_submit, project=OrderType.METAGENOME), OrderType.MICROSALT: OrderIn.parse_obj(microbial_order_to_submit, project=OrderType.MICROSALT), OrderType.MIP_DNA: OrderIn.parse_obj(mip_order_to_submit, project=OrderType.MIP_DNA), OrderType.MIP_RNA: OrderIn.parse_obj(mip_rna_order_to_submit, project=OrderType.MIP_RNA), OrderType.RML: OrderIn.parse_obj(rml_order_to_submit, project=OrderType.RML), OrderType.SARS_COV_2: OrderIn.parse_obj(sarscov2_order_to_submit, project=OrderType.SARS_COV_2), }
def test_validate_sex_inconsistent_sex(orders_api: OrdersAPI, mip_order_to_submit: dict, helpers: StoreHelpers): # GIVEN we have an order with a sample that is already in the database but with different sex order_data = OrderIn.parse_obj(mip_order_to_submit, project=OrderType.MIP_DNA) store = orders_api.status customer_obj = store.customer(order_data.customer) # add sample with different sex than in order sample: MipDnaSample for sample in order_data.samples: sample_obj: models.Sample = helpers.add_sample( store=store, subject_id=sample.subject_id, name=sample.name, gender="male" if sample.sex == "female" else "female", customer_id=customer_obj.internal_id, ) store.add_commit(sample_obj) assert sample_obj.sex != sample.sex submitter: MipDnaSubmitter = MipDnaSubmitter(lims=orders_api.lims, status=orders_api.status) # WHEN calling _validate_sex # THEN an OrderError should be raised on non-matching sex with pytest.raises(OrderError): submitter._validate_subject_sex(samples=order_data.samples, customer_id=order_data.customer)
def metagenome_status_data(metagenome_order_to_submit: dict): """Parse metagenome order example.""" project: OrderType = OrderType.METAGENOME order: OrderIn = OrderIn.parse_obj(obj=metagenome_order_to_submit, project=project) return MetagenomeSubmitter.order_to_status(order=order)
def test_validate_sex_unknown_new_sex(orders_api: OrdersAPI, mip_order_to_submit: dict, helpers: StoreHelpers): # GIVEN we have an order with a sample that is already in the database and with different gender but the new is of # type "unknown" order_data = OrderIn.parse_obj(mip_order_to_submit, project=OrderType.MIP_DNA) store = orders_api.status customer_obj = store.customer(order_data.customer) # add sample with different sex than in order for sample in order_data.samples: sample_obj: models.Sample = helpers.add_sample( store=store, subject_id=sample.subject_id, name=sample.name, gender=sample.sex, customer_id=customer_obj.internal_id, ) sample.sex = "unknown" store.add_commit(sample_obj) for sample in order_data.samples: assert sample_obj.sex != sample.sex submitter: MipDnaSubmitter = MipDnaSubmitter(lims=orders_api.lims, status=orders_api.status) # WHEN calling _validate_sex submitter._validate_subject_sex(samples=order_data.samples, customer_id=order_data.customer)
def test_store_items_in_status_control_has_stored_value( sarscov2_order_to_submit: dict, base_store: Store): # GIVEN sarscov2 order with three samples with control value order: OrderIn = OrderIn.parse_obj(sarscov2_order_to_submit, OrderType.SARS_COV_2) control_value = ControlEnum.positive sample: SarsCov2Sample for sample in order.samples: sample.control: ControlEnum = control_value submitter: SarsCov2Submitter = SarsCov2Submitter(status=base_store, lims=None) status_data = submitter.order_to_status(order=order) # WHEN storing the order submitter.store_items_in_status( comment="", customer=order.customer, data_analysis=Pipeline.SARS_COV_2, data_delivery=DataDelivery.FASTQ, order="", ordered=dt.datetime.now(), ticket=123456, items=status_data.get("samples"), ) # THEN control should exist on the sample in the store customer = base_store.customer(order.customer) sample: SarsCov2Sample for sample in order.samples: stored_sample: models.Sample = base_store.find_samples( customer=customer, name=sample.name).first() assert stored_sample.control == control_value
def test_submit( all_orders_to_submit: dict, base_store: Store, monkeypatch, order_type: OrderType, orders_api: OrdersAPI, ticket_number: int, user_mail: str, user_name: str, ): order_data = OrderIn.parse_obj(obj=all_orders_to_submit[order_type], project=order_type) monkeypatch_process_lims(monkeypatch, order_data) # GIVEN an order and an empty store assert base_store.samples().first() is None # WHEN submitting the order result = orders_api.submit(project=order_type, order_in=order_data, user_name=user_name, user_mail=user_mail) # THEN the result should contain the ticket number for the order for record in result["records"]: if isinstance(record, (models.Pool, models.Sample)): assert record.ticket_number == ticket_number elif isinstance(record, models.Family): for link_obj in record.links: assert link_obj.sample.ticket_number == ticket_number
def test_pools_to_status(rml_order_to_submit): # GIVEN a rml order with three samples in one pool order = OrderIn.parse_obj(rml_order_to_submit, OrderType.RML) # WHEN parsing for status data = RmlSubmitter.order_to_status(order=order) # THEN it should pick out the general information assert data["customer"] == "cust000" assert data["order"] == "#123456" assert data["comment"] == "order comment" # ... and information about the pool(s) assert len(data["pools"]) == 2 pool = data["pools"][0] assert pool["name"] == "pool-1" assert pool["application"] == "RMLP05R800" assert pool["data_analysis"] == str(Pipeline.FLUFFY) assert pool["data_delivery"] == str(DataDelivery.NIPT_VIEWER) assert len(pool["samples"]) == 2 sample = pool["samples"][0] assert sample["name"] == "sample1" assert sample["comment"] == "test comment" assert pool["priority"] == "research" assert sample["control"] == "negative"
def test_submit_unique_sample_case_name( orders_api: OrdersAPI, mip_order_to_submit: dict, ticket_number: int, user_name: str, user_mail: str, monkeypatch, ): # GIVEN we have an order with a case that is not existing in the database order_data = OrderIn.parse_obj(obj=mip_order_to_submit, project=OrderType.MIP_DNA) store = orders_api.status sample: MipDnaSample for sample in order_data.samples: case_id = sample.family_name customer_obj = store.customer(order_data.customer) assert not store.find_family(customer=customer_obj, name=case_id) monkeypatch_process_lims(monkeypatch, order_data) # WHEN calling submit orders_api.submit(project=OrderType.MIP_DNA, order_in=order_data, user_name=user_name, user_mail=user_mail)
def test_to_lims_mip(mip_order_to_submit): # GIVEN a scout order for a trio order_data = OrderIn.parse_obj(obj=mip_order_to_submit, project=OrderType.MIP_DNA) # WHEN parsing the order to format for LIMS import samples: List[LimsSample] = build_lims_sample(customer="cust003", samples=order_data.samples) # THEN it should list all samples assert len(samples) == 4 # THEN container should be 96 well plate for all samples assert {sample.container for sample in samples} == {"96 well plate"} # THEN container names should be the same for all samples container_names = { sample.container_name for sample in samples if sample.container_name } assert container_names == {"CMMS"} # ... and pick out relevant UDFs first_sample: LimsSample = samples[0] assert first_sample.well_position == "A:1" assert first_sample.udfs.family_name == "family1" assert first_sample.udfs.priority == "standard" assert first_sample.udfs.application == "WGSPCFC030" assert first_sample.udfs.source == "tissue (fresh frozen)" assert first_sample.udfs.quantity == "220" assert first_sample.udfs.customer == "cust003" assert first_sample.udfs.volume == "1" # THEN assert that the comment of a sample is a string assert isinstance(samples[1].udfs.comment, str)
def test_submit_fluffy_duplicate_sample_case_name( all_orders_to_submit: dict, monkeypatch, order_type: OrderType, orders_api: OrdersAPI, ticket_number: int, user_mail: str, user_name: str, ): # GIVEN we have an order with a case that is already in the database order_data = OrderIn.parse_obj(obj=all_orders_to_submit[order_type], project=order_type) monkeypatch_process_lims(monkeypatch, order_data) orders_api.submit(project=order_type, order_in=order_data, user_name=user_name, user_mail=user_mail) # WHEN calling submit # THEN an OrderError should be raised on duplicate case name with pytest.raises(OrderError): orders_api.submit(project=order_type, order_in=order_data, user_name=user_name, user_mail=user_mail)
def test_validate_normal_order(sarscov2_order_to_submit: dict, base_store: Store): # GIVEN sarscov2 order with three samples, none in the database order = OrderIn.parse_obj(sarscov2_order_to_submit, OrderType.SARS_COV_2) # WHEN validating the order SarsCov2Submitter(status=base_store, lims=None).validate_order(order=order)
def test_microbial_samples_to_status(microbial_order_to_submit): # GIVEN microbial order with three samples order = OrderIn.parse_obj(microbial_order_to_submit, OrderType.MICROSALT) # WHEN parsing for status data = MicrobialSubmitter.order_to_status(order=order) # THEN it should pick out samples and relevant information assert len(data["samples"]) == 5 assert data["customer"] == "cust002" assert data["order"] == "Microbial samples" assert data["comment"] == "Order comment" assert data["data_analysis"] == str(Pipeline.MICROSALT) assert data["data_delivery"] == str(DataDelivery.FASTQ) # THEN first sample should contain all the relevant data from the microbial order sample_data = data["samples"][0] assert sample_data["priority"] == "research" assert sample_data["name"] == "all-fields" assert sample_data.get("internal_id") is None assert sample_data["organism_id"] == "M.upium" assert sample_data["reference_genome"] == "NC_111" assert sample_data["application"] == "MWRNXTR003" assert sample_data["comment"] == "plate comment" assert sample_data["volume"] == "1"
def test_to_lims_sarscov2(sarscov2_order_to_submit): # GIVEN a sarscov2 order for samples order_data = OrderIn.parse_obj(obj=sarscov2_order_to_submit, project=OrderType.SARS_COV_2) # WHEN parsing for LIMS samples: List[LimsSample] = build_lims_sample(customer="cust000", samples=order_data.samples) # THEN it should have found the same number of samples assert len(samples) == 5 # ... and pick out relevant UDFs first_sample = samples[0].dict() assert first_sample["udfs"]["collection_date"] == "2021-05-05" assert first_sample["udfs"]["extraction_method"] == "MagNaPure 96" assert first_sample["udfs"]["lab_code"] == "SE110 Växjö" assert first_sample["udfs"]["organism"] == "SARS CoV-2" assert first_sample["udfs"][ "original_lab"] == "Karolinska University Hospital Solna" assert first_sample["udfs"]["original_lab_address"] == "171 76 Stockholm" assert first_sample["udfs"]["pre_processing_method"] == "COVIDSeq" assert first_sample["udfs"]["priority"] == "research" assert first_sample["udfs"]["reference_genome"] == "NC_111" assert first_sample["udfs"]["region"] == "Stockholm" assert first_sample["udfs"]["region_code"] == "01" assert first_sample["udfs"][ "selection_criteria"] == "1. Allmän övervakning" assert first_sample["udfs"]["volume"] == "1"
def test_too_long_order_name(): # GIVEN order with more than allowed characters name long_name = "A super long order name that is longer than sixty-four characters." assert len(long_name) > models.Sample.order.property.columns[0].type.length # WHEN placing it in the pydantic order model # THEN an error is raised with pytest.raises(ValueError): OrderIn(name=long_name, customer="", comment="", samples=[])
def test_cases_to_status_synopsis(mip_order_to_submit): # GIVEN a scout order with a trio case where synopsis is None for sample in mip_order_to_submit["samples"]: sample["synopsis"] = None project: OrderType = OrderType.MIP_DNA order = OrderIn.parse_obj(mip_order_to_submit, project=project) # WHEN parsing for status MipDnaSubmitter.order_to_status(order=order)
def test_submit_scout_legal_sample_customer( all_orders_to_submit: dict, monkeypatch, order_type: OrderType, orders_api: OrdersAPI, sample_store: Store, ticket_number: int, user_mail: str, user_name: str, ): order_data = OrderIn.parse_obj(obj=all_orders_to_submit[order_type], project=order_type) monkeypatch_process_lims(monkeypatch, order_data) # GIVEN we have an order with a customer that is in the same customer group as customer # that the samples originate from customer_group = sample_store.add_customer_group( "customer999only", "customer 999 only group") sample_store.add_commit(customer_group) sample_customer = sample_store.add_customer( "customer1", "customer 1", scout_access=True, invoice_address="dummy street 1", customer_group=customer_group, invoice_reference="dummy nr", ) order_customer = sample_store.add_customer( "customer2", "customer 2", scout_access=True, invoice_address="dummy street 2", customer_group=customer_group, invoice_reference="dummy nr", ) sample_store.add_commit(sample_customer) sample_store.add_commit(order_customer) existing_sample = sample_store.samples().first() existing_sample.customer = sample_customer sample_store.commit() order_data.customer = order_customer.internal_id for sample in order_data.samples: sample.internal_id = existing_sample.internal_id break # WHEN calling submit # THEN an OrderError should not be raised on illegal customer orders_api.submit(project=order_type, order_in=order_data, user_name=user_name, user_mail=user_mail)
def test_order_to_status_control_exists(sarscov2_order_to_submit: dict, base_store: Store): # GIVEN sarscov2 order with three samples order: OrderIn = OrderIn.parse_obj(sarscov2_order_to_submit, OrderType.SARS_COV_2) # WHEN transforming order to status structure result: dict = SarsCov2Submitter.order_to_status(order=order) # THEN check that control is in the result sample: dict for sample in result.get("samples"): assert "control" in sample
def submit_order(order_type): """Submit an order for samples.""" api = OrdersAPI(lims=lims, status=db, osticket=osticket) error_message: str try: request_json = request.get_json() LOG.info("processing order: %s", request_json) project: OrderType = OrderType(order_type) order_in: OrderIn = OrderIn.parse_obj(request_json, project=project) result = api.submit( project=project, order_in=order_in, user_name=g.current_user.name, user_mail=g.current_user.email, ) except ( # user misbehaviour OrderError, OrderFormError, ValidationError, ValueError, ) as error: error_message = error.message if hasattr(error, "message") else str(error) http_error_response = http.HTTPStatus.BAD_REQUEST LOG.error(error_message) except ( # system misbehaviour AttributeError, ConnectionError, HTTPError, IntegrityError, KeyError, NewConnectionError, MaxRetryError, TimeoutError, TypeError, ) as error: LOG.exception(error) error_message = error.message if hasattr(error, "message") else str(error) http_error_response = http.HTTPStatus.INTERNAL_SERVER_ERROR else: return jsonify( project=result["project"], records=[record.to_dict() for record in result["records"]]) if error_message: return abort( make_response(jsonify(message=error_message), http_error_response))
def test_metagenome_to_status(metagenome_order_to_submit): # GIVEN metagenome order with two samples order = OrderIn.parse_obj(metagenome_order_to_submit, OrderType.METAGENOME) # WHEN parsing for status data = MetagenomeSubmitter.order_to_status(order=order) # THEN it should pick out samples and relevant information assert len(data["samples"]) == 2 first_sample = data["samples"][0] assert first_sample["name"] == "Bristol" assert first_sample["application"] == "METLIFR020" assert first_sample["priority"] == "standard" assert first_sample["volume"] == "1"
def test_validate_submitted_control_order(sarscov2_order_to_submit: dict, base_store: Store, helpers: StoreHelpers): # GIVEN sarscov2 order with three control samples, all in the database order: OrderIn = OrderIn.parse_obj(sarscov2_order_to_submit, OrderType.SARS_COV_2) sample: SarsCov2Sample for sample in order.samples: helpers.add_sample(store=base_store, name=sample.name, customer_id=order.customer) sample.control = ControlEnum.positive # WHEN validating the order # THEN it should be regarded as valid SarsCov2Submitter(status=base_store, lims=None).validate_order(order=order)
def test_validate_submitted_order(sarscov2_order_to_submit: dict, base_store: Store, helpers: StoreHelpers): # GIVEN sarscov2 order with three samples, all in the database order: OrderIn = OrderIn.parse_obj(sarscov2_order_to_submit, OrderType.SARS_COV_2) sample: SarsCov2Sample for sample in order.samples: helpers.add_sample(store=base_store, name=sample.name, customer_id=order.customer) # WHEN validating the order # THEN it should be regarded as invalid with (pytest.raises(OrderError)): SarsCov2Submitter(status=base_store, lims=None).validate_order(order=order)
def test_to_lims_fastq(fastq_order_to_submit): # GIVEN a fastq order for two samples; normal vs. tumour order_data = OrderIn.parse_obj(obj=fastq_order_to_submit, project=OrderType.FASTQ) # WHEN parsing the order to format for LIMS samples: List[LimsSample] = build_lims_sample(customer="dummyCust", samples=order_data.samples) # THEN should "work" assert len(samples) == 2 normal_sample = samples[0] tumor_sample = samples[1] # ... and pick out relevant UDF values assert normal_sample.udfs.tumour is False assert tumor_sample.udfs.tumour is True assert normal_sample.udfs.volume == "1"
def test_to_lims_rml(rml_order_to_submit): # GIVEN a rml order for four samples order_data = OrderIn.parse_obj(obj=rml_order_to_submit, project=OrderType.RML) # WHEN parsing for LIMS samples: List[LimsSample] = build_lims_sample(customer="dummyCust", samples=order_data.samples) # THEN it should have found the same number of samples assert len(samples) == 4 # ... and pick out relevant UDFs first_sample = samples[0] assert first_sample.udfs.pool == "pool-1" assert first_sample.udfs.volume == "30" assert first_sample.udfs.concentration == "5.0" assert first_sample.udfs.index == "IDT DupSeq 10 bp Set B" assert first_sample.udfs.index_number == "1"
def test_order_to_status_control_has_input_value( sarscov2_order_to_submit: dict, base_store: Store): # GIVEN sarscov2 order with three samples with control value set control_value = ControlEnum.positive order: OrderIn = OrderIn.parse_obj(sarscov2_order_to_submit, OrderType.SARS_COV_2) sample: SarsCov2Sample for sample in order.samples: sample.control: ControlEnum = control_value # WHEN transforming order to status structure result: dict = SarsCov2Submitter.order_to_status(order=order) # THEN check that control is in the result sample: dict for sample in result.get("samples"): assert control_value in sample.get("control")
def test_validate_case_name(rml_order_to_submit: dict, base_store: Store, helpers: StoreHelpers): # GIVEN pool order with a case already all in the database order: OrderIn = OrderIn.parse_obj(rml_order_to_submit, OrderType.RML) sample: RmlSample customer: models.Customer = helpers.ensure_customer( store=base_store, customer_id=order.customer) for sample in order.samples: case = helpers.ensure_case( store=base_store, name=PoolSubmitter.create_case_name(ticket=order.ticket, pool_name=sample.pool), customer=customer, data_analysis=Pipeline.FLUFFY, data_delivery=DataDelivery.STATINA, ) base_store.add_commit(case)
def test_samples_to_status(fastq_order_to_submit): # GIVEN fastq order with two samples order = OrderIn.parse_obj(fastq_order_to_submit, OrderType.FASTQ) # WHEN parsing for status data = FastqSubmitter.order_to_status(order=order) # THEN it should pick out samples and relevant information assert len(data["samples"]) == 2 first_sample = data["samples"][0] assert first_sample["name"] == "prov1" assert first_sample["application"] == "WGSPCFC060" assert first_sample["priority"] == "priority" assert first_sample["tumour"] is False assert first_sample["volume"] == "1" # ... and the other sample is a tumour assert data["samples"][1]["tumour"] is True
def test_to_lims_balsamic(balsamic_order_to_submit): # GIVEN a cancer order for a sample order_data = OrderIn.parse_obj(obj=balsamic_order_to_submit, project=OrderType.BALSAMIC) # WHEN parsing the order to format for LIMS import samples: List[LimsSample] = build_lims_sample(customer="cust000", samples=order_data.samples) # THEN it should list all samples assert len(samples) == 1 # ... and determine the container, container name, and well position container_names = { sample.container_name for sample in samples if sample.container_name } # ... and pick out relevant UDFs first_sample = samples[0].dict() assert first_sample["name"] == "s1" assert {sample.container for sample in samples} == set(["96 well plate"]) assert first_sample["udfs"]["data_analysis"] == str(Pipeline.BALSAMIC) assert first_sample["udfs"]["application"] == "WGSPCFC030" assert first_sample["udfs"]["sex"] == "M" assert first_sample["udfs"]["family_name"] == "family1" assert first_sample["udfs"]["customer"] == "cust000" assert first_sample["udfs"]["source"] == "blood" assert first_sample["udfs"]["volume"] == "1" assert first_sample["udfs"]["priority"] == "standard" assert container_names == set(["p1"]) assert first_sample["well_position"] == "A:1" assert first_sample["udfs"]["tumour"] is True assert first_sample["udfs"]["capture_kit"] == "other" assert first_sample["udfs"]["tumour_purity"] == "75" assert first_sample["udfs"]["formalin_fixation_time"] == "1" assert first_sample["udfs"]["post_formalin_fixation_time"] == "2" assert first_sample["udfs"]["tissue_block_size"] == "small" assert first_sample["udfs"]["quantity"] == "2" assert first_sample["udfs"]["comment"] == "other Elution buffer"
def test_to_lims_microbial(microbial_order_to_submit): # GIVEN a microbial order for three samples order_data = OrderIn.parse_obj(obj=microbial_order_to_submit, project=OrderType.MICROSALT) # WHEN parsing for LIMS samples: List[LimsSample] = build_lims_sample(customer="cust000", samples=order_data.samples) # THEN it should "work" assert len(samples) == 5 # ... and pick out relevant UDFs first_sample = samples[0].dict() assert first_sample["udfs"]["priority"] == "research" assert first_sample["udfs"]["organism"] == "M.upium" assert first_sample["udfs"]["reference_genome"] == "NC_111" assert (first_sample["udfs"]["extraction_method"] == "MagNaPure 96 (contact Clinical Genomics " "before submission)") assert first_sample["udfs"]["volume"] == "1"
def test_submit_unique_sample_name( all_orders_to_submit: dict, monkeypatch, order_type: OrderType, orders_api: OrdersAPI, ticket_number: int, user_mail: str, user_name: str, ): # GIVEN we have an order with a sample that is not existing in the database order_data = OrderIn.parse_obj(obj=all_orders_to_submit[order_type], project=order_type) store = orders_api.status assert store.samples().first() is None monkeypatch_process_lims(monkeypatch, order_data) # WHEN calling submit orders_api.submit(project=order_type, order_in=order_data, user_name=user_name, user_mail=user_mail)
def test_not_sarscov2_submit_duplicate_sample_name( all_orders_to_submit: dict, helpers: StoreHelpers, monkeypatch, order_type: OrderType, orders_api: OrdersAPI, sample_store: Store, ticket_number: int, user_mail: str, user_name: str, ): # GIVEN we have an order with samples that is already in the database order_data = OrderIn.parse_obj(obj=all_orders_to_submit[order_type], project=order_type) monkeypatch_process_lims(monkeypatch, order_data) store_samples_with_names_from_order(orders_api.status, helpers, order_data) # WHEN calling submit orders_api.submit(project=order_type, order_in=order_data, user_name=user_name, user_mail=user_mail)