Skip to content

Commit b2b5156

Browse files
committed
DEVEXP-786: Batches - Models and APIs Unit Tests
1 parent 25c49ff commit b2b5156

8 files changed

Lines changed: 1372 additions & 2 deletions
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import pytest
2+
from pydantic import ValidationError
3+
from sinch.domains.sms.models.v1.internal import DeliveryFeedbackRequest
4+
5+
6+
@pytest.fixture
7+
def sample_delivery_feedback_request_data():
8+
return {
9+
"batch_id": "01W4FFL35P4NC4K35SMSBATCH3",
10+
"recipients": ["+46876543210", "+46987654321"],
11+
}
12+
13+
14+
def test_delivery_feedback_request_expects_valid_inputs(
15+
sample_delivery_feedback_request_data,
16+
):
17+
"""Test DeliveryFeedbackRequest with valid inputs."""
18+
request = DeliveryFeedbackRequest(**sample_delivery_feedback_request_data)
19+
assert (
20+
request.batch_id == sample_delivery_feedback_request_data["batch_id"]
21+
)
22+
assert (
23+
request.recipients
24+
== sample_delivery_feedback_request_data["recipients"]
25+
)
26+
27+
28+
def test_delivery_feedback_request_expects_single_recipient():
29+
"""Test DeliveryFeedbackRequest with a single recipient."""
30+
request = DeliveryFeedbackRequest(
31+
batch_id="01W4FFL35P4NC4K35SMSBATCH3",
32+
recipients=["+46876543210"],
33+
)
34+
assert request.batch_id == "01W4FFL35P4NC4K35SMSBATCH3"
35+
assert len(request.recipients) == 1
36+
assert request.recipients[0] == "+46876543210"
37+
38+
39+
def test_delivery_feedback_request_expects_empty_recipients_list():
40+
"""Test DeliveryFeedbackRequest with empty recipients list."""
41+
request = DeliveryFeedbackRequest(
42+
batch_id="01W4FFL35P4NC4K35SMSBATCH3",
43+
recipients=[],
44+
)
45+
assert request.batch_id == "01W4FFL35P4NC4K35SMSBATCH3"
46+
assert request.recipients == []
47+
48+
49+
@pytest.mark.parametrize(
50+
"missing_field",
51+
["batch_id", "recipients"],
52+
)
53+
def test_delivery_feedback_request_expects_required_fields(
54+
sample_delivery_feedback_request_data, missing_field
55+
):
56+
"""Test that DeliveryFeedbackRequest requires batch_id and recipients fields."""
57+
data = sample_delivery_feedback_request_data.copy()
58+
data.pop(missing_field)
59+
with pytest.raises(ValidationError) as exc_info:
60+
DeliveryFeedbackRequest(**data)
61+
assert missing_field in str(exc_info.value)
62+
63+
64+
@pytest.mark.parametrize(
65+
"invalid_batch_id",
66+
[12345, None],
67+
)
68+
def test_delivery_feedback_request_expects_batch_id_must_be_string(
69+
invalid_batch_id,
70+
):
71+
"""Test that batch_id must be a string."""
72+
with pytest.raises(ValidationError):
73+
DeliveryFeedbackRequest(
74+
batch_id=invalid_batch_id,
75+
recipients=["+46876543210"],
76+
)
77+
78+
79+
@pytest.mark.parametrize(
80+
"invalid_recipients",
81+
["+46876543210", [123, 456], ["+46876543210", None]],
82+
)
83+
def test_delivery_feedback_request_expects_recipients_must_be_list_of_strings(
84+
invalid_recipients,
85+
):
86+
"""Test that recipients must be a list of strings."""
87+
with pytest.raises(ValidationError):
88+
DeliveryFeedbackRequest(
89+
batch_id="01W4FFL35P4NC4K35SMSBATCH3",
90+
recipients=invalid_recipients,
91+
)
92+
93+
94+
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
from datetime import datetime, timezone
2+
import pytest
3+
from pydantic import ValidationError
4+
from sinch.domains.sms.models.v1.internal import ListBatchesRequest
5+
6+
7+
def test_list_batches_request_expects_defaults():
8+
"""Test that the model correctly sets default values."""
9+
model = ListBatchesRequest()
10+
assert model.page is None
11+
assert model.page_size is None
12+
assert model.start_date is None
13+
assert model.end_date is None
14+
assert model.from_ is None
15+
assert model.client_reference is None
16+
17+
18+
def test_list_batches_request_expects_parsed_input():
19+
"""Test that the model correctly parses input with all parameters."""
20+
start = datetime(2025, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
21+
end = datetime(2025, 1, 8, 12, 0, 0, tzinfo=timezone.utc)
22+
23+
model = ListBatchesRequest(
24+
page=1,
25+
page_size=50,
26+
start_date=start,
27+
end_date=end,
28+
from_=["+46701234567", "+46709876543"],
29+
client_reference="my-client-ref",
30+
)
31+
32+
assert model.page == 1
33+
assert model.page_size == 50
34+
assert model.start_date == start
35+
assert model.end_date == end
36+
assert model.from_ == ["+46701234567", "+46709876543"]
37+
assert model.client_reference == "my-client-ref"
38+
39+
40+
def test_list_batches_request_expects_from_alias():
41+
"""Test that the 'from' alias works correctly."""
42+
model = ListBatchesRequest(from_=["+46701234567"])
43+
44+
assert model.from_ == ["+46701234567"]
45+
46+
# Check that model_dump with by_alias=True uses "from"
47+
dumped = model.model_dump(exclude_none=True, by_alias=True)
48+
assert "from" in dumped
49+
assert dumped["from"] == ["+46701234567"]
50+
assert "from_" not in dumped
51+
52+
# Check that model_dump with by_alias=False uses "from_"
53+
dumped_no_alias = model.model_dump(exclude_none=True, by_alias=False)
54+
assert "from_" in dumped_no_alias
55+
assert dumped_no_alias["from_"] == ["+46701234567"]
56+
assert "from" not in dumped_no_alias
57+
58+
59+
def test_list_batches_request_expects_partial_input():
60+
"""Test that the model works with partial input."""
61+
model = ListBatchesRequest(page=2, page_size=20)
62+
63+
assert model.page == 2
64+
assert model.page_size == 20
65+
assert model.start_date is None
66+
assert model.end_date is None
67+
assert model.from_ is None
68+
assert model.client_reference is None
69+
70+
71+
def test_list_batches_request_expects_empty_from_list():
72+
"""Test that from_ can be an empty list."""
73+
model = ListBatchesRequest(from_=[])
74+
75+
assert model.from_ == []
76+
77+
78+
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import pytest
2+
from pydantic import ValidationError
3+
from datetime import datetime, timezone
4+
from sinch.domains.sms.models.v1.internal.replace_batch_request import (
5+
ReplaceBinaryRequest,
6+
)
7+
8+
9+
@pytest.fixture
10+
def sample_replace_binary_request_data():
11+
return {
12+
"batch_id": "01FC66621XXXXX119Z8PMV1QPQ",
13+
"to": ["+46701234567", "+46709876543"],
14+
"from_": "+46701111111",
15+
"body": "SGVsbG8gV29ybGQh",
16+
"udh": "06050423F423F4",
17+
}
18+
19+
20+
def test_replace_binary_request_expects_valid_inputs_and_all_fields(
21+
sample_replace_binary_request_data,
22+
):
23+
"""Test ReplaceBinaryRequest with valid inputs and all optional fields."""
24+
request = ReplaceBinaryRequest(**sample_replace_binary_request_data)
25+
assert request.batch_id == sample_replace_binary_request_data["batch_id"]
26+
assert request.to == sample_replace_binary_request_data["to"]
27+
assert request.from_ == sample_replace_binary_request_data["from_"]
28+
assert request.body == sample_replace_binary_request_data["body"]
29+
assert request.udh == sample_replace_binary_request_data["udh"]
30+
assert request.type == "mt_binary"
31+
assert request.delivery_report is None
32+
assert request.feedback_enabled is None
33+
34+
send_at = datetime(2025, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
35+
expire_at = datetime(2025, 1, 2, 12, 0, 0, tzinfo=timezone.utc)
36+
37+
request = ReplaceBinaryRequest(
38+
**sample_replace_binary_request_data,
39+
delivery_report="summary",
40+
send_at=send_at,
41+
expire_at=expire_at,
42+
callback_url="https://capybara.com/callback",
43+
client_reference="test-ref",
44+
feedback_enabled=True,
45+
from_ton=1,
46+
from_npi=1,
47+
)
48+
49+
assert request.delivery_report == "summary"
50+
assert request.send_at == send_at
51+
assert request.expire_at == expire_at
52+
assert request.callback_url == "https://capybara.com/callback"
53+
assert request.client_reference == "test-ref"
54+
assert request.feedback_enabled is True
55+
assert request.from_ton == 1
56+
assert request.from_npi == 1
57+
58+
59+
@pytest.mark.parametrize(
60+
"missing_field",
61+
["batch_id", "to", "body", "udh"],
62+
)
63+
def test_replace_binary_request_expects_required_fields(
64+
sample_replace_binary_request_data, missing_field
65+
):
66+
"""Test that ReplaceBinaryRequest requires batch_id, to, body, and udh fields."""
67+
data = sample_replace_binary_request_data.copy()
68+
data.pop(missing_field)
69+
with pytest.raises(ValidationError) as exc_info:
70+
ReplaceBinaryRequest(**data)
71+
assert missing_field in str(exc_info.value)
72+
73+
74+
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import pytest
2+
from pydantic import ValidationError
3+
from datetime import datetime, timezone
4+
from sinch.domains.sms.models.v1.internal.replace_batch_request import (
5+
ReplaceMediaRequest,
6+
)
7+
from sinch.domains.sms.models.v1.shared import MediaBody
8+
9+
10+
@pytest.fixture
11+
def sample_replace_media_request_data():
12+
return {
13+
"batch_id": "01W4FFL35P4NC4K35SMSBATCH2",
14+
"to": ["+46876543210", "+46987654321"],
15+
"from_": "+46800123456",
16+
"body": MediaBody(
17+
url="https://capybara.com/video.mp4",
18+
message="Watch this amazing capybara video!",
19+
subject="Capybara Video",
20+
),
21+
}
22+
23+
24+
def test_replace_media_request_expects_valid_inputs_and_all_fields(
25+
sample_replace_media_request_data,
26+
):
27+
"""Test ReplaceMediaRequest with valid inputs and all optional fields."""
28+
request = ReplaceMediaRequest(**sample_replace_media_request_data)
29+
assert request.batch_id == sample_replace_media_request_data["batch_id"]
30+
assert request.to == sample_replace_media_request_data["to"]
31+
assert request.from_ == sample_replace_media_request_data["from_"]
32+
assert isinstance(request.body, MediaBody)
33+
assert request.body.url == "https://capybara.com/video.mp4"
34+
assert request.body.message == "Watch this amazing capybara video!"
35+
assert request.body.subject == "Capybara Video"
36+
assert request.type == "mt_media"
37+
assert request.delivery_report is None
38+
assert request.feedback_enabled is None
39+
assert request.strict_validation is None
40+
41+
send_at = datetime(2025, 1, 1, 12, 0, 0, tzinfo=timezone.utc)
42+
expire_at = datetime(2025, 1, 2, 12, 0, 0, tzinfo=timezone.utc)
43+
44+
request = ReplaceMediaRequest(
45+
**sample_replace_media_request_data,
46+
delivery_report="full",
47+
send_at=send_at,
48+
expire_at=expire_at,
49+
callback_url="https://capybara.com/webhook",
50+
client_reference="capybara-media-batch-123",
51+
feedback_enabled=True,
52+
strict_validation=True,
53+
parameters={
54+
"name": {"+46876543210": "Alice", "default": "user"},
55+
"promo": {"+46876543210": "SUMMER2024"},
56+
},
57+
)
58+
59+
assert request.delivery_report == "full"
60+
assert request.send_at == send_at
61+
assert request.expire_at == expire_at
62+
assert request.callback_url == "https://capybara.com/webhook"
63+
assert request.client_reference == "capybara-media-batch-123"
64+
assert request.feedback_enabled is True
65+
assert request.strict_validation is True
66+
assert request.parameters["name"]["+46876543210"] == "Alice"
67+
assert request.parameters["promo"]["+46876543210"] == "SUMMER2024"
68+
69+
70+
@pytest.mark.parametrize(
71+
"missing_field",
72+
["batch_id", "to", "body"],
73+
)
74+
def test_replace_media_request_expects_required_fields(
75+
sample_replace_media_request_data, missing_field
76+
):
77+
"""Test that ReplaceMediaRequest requires batch_id, to, and body fields."""
78+
data = sample_replace_media_request_data.copy()
79+
data.pop(missing_field)
80+
with pytest.raises(ValidationError) as exc_info:
81+
ReplaceMediaRequest(**data)
82+
assert missing_field in str(exc_info.value)
83+
84+
85+
def test_replace_media_request_expects_body_must_be_media_body(
86+
sample_replace_media_request_data,
87+
):
88+
"""Test that body must be a MediaBody instance or dict that can be converted."""
89+
data = sample_replace_media_request_data.copy()
90+
data["body"] = "invalid"
91+
with pytest.raises(ValidationError):
92+
ReplaceMediaRequest(**data)
93+
94+
data["body"] = None
95+
with pytest.raises(ValidationError):
96+
ReplaceMediaRequest(**data)
97+
98+
data["body"] = {"url": "https://capybara.com/audio.mp3"}
99+
request = ReplaceMediaRequest(**data)
100+
assert isinstance(request.body, MediaBody)
101+
assert request.body.url == "https://capybara.com/audio.mp3"

0 commit comments

Comments
 (0)