Skip to content

Commit 825f865

Browse files
ELI 557 - Iteration id must be unique
1 parent 5496516 commit 825f865

File tree

3 files changed

+45
-0
lines changed

3 files changed

+45
-0
lines changed

src/rules_validation_api/validators/campaign_config_validator.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import typing
2+
from collections import Counter
23
from operator import attrgetter
34

45
from pydantic import field_validator, model_validator
@@ -13,6 +14,16 @@ class CampaignConfigValidation(CampaignConfig):
1314
def validate_iterations(cls, iterations: list[Iteration]) -> list[IterationValidation]:
1415
return [IterationValidation(**i.model_dump()) for i in iterations]
1516

17+
@model_validator(mode="after")
18+
def validate_iterations_have_unique_id(self) -> typing.Self:
19+
ids = [iteration.id for iteration in self.iterations]
20+
duplicates = {i_id for i_id, count in Counter(ids).items() if count > 1}
21+
if duplicates:
22+
raise ValueError(
23+
f"Iterations contain duplicate IDs: {', '.join(duplicates)}"
24+
)
25+
return self
26+
1627
@model_validator(mode="after")
1728
def validate_campaign_has_iteration_within_schedule(self) -> typing.Self:
1829
iterations_by_date = sorted(self.iterations, key=attrgetter("iteration_date"))

tests/unit/validation/conftest.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,26 @@ def valid_campaign_config_with_only_mandatory_fields():
3434
}
3535

3636

37+
@pytest.fixture
38+
def valid_iteration_with_only_mandatory_fields():
39+
return {
40+
"ID": "ITER001",
41+
"Version": 1,
42+
"Name": "Mid-January Push",
43+
"IterationDate": "20250102",
44+
"IterationNumber": 1,
45+
"ApprovalMinimum": 10,
46+
"ApprovalMaximum": 100,
47+
"Type": "A",
48+
"DefaultCommsRouting": "",
49+
"DefaultNotEligibleRouting": "",
50+
"DefaultNotActionableRouting": "",
51+
"IterationCohorts": [],
52+
"IterationRules": [],
53+
"ActionsMapper": {},
54+
}
55+
56+
3757
@pytest.fixture
3858
def valid_iteration_rule_with_only_mandatory_fields():
3959
return {

tests/unit/validation/test_campaign_config_validator.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,3 +233,17 @@ def test_validate_iterations_non_empty(self, valid_campaign_config_with_only_man
233233
CampaignConfigValidation(**data)
234234
errors = error.value.errors()
235235
assert any(e["loc"][-1] == "Iterations" for e in errors), "Expected validation error on 'Iterations'"
236+
237+
def test_unique_iteration_ids(self, valid_campaign_config_with_only_mandatory_fields, valid_iteration_with_only_mandatory_fields):
238+
data = valid_campaign_config_with_only_mandatory_fields.copy()
239+
data["Iterations"].append(valid_iteration_with_only_mandatory_fields.copy())
240+
data["Iterations"][1]["ID"] = data["Iterations"][0]["ID"]
241+
with pytest.raises(ValidationError) as exc_info:
242+
CampaignConfigValidation(**data)
243+
244+
# Extract the error message
245+
error_message = str(exc_info.value)
246+
247+
# Assert that the duplicate ID appears in the message
248+
duplicate_id = data["Iterations"][0]["ID"]
249+
assert f"Iterations contain duplicate IDs: {duplicate_id}" in error_message

0 commit comments

Comments
 (0)