Реализация на отдельных двух машинах с протестированным взаимодействием по проверке сообщений
This commit is contained in:
@@ -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:"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user