feat: add cdr processing worker and dlq routing

This commit is contained in:
2026-09-20 14:38:05 +03:30
parent 89a746227b
commit 0e23e5bde8
10 changed files with 623 additions and 22 deletions

36
tests/unit/test_dlq.py Normal file
View File

@@ -0,0 +1,36 @@
from core.domain.errors import (
CDRProcessingError,
FailureReason,
)
from core.worker.dlq import build_dlq_envelope
def test_build_dlq_envelope() -> None:
original = {
"raw_id": "raw-invalid-001",
"rat": 99,
}
error = CDRProcessingError(
reason=FailureReason.INVALID_RAT_VALUE,
detail="Unsupported RAT value: 99.",
failed_field="rat",
)
envelope = build_dlq_envelope(
original_payload=original,
error=error,
worker_instance="worker-test",
)
assert envelope["original_payload"] == original
assert (
envelope["failure_reason"]
== "invalid_rat_value"
)
assert envelope["failed_field"] == "rat"
assert envelope["worker_instance"] == "worker-test"
assert envelope["failed_at"].endswith("Z")

View File

@@ -0,0 +1,78 @@
import json
import pytest
from core.domain.errors import (
CDRProcessingError,
FailureReason,
)
from core.worker.processor import (
decode_payload,
process_payload,
)
def valid_payload() -> dict:
return {
"raw_id": "raw-worker-001",
"src_ip": "10.240.12.1",
"device_id": "310410998877665",
"caller_num": "0019875551234",
"svc": "4G_DATA",
"up_bytes": 100,
"down_bytes": 200,
"rat": 6,
"lac": "4021",
"ci": "8812",
"epoch_start": 1789900000,
"epoch_end": 1789900300,
}
def test_decode_valid_json_object() -> None:
value = json.dumps(
valid_payload()
).encode("utf-8")
payload = decode_payload(value)
assert payload == valid_payload()
def test_malformed_json() -> None:
with pytest.raises(
CDRProcessingError
) as exc_info:
decode_payload(
b'{"raw_id": invalid}'
)
assert (
exc_info.value.reason
== FailureReason.MALFORMED_JSON
)
def test_json_array_is_rejected() -> None:
with pytest.raises(
CDRProcessingError
) as exc_info:
decode_payload(
b'["not", "a", "cdr"]'
)
assert (
exc_info.value.reason
== FailureReason.NORMALIZATION_ERROR
)
def test_worker_normalizes_valid_payload() -> None:
normalized = process_payload(
valid_payload()
)
assert normalized.raw_id == "raw-worker-001"
assert normalized.radio_access_type == "LTE_4G"
assert normalized.total_bytes == 300
assert normalized.duration_seconds == 300