test: add end-to-end and load verification

This commit is contained in:
2026-09-20 17:46:42 +03:30
parent 85d9003e43
commit d2a678264e
3 changed files with 1145 additions and 0 deletions

View File

@@ -0,0 +1,242 @@
import json
import os
import random
import time
import uuid
from collections import Counter
from concurrent.futures import ThreadPoolExecutor, as_completed
from copy import deepcopy
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen
BASE_URL = os.getenv(
"BASE_URL",
"http://localhost:8000",
)
ENDPOINT = f"{BASE_URL}/api/v1/cdr/raw"
RUN_ID = os.getenv(
"RUN_ID",
uuid.uuid4().hex[:8],
)
def valid_payload(index: int) -> dict:
start = int(time.time())
return {
"raw_id": f"functional-{RUN_ID}-{index:04d}",
"src_ip": "10.240.12.1",
"device_id": "310410998877665",
"caller_num": "+14155552671",
"svc": "4G_DATA",
"up_bytes": 1024,
"down_bytes": 4096,
"rat": 6,
"lac": "4021",
"ci": "8812",
"epoch_start": start,
"epoch_end": start + 300,
}
def send_json(payload: dict) -> int | str:
body = json.dumps(
payload
).encode("utf-8")
return send_raw(body)
def send_raw(body: bytes) -> int | str:
request = Request(
ENDPOINT,
data=body,
method="POST",
headers={
"Content-Type": "application/json",
},
)
try:
with urlopen(
request,
timeout=10,
) as response:
return response.status
except HTTPError as exc:
return exc.code
except URLError as exc:
return f"network_error:{exc.reason}"
def main() -> None:
requests: list[
tuple[str, dict | bytes]
] = []
valid_records = [
valid_payload(index)
for index in range(1000)
]
# 1000 valid CDRs
for payload in valid_records:
requests.append(
("valid", payload)
)
# 20 missing caller_num
for index in range(20):
payload = valid_payload(
2000 + index
)
payload.pop(
"caller_num"
)
requests.append(
("missing_caller_num", payload)
)
# 10 malformed JSON requests
for _ in range(10):
requests.append(
(
"invalid_json",
b'{"raw_id": invalid}',
)
)
# 10 invalid RAT values
for index in range(10):
payload = valid_payload(
3000 + index
)
payload["rat"] = 99
requests.append(
("invalid_rat", payload)
)
# 10 invalid epochs
for index in range(10):
payload = valid_payload(
4000 + index
)
payload["epoch_start"] = (
payload["epoch_end"] + 100
)
requests.append(
("invalid_epoch", payload)
)
# 20 duplicates of already accepted valid records.
for payload in valid_records[:20]:
requests.append(
(
"duplicate",
deepcopy(payload),
)
)
random.shuffle(
requests
)
results = Counter()
started_at = time.perf_counter()
with ThreadPoolExecutor(
max_workers=50
) as executor:
futures = []
for request_type, payload in requests:
if isinstance(
payload,
bytes,
):
future = executor.submit(
send_raw,
payload,
)
else:
future = executor.submit(
send_json,
payload,
)
futures.append(
(
request_type,
future,
)
)
for request_type, future in futures:
status = future.result()
results[
(
request_type,
status,
)
] += 1
elapsed = (
time.perf_counter()
- started_at
)
print()
print(
f"Run ID: {RUN_ID}"
)
print(
f"Total requests: {len(requests)}"
)
print(
f"Elapsed: {elapsed:.2f}s"
)
print()
for (
request_type,
status,
), count in sorted(
results.items(),
key=lambda item: str(
item[0]
),
):
print(
f"{request_type:24} "
f"status={status!s:8} "
f"count={count}"
)
print()
print("Expected:")
print(" valid → 1000 x 202")
print(" duplicate → 20 x 202")
print(" missing_caller → 20 x 400")
print(" invalid_json → 10 x 400")
print(" invalid_rat → 10 x 400")
print(" invalid_epoch → 10 x 400")
if __name__ == "__main__":
main()