Реализована интеграция с СМС провайдером
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
import base64
|
||||
import json
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
|
||||
import yaml
|
||||
from pydantic import SecretStr
|
||||
|
||||
from app.main import app, websocket_token
|
||||
from app.main import app, otp_settings, websocket_token
|
||||
from app.services import SettingsSnapshot
|
||||
|
||||
EXPECTED_PATHS = {
|
||||
"/health/live",
|
||||
@@ -56,3 +59,68 @@ def test_websocket_accepts_canonical_base64url_jwt_protocol() -> None:
|
||||
def test_committed_openapi_server_does_not_double_api_prefix() -> None:
|
||||
committed = yaml.safe_load(Path("openapi.yaml").read_text(encoding="utf-8"))
|
||||
assert committed["servers"] == [{"url": "/"}]
|
||||
|
||||
|
||||
def test_otp_settings_contract_is_strict_and_complete() -> None:
|
||||
generated = app.openapi()
|
||||
response = generated["paths"]["/internal/settings/v1/otp"]["get"]["responses"]["200"]
|
||||
schema_ref = response["content"]["application/json"]["schema"]["$ref"]
|
||||
schema = generated["components"]["schemas"][schema_ref.rsplit("/", 1)[-1]]
|
||||
|
||||
assert set(schema["required"]) == {
|
||||
"max_send_attempts_per_24h",
|
||||
"min_seconds_between_attempts",
|
||||
"max_verify_attempts",
|
||||
"code_length",
|
||||
"ttl_seconds",
|
||||
"sms_order_timeout_ms",
|
||||
"version",
|
||||
"cache_ttl_seconds",
|
||||
}
|
||||
assert schema["additionalProperties"] is False
|
||||
assert schema["properties"]["code_length"] == {
|
||||
"type": "integer",
|
||||
"maximum": 10.0,
|
||||
"minimum": 4.0,
|
||||
"title": "Code Length",
|
||||
}
|
||||
assert schema["properties"]["ttl_seconds"]["multipleOf"] == 60
|
||||
|
||||
|
||||
async def test_otp_settings_returns_runtime_values_and_supports_etag() -> None:
|
||||
request = SimpleNamespace(
|
||||
headers={"Authorization": "Bearer bridge-token"},
|
||||
app=SimpleNamespace(
|
||||
state=SimpleNamespace(
|
||||
settings=SimpleNamespace(
|
||||
keycloak_settings_bridge_token=SecretStr("bridge-token")
|
||||
)
|
||||
)
|
||||
),
|
||||
)
|
||||
settings = SettingsSnapshot(
|
||||
{
|
||||
"otp.phone.max_send_attempts_per_24h": "3",
|
||||
"otp.phone.min_seconds_between_attempts": "30",
|
||||
"otp.phone.max_verify_attempts": "5",
|
||||
"otp.phone.code_length": "6",
|
||||
"otp.phone.ttl_seconds": "60",
|
||||
"otp.phone.sms_order_timeout_ms": "3000",
|
||||
},
|
||||
"settings-version",
|
||||
)
|
||||
|
||||
response = await otp_settings(request, settings)
|
||||
assert json.loads(response.body) == {
|
||||
"max_send_attempts_per_24h": 3,
|
||||
"min_seconds_between_attempts": 30,
|
||||
"max_verify_attempts": 5,
|
||||
"code_length": 6,
|
||||
"ttl_seconds": 60,
|
||||
"sms_order_timeout_ms": 3000,
|
||||
"version": "settings-version",
|
||||
"cache_ttl_seconds": 60,
|
||||
}
|
||||
|
||||
cached = await otp_settings(request, settings, response.headers["etag"])
|
||||
assert cached.status_code == 304
|
||||
|
||||
Reference in New Issue
Block a user