Реализация на отдельных двух машинах с протестированным взаимодействием по проверке сообщений

This commit is contained in:
mi
2026-08-19 18:24:00 +03:00
parent bbef7a30c9
commit c7a80e7256
103 changed files with 3457 additions and 3725 deletions
@@ -13,6 +13,7 @@ from app.integrations import (
)
from app.realtime import CHANNEL_PREFIX
from app.settings import Settings
from app.workers import worker_http_clients
def settings() -> Settings:
@@ -25,8 +26,9 @@ def settings() -> Settings:
"KEYCLOAK_INTERNAL_URL": "http://keycloak:8080",
"KEYCLOAK_REALM": "han",
"KEYCLOAK_AUDIENCE": "api",
"MESSAGE_SAFETY_URL": "http://safety:8080",
"MESSAGE_SAFETY_URL": "https://processing.internal:8443",
"MESSAGE_SAFETY_SERVICE_TOKEN": "safety-token",
"MESSAGE_SAFETY_CA_FILE": "/run/config/message-safety-internal-ca.pem",
"BITRIX_LOCAL_APP_BASE_URL": "http://bitrix:8080",
"BITRIX_LOCAL_APP_INTERNAL_TOKEN": "bitrix-token",
"BITRIX_API_INBOX_TOKEN": "inbox-token",
@@ -42,6 +44,85 @@ def settings() -> Settings:
return Settings.model_validate(common)
@pytest.mark.asyncio
async def test_worker_uses_isolated_tls_client_for_remote_safety(monkeypatch) -> None:
created = []
class FakeAsyncClient:
def __init__(self, **kwargs):
self.kwargs = kwargs
self.closed = False
created.append(self)
async def __aenter__(self):
return self
async def __aexit__(self, *_):
self.closed = True
monkeypatch.setattr("app.workers.httpx.AsyncClient", FakeAsyncClient)
async with worker_http_clients(settings()) as (openlines_http, safety_http):
assert openlines_http.kwargs == {}
assert safety_http.kwargs == {
"verify": "/run/config/message-safety-internal-ca.pem"
}
assert openlines_http is not safety_http
assert all(client.closed for client in created)
@pytest.mark.asyncio
async def test_safety_ready_uses_private_status_alias_and_accepts_redis_degradation() -> None:
async def handler(request: httpx.Request) -> httpx.Response:
assert request.url.path == "/internal/safety/status"
return httpx.Response(
200,
json={
"status": "degraded",
"processing_mode": "standard",
"config_version": 1,
"capabilities": {
"text": "ready",
"links": "ready",
"files": "ready",
"worker": "ready",
},
},
)
async with httpx.AsyncClient(transport=httpx.MockTransport(handler)) as http:
assert await SafetyClient(settings(), http).ready() is True
@pytest.mark.asyncio
@pytest.mark.parametrize(
("processing_mode", "files"),
(("mock", "ready"), ("standard", "unavailable")),
)
async def test_safety_ready_rejects_unsafe_mode_or_unavailable_capability(
processing_mode: str, files: str
) -> None:
async def handler(_: httpx.Request) -> httpx.Response:
return httpx.Response(
200,
json={
"status": "degraded",
"processing_mode": processing_mode,
"config_version": 1,
"capabilities": {
"text": "ready",
"links": "ready",
"files": files,
"worker": "ready",
},
},
)
async with httpx.AsyncClient(transport=httpx.MockTransport(handler)) as http:
assert await SafetyClient(settings(), http).ready() is False
def test_realtime_channel_matches_redis_acl_namespace() -> None:
assert CHANNEL_PREFIX == "han:rt:dialog:"