Initial commit

This commit is contained in:
2026-09-09 16:21:13 +03:00
commit 2067d8c298
17 changed files with 1887 additions and 0 deletions
+181
View File
@@ -0,0 +1,181 @@
from __future__ import annotations
import csv
import json
import os
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch
from common.security import TokenStore
from common import ApiError
from geo_alarm import CsvRegistrationProcessor, normalize_turkish_name
REGISTRATION_ONE = "f7587d9e-2481-4b4c-818d-c8d1946851b7"
REGISTRATION_TWO = "57d1e2ba-bf2d-4ef3-b078-523060b2000c"
ACCOUNT_ID = "2f04f1b5-1c0a-4c4e-b0a7-0ba6e9b7f2e1"
class FakeClient:
def __init__(self, env_file: Path) -> None:
self.token_store = TokenStore(env_file)
class FakeService:
def __init__(self, env_file: Path) -> None:
self.client = FakeClient(env_file)
self.payloads = []
def get_account_id(self):
return ACCOUNT_ID
def list_cities(self):
return [{"id": 6, "name": "Ankara"}, {"id": 34, "name": "İstanbul"}]
def list_districts(self, city_id):
return {
6: [{"id": 557, "name": "Çankaya"}],
34: [{"id": 347, "name": "Kadıköy"}],
}[city_id]
def create_registration(self, payload, idempotency_key):
self.payloads.append(payload)
registration_id = REGISTRATION_ONE if len(self.payloads) == 1 else REGISTRATION_TWO
warnings = ["test warning"] if len(self.payloads) == 1 else []
return 200, registration_id, warnings
class RecoveringService(FakeService):
def create_registration(self, payload, idempotency_key):
self.payloads.append(payload)
raise ApiError("duplicate", status_code=409)
def find_by_recipient_id(self, recipient_id):
return 200, REGISTRATION_ONE, []
class GeoAlarmTest(unittest.TestCase):
def test_turkish_exact_normalization(self) -> None:
self.assertEqual(normalize_turkish_name(" İSTANBUL "), "istanbul")
self.assertEqual(normalize_turkish_name("IĞDIR"), "ığdır")
self.assertEqual(normalize_turkish_name("ÇANKAYA"), "çankaya")
self.assertNotEqual(normalize_turkish_name("I"), normalize_turkish_name("İ"))
def test_csv_processing_and_webhook_transition(self) -> None:
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
env_file = root / ".env"
env_file.write_text("IKLIM_WEBHOOK_INITIALIZED=false\n", encoding="utf-8")
csv_file = root / "nowcast-geo-alarm-registrations.csv"
csv_file.write_text(
"city;district;recipientId\n"
" anKARA ; ÇANKAYA ;recipient-001\n"
"Ankara;Olmayan;recipient-invalid\n"
"İSTANBUL;KADIKÖY;recipient-002\n",
encoding="utf-8",
)
webhook_file = root / "webhook.json"
webhook_file.write_text(
json.dumps(
{
"url": "https://customer.example/webhook",
"httpMethod": "POST",
"contentType": "application/json",
"authentication": {
"selected": "BASIC",
"options": {
"BASIC": {"username": "user", "password": "pass"}
},
},
}
),
encoding="utf-8",
)
nowcast_filter_file = root / "nowcast-geo-alarm-filter.json"
nowcast_filter_file.write_text(
json.dumps({"precipitation": {"intensities": ["LIGHT"]}}),
encoding="utf-8",
)
service = FakeService(env_file)
with patch.dict(
os.environ, {"IKLIM_WEBHOOK_INITIALIZED": "false"}, clear=True
):
CsvRegistrationProcessor(
service,
csv_path=csv_file,
webhook_config_path=webhook_file,
nowcast_filter_config_path=nowcast_filter_file,
).run()
with csv_file.open("r", encoding="utf-8-sig", newline="") as handle:
rows = list(csv.DictReader(handle, delimiter=";"))
self.assertEqual(
list(rows[0]),
["city", "district", "recipientId", "status", "httpStatus", "registrationId"],
)
self.assertEqual(rows[0]["status"], "SUCCESS")
self.assertEqual(rows[0]["registrationId"], REGISTRATION_ONE)
self.assertEqual(rows[1]["status"], "FAILED")
self.assertEqual(rows[1]["httpStatus"], "NOT_SENT")
self.assertEqual(rows[2]["status"], "SUCCESS")
self.assertEqual(service.payloads[0]["webhook"]["url"], "https://customer.example/webhook")
self.assertNotIn("accountId", service.payloads[0]["webhook"])
self.assertEqual(service.payloads[1]["webhook"], {"accountId": ACCOUNT_ID})
self.assertIn("IKLIM_WEBHOOK_INITIALIZED=true", env_file.read_text())
def test_conflict_is_recovered_by_recipient_id(self) -> None:
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
env_file = root / ".env"
env_file.write_text("IKLIM_WEBHOOK_INITIALIZED=false\n", encoding="utf-8")
csv_file = root / "nowcast-geo-alarm-registrations.csv"
csv_file.write_text(
"city;district;recipientId\nAnkara;Çankaya;recipient-001\n",
encoding="utf-8",
)
webhook_file = root / "webhook.json"
webhook_file.write_text(
json.dumps(
{
"url": "https://customer.example/webhook",
"httpMethod": "POST",
"contentType": "application/json",
"authentication": {
"selected": "BASIC",
"options": {
"BASIC": {"username": "user", "password": "pass"}
},
},
}
),
encoding="utf-8",
)
nowcast_filter_file = root / "nowcast-geo-alarm-filter.json"
nowcast_filter_file.write_text(
json.dumps({"precipitation": {"intensities": ["LIGHT"]}}),
encoding="utf-8",
)
with patch.dict(
os.environ, {"IKLIM_WEBHOOK_INITIALIZED": "false"}, clear=True
):
CsvRegistrationProcessor(
RecoveringService(env_file),
csv_path=csv_file,
webhook_config_path=webhook_file,
nowcast_filter_config_path=nowcast_filter_file,
).run()
with csv_file.open("r", encoding="utf-8-sig", newline="") as handle:
row = next(csv.DictReader(handle, delimiter=";"))
self.assertEqual(row["status"], "SUCCESS")
self.assertEqual(row["httpStatus"], "HTTP_409")
self.assertEqual(row["registrationId"], REGISTRATION_ONE)
if __name__ == "__main__":
unittest.main()