Skip to content

Commit

Permalink
Validate unique case names (#3482)
Browse files Browse the repository at this point in the history
  • Loading branch information
seallard authored Jul 29, 2024
1 parent 3391bdf commit 184783d
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 15 deletions.
5 changes: 5 additions & 0 deletions cg/services/order_validation_service/models/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ class OccupiedWellError(CaseSampleError):
message: str = "Well is already occupied"


class RepeatedCaseNameError(CaseError):
field: str = "name"
message: str = "Case name already used"


class RepeatedSampleNameError(CaseSampleError):
field: str = "name"
message: str = "Sample name already used"
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from cg.services.order_validation_service.models.errors import (
OccupiedWellError,
RepeatedCaseNameError,
RepeatedSampleNameError,
)
from cg.services.order_validation_service.workflows.tomte.models.order import TomteOrder
from cg.services.order_validation_service.workflows.tomte.validation.inter_field.utils import (
_get_errors,
_get_excess_samples,
_get_plate_samples,
get_duplicate_sample_name_errors,
get_repeated_case_name_errors,
get_repeated_sample_name_errors,
)


Expand All @@ -17,9 +19,13 @@ def validate_wells_contain_at_most_one_sample(order: TomteOrder) -> list[Occupie
return _get_errors(samples)


def validate_unique_sample_names_in_cases(order: TomteOrder) -> list[RepeatedSampleNameError]:
def validate_no_repeated_case_names(order: TomteOrder) -> list[RepeatedCaseNameError]:
return get_repeated_case_name_errors(order)


def validate_no_repeated_sample_names(order: TomteOrder) -> list[RepeatedSampleNameError]:
errors: list[RepeatedSampleNameError] = []
for case in order.cases:
case_errors = get_duplicate_sample_name_errors(case)
case_errors = get_repeated_sample_name_errors(case)
errors.extend(case_errors)
return errors
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from cg.models.orders.sample_base import ContainerEnum
from cg.services.order_validation_service.models.errors import (
OccupiedWellError,
RepeatedCaseNameError,
RepeatedSampleNameError,
)
from cg.services.order_validation_service.workflows.tomte.models.case import TomteCase
Expand Down Expand Up @@ -53,12 +54,23 @@ def _get_sample_well_map(plate_samples_with_cases: list[tuple[TomteSample, Tomte
return sample_well_map


def get_duplicate_sample_names(case: TomteCase) -> list[str]:
def get_repeated_case_names(order: TomteOrder) -> list[str]:
case_names = [case.name for case in order.cases]
count = Counter(case_names)
return [name for name, freq in count.items() if freq > 1]


def get_repeated_case_name_errors(order: TomteOrder) -> list[RepeatedCaseNameError]:
case_names = get_repeated_case_names(order)
return [RepeatedCaseNameError(case_name=name) for name in case_names]


def get_repeated_sample_names(case: TomteCase) -> list[str]:
sample_names = [sample.name for sample in case.samples]
count = Counter(sample_names)
return [name for name, freq in count.items() if freq > 1]


def get_duplicate_sample_name_errors(case: TomteCase) -> list[RepeatedSampleNameError]:
sample_names = get_duplicate_sample_names(case)
def get_repeated_sample_name_errors(case: TomteCase) -> list[RepeatedSampleNameError]:
sample_names = get_repeated_sample_names(case)
return [RepeatedSampleNameError(sample_name=name, case_name=case.name) for name in sample_names]
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
validate_ticket_number_required_if_connected,
)
from cg.services.order_validation_service.workflows.tomte.validation.inter_field.rules import (
validate_unique_sample_names_in_cases,
validate_no_repeated_case_names,
validate_no_repeated_sample_names,
validate_wells_contain_at_most_one_sample,
)

Expand All @@ -19,6 +20,7 @@
]

TOMTE_CASE_SAMPLE_RULES = [
validate_unique_sample_names_in_cases,
validate_no_repeated_case_names,
validate_no_repeated_sample_names,
validate_wells_contain_at_most_one_sample,
]
19 changes: 15 additions & 4 deletions tests/services/order_validation_service/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,26 @@ def order_with_samples_in_same_well(case_with_samples_in_same_well: TomteCase) -


@pytest.fixture
def case_with_samples_with_duplicate_names() -> TomteCase:
def case_with_samples_with_repeated_names() -> TomteCase:
sample_1: TomteSample = create_sample(1)
sample_2: TomteSample = create_sample(1)
sample_1.name = sample_2.name
return create_case([sample_1, sample_2])


@pytest.fixture
def order_with_duplicate_sample_names(
case_with_samples_with_duplicate_names: TomteCase,
def order_with_repeated_sample_names(
case_with_samples_with_repeated_names: TomteCase,
) -> TomteOrder:
return create_order([case_with_samples_with_duplicate_names])
return create_order([case_with_samples_with_repeated_names])


@pytest.fixture
def case() -> TomteCase:
sample: TomteSample = create_sample(1)
return create_case([sample])


@pytest.fixture
def order_with_repeated_case_names(case: TomteCase) -> TomteOrder:
return create_order([case, case])
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from cg.services.order_validation_service.models.errors import (
OccupiedWellError,
RepeatedCaseNameError,
RepeatedSampleNameError,
)
from cg.services.order_validation_service.workflows.tomte.models.order import TomteOrder
from cg.services.order_validation_service.workflows.tomte.validation.inter_field.rules import (
validate_unique_sample_names_in_cases,
validate_no_repeated_case_names,
validate_no_repeated_sample_names,
validate_wells_contain_at_most_one_sample,
)

Expand Down Expand Up @@ -34,14 +36,27 @@ def test_order_without_multiple_samples_in_well(valid_order: TomteOrder):
assert not errors


def test_duplicate_sample_names_not_allowed(order_with_duplicate_sample_names: TomteOrder):
def test_repeated_sample_names_not_allowed(order_with_repeated_sample_names: TomteOrder):
# Given an order with samples in a case with the same name

# WHEN validating the order
errors = validate_unique_sample_names_in_cases(order_with_duplicate_sample_names)
errors = validate_no_repeated_sample_names(order_with_repeated_sample_names)

# THEN errors are returned
assert errors

# THEN the errors are about the sample names
assert isinstance(errors[0], RepeatedSampleNameError)


def test_repeated_case_names_not_allowed(order_with_repeated_case_names: TomteOrder):
# GIVEN an order with cases with the same name

# WHEN validating the order
errors = validate_no_repeated_case_names(order_with_repeated_case_names)

# THEN errors are returned
assert errors

# THEN the errors are about the case names
assert isinstance(errors[0], RepeatedCaseNameError)

0 comments on commit 184783d

Please sign in to comment.