diff --git a/cg/services/orders/validation/workflows/fluffy/models/sample.py b/cg/services/orders/validation/workflows/fluffy/models/sample.py index 88169cfb8f..c035275300 100644 --- a/cg/services/orders/validation/workflows/fluffy/models/sample.py +++ b/cg/services/orders/validation/workflows/fluffy/models/sample.py @@ -27,7 +27,7 @@ class FluffySample(Sample): well_position_rml: str | None = None @model_validator(mode="after") - def set_default_index_sequence(self): + def set_default_index_sequence(self) -> "FluffySample": """Set a default index_sequence from the index and index_number.""" if not self.index_sequence and (self.index and self.index_number): try: diff --git a/cg/services/orders/validation/workflows/rml/models/sample.py b/cg/services/orders/validation/workflows/rml/models/sample.py index 82317b3794..cf3e65cae1 100644 --- a/cg/services/orders/validation/workflows/rml/models/sample.py +++ b/cg/services/orders/validation/workflows/rml/models/sample.py @@ -23,11 +23,12 @@ class RmlSample(Sample): pool: str priority: PriorityEnum rml_plate_name: str | None = None + volume: int well_position_rml: str | None = None @model_validator(mode="after") - def set_default_index_sequence(self): + def set_default_index_sequence(self) -> "RmlSample": """Set a default index_sequence from the index and index_number.""" if not self.index_sequence and (self.index and self.index_number): try: diff --git a/tests/conftest.py b/tests/conftest.py index b268bf2696..bda55a3e6a 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -123,6 +123,7 @@ "tests.fixture_plugins.orders_fixtures.order_form_fixtures", "tests.fixture_plugins.orders_fixtures.order_to_submit_fixtures", "tests.fixture_plugins.orders_fixtures.order_fixtures", + "tests.fixture_plugins.orders_fixtures.path_fixtures", "tests.fixture_plugins.orders_fixtures.services_fixtures", "tests.fixture_plugins.orders_fixtures.store_fixtures", "tests.fixture_plugins.orders_fixtures.store_service_fixtures", @@ -745,12 +746,6 @@ def apps_dir(fixtures_dir: Path) -> Path: return Path(fixtures_dir, "apps") -@pytest.fixture(scope="session") -def cgweb_orders_dir(fixtures_dir: Path) -> Path: - """Return the path to the cgweb_orders dir.""" - return Path(fixtures_dir, "cgweb_orders") - - @pytest.fixture(scope="session") def data_dir(fixtures_dir: Path) -> Path: """Return the path to the data dir.""" diff --git a/tests/fixture_plugins/orders_fixtures/order_to_submit_fixtures.py b/tests/fixture_plugins/orders_fixtures/order_to_submit_fixtures.py index 554887ec87..c63d542f2f 100644 --- a/tests/fixture_plugins/orders_fixtures/order_to_submit_fixtures.py +++ b/tests/fixture_plugins/orders_fixtures/order_to_submit_fixtures.py @@ -129,5 +129,23 @@ def tomte_order_to_submit(cgweb_orders_dir: Path) -> dict: def invalid_balsamic_order_to_submit(cgweb_orders_dir: Path) -> dict: """Load an invalid example Balsamic order.""" return ReadFile.get_content_from_file( - file_format=FileFormat.JSON, file_path=Path(cgweb_orders_dir, "FAIL_balsamic.json") + file_format=FileFormat.JSON, file_path=Path(cgweb_orders_dir, "balsamic_FAIL.json") + ) + + +@pytest.fixture(scope="session") +def fluffy_order_to_submit_without_index_sequence(invalid_cgweb_orders_dir) -> dict: + """Load an invalid example Fluffy order.""" + return ReadFile.get_content_from_file( + file_format=FileFormat.JSON, + file_path=Path(invalid_cgweb_orders_dir, "fluffy_no_index_sequence.json"), + ) + + +@pytest.fixture(scope="session") +def rml_order_to_submit_without_index_sequence(invalid_cgweb_orders_dir) -> dict: + """Load an invalid example RML order.""" + return ReadFile.get_content_from_file( + file_format=FileFormat.JSON, + file_path=Path(invalid_cgweb_orders_dir, "rml_no_index_sequence.json"), ) diff --git a/tests/fixture_plugins/orders_fixtures/path_fixtures.py b/tests/fixture_plugins/orders_fixtures/path_fixtures.py new file mode 100644 index 0000000000..74eea596cf --- /dev/null +++ b/tests/fixture_plugins/orders_fixtures/path_fixtures.py @@ -0,0 +1,15 @@ +from pathlib import Path + +import pytest + + +@pytest.fixture(scope="session") +def cgweb_orders_dir(fixtures_dir: Path) -> Path: + """Return the path to the cgweb_orders dir.""" + return Path(fixtures_dir, "cgweb_orders") + + +@pytest.fixture(scope="session") +def invalid_cgweb_orders_dir(fixtures_dir: Path) -> Path: + """Return the path to the invalid_cgweb_orders dir.""" + return Path(fixtures_dir, "invalid_cgweb_orders") diff --git a/tests/fixture_plugins/orders_fixtures/services_fixtures.py b/tests/fixture_plugins/orders_fixtures/services_fixtures.py index e6de30a4d8..ea0823371f 100644 --- a/tests/fixture_plugins/orders_fixtures/services_fixtures.py +++ b/tests/fixture_plugins/orders_fixtures/services_fixtures.py @@ -7,6 +7,7 @@ ) from cg.services.orders.submitter.service import OrderSubmitter from cg.services.orders.submitter.ticket_handler import TicketHandler +from cg.services.orders.validation.model_validator.model_validator import ModelValidator from cg.services.orders.validation.service import OrderValidationService from cg.store.store import Store from tests.mocks.limsmock import MockLimsAPI @@ -17,6 +18,11 @@ def freshdesk_client() -> FreshdeskClient: return FreshdeskClient(base_url="https://mock.freshdesk.com", api_key="mock_api_key") +@pytest.fixture +def model_validator() -> ModelValidator: + return ModelValidator() + + @pytest.fixture def order_validation_service(store_to_submit_and_validate_orders: Store) -> OrderValidationService: return OrderValidationService(store_to_submit_and_validate_orders) @@ -35,11 +41,6 @@ def order_submitter( ) -@pytest.fixture -def ticket_handler(store: Store, freshdesk_client: FreshdeskClient) -> TicketHandler: - return TicketHandler(db=store, client=freshdesk_client, system_email_id=12345, env="production") - - @pytest.fixture def storing_service_registry( store_to_submit_and_validate_orders: Store, lims_api: MockLimsAPI @@ -47,3 +48,8 @@ def storing_service_registry( return setup_storing_service_registry( lims=lims_api, status_db=store_to_submit_and_validate_orders ) + + +@pytest.fixture +def ticket_handler(store: Store, freshdesk_client: FreshdeskClient) -> TicketHandler: + return TicketHandler(db=store, client=freshdesk_client, system_email_id=12345, env="production") diff --git a/tests/fixtures/cgweb_orders/FAIL_balsamic.json b/tests/fixtures/invalid_cgweb_orders/balsamic_FAIL.json similarity index 100% rename from tests/fixtures/cgweb_orders/FAIL_balsamic.json rename to tests/fixtures/invalid_cgweb_orders/balsamic_FAIL.json diff --git a/tests/fixtures/invalid_cgweb_orders/fluffy_no_index_sequence.json b/tests/fixtures/invalid_cgweb_orders/fluffy_no_index_sequence.json new file mode 100644 index 0000000000..570be5a522 --- /dev/null +++ b/tests/fixtures/invalid_cgweb_orders/fluffy_no_index_sequence.json @@ -0,0 +1,72 @@ +{ + "cases": [], + "comment": null, + "customer": "cust000", + "data_delivery": null, + "delivery_type": "statina", + "name": "1604.19.rml", + "project_type": "fluffy", + "samples": [ + { + "age_at_sampling": null, + "application": "RMLP15R100", + "capture_kit": null, + "collection_date": null, + "comment": "comment", + "concentration": "2", + "concentration_ng_ul": null, + "concentration_sample": "4", + "container": null, + "container_name": null, + "control": "positive", + "custom_index": null, + "customer": "cust000", + "data_analysis": "FLUFFY", + "data_delivery": "statina", + "elution_buffer": null, + "extraction_method": null, + "family_name": null, + "father": null, + "formalin_fixation_time": null, + "index": "IDT DupSeq 10 bp Set B", + "index_number": "3", + "index_sequence": "", + "internal_id": null, + "lab_code": null, + "mother": null, + "name": "fluffysample1", + "organism": null, + "organism_other": null, + "original_lab": null, + "original_lab_address": null, + "phenotype_groups": null, + "phenotype_terms": null, + "pool": "pool1", + "post_formalin_fixation_time": null, + "pre_processing_method": null, + "primer": null, + "priority": "research", + "quantity": null, + "reagent_label": "C01 IDT_10nt_568 (TGTGAGCGAA-AACTCCGATC)", + "reference_genome": null, + "region": null, + "region_code": null, + "require_qc_ok": false, + "rml_plate_name": "plate1", + "selection_criteria": null, + "sex": null, + "source": null, + "status": null, + "subject_id": null, + "tissue_block_size": null, + "tumour": null, + "tumour_purity": null, + "verified_organism": null, + "volume": "20", + "well_position": null, + "well_position_rml": "A:1" + } + ], + "ticket": null, + "user_id": 1 +} \ No newline at end of file diff --git a/tests/fixtures/invalid_cgweb_orders/rml_no_index_sequence.json b/tests/fixtures/invalid_cgweb_orders/rml_no_index_sequence.json new file mode 100644 index 0000000000..2ff48b8595 --- /dev/null +++ b/tests/fixtures/invalid_cgweb_orders/rml_no_index_sequence.json @@ -0,0 +1,72 @@ +{ + "cases": [], + "comment": null, + "customer": "cust000", + "data_delivery": null, + "delivery_type": "fastq", + "name": "1604.19.rml", + "project_type": "rml", + "samples": [ + { + "age_at_sampling": null, + "application": "RMLP15R500", + "capture_kit": null, + "collection_date": null, + "comment": "", + "concentration": "2", + "concentration_ng_ul": null, + "concentration_sample": null, + "container": null, + "container_name": null, + "control": "", + "custom_index": null, + "customer": "cust000", + "data_analysis": "RAW-DATA", + "data_delivery": "fastq", + "elution_buffer": null, + "extraction_method": null, + "family_name": null, + "father": null, + "formalin_fixation_time": null, + "index": "NEXTflex® v2 UDI Barcodes 1 - 96", + "index_number": "3", + "index_sequence": "", + "internal_id": null, + "lab_code": null, + "mother": null, + "name": "rmlsample4", + "organism": null, + "organism_other": null, + "original_lab": null, + "original_lab_address": null, + "phenotype_groups": null, + "phenotype_terms": null, + "pool": "pool4", + "post_formalin_fixation_time": null, + "pre_processing_method": null, + "primer": null, + "priority": "priority", + "quantity": null, + "reagent_label": "UDI 3 (CGCTGCTC-GGCAGATC)", + "reference_genome": null, + "region": null, + "region_code": null, + "require_qc_ok": false, + "rml_plate_name": "rmplate4", + "selection_criteria": null, + "sex": null, + "source": null, + "status": null, + "subject_id": null, + "tissue_block_size": null, + "tumour": null, + "tumour_purity": null, + "verified_organism": null, + "volume": "23", + "well_position": null, + "well_position_rml": "A:1" + } + ], + "ticket": null, + "user_id": 1 +} \ No newline at end of file diff --git a/tests/services/orders/validation_service/test_model_validator.py b/tests/services/orders/validation_service/test_model_validator.py new file mode 100644 index 0000000000..ff89b587eb --- /dev/null +++ b/tests/services/orders/validation_service/test_model_validator.py @@ -0,0 +1,35 @@ +import pytest + +from cg.services.orders.validation.model_validator.model_validator import ModelValidator +from cg.services.orders.validation.models.order import Order +from cg.services.orders.validation.workflows.fluffy.models.order import FluffyOrder +from cg.services.orders.validation.workflows.rml.models.order import RmlOrder + + +@pytest.mark.parametrize( + "order_fixture, expected_index_sequence, order_model", + [ + ( + "fluffy_order_to_submit_without_index_sequence", + "C01 IDT_10nt_568 (TGTGAGCGAA-AACTCCGATC)", + FluffyOrder, + ), + ("rml_order_to_submit_without_index_sequence", "UDI 3 (CGCTGCTC-GGCAGATC)", RmlOrder), + ], + ids=["fluffy", "rml"], +) +def test_validate_pool_sample_default_index( + order_fixture: str, + expected_index_sequence: str, + order_model: type[Order], + model_validator: ModelValidator, + request: pytest.FixtureRequest, +): + # GIVEN a pool raw order with a sample without index sequence but correct index and index number + raw_order: dict = request.getfixturevalue(order_fixture) + + # WHEN validating the order + order, _ = model_validator.validate(order=raw_order, model=order_model) + + # THEN the index sequence should be set to the default index sequence + assert order.samples[0].index_sequence == expected_index_sequence