build 059.1-059.2: add websocket OHLC transport and schema validation
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
# app/tests/unit/market_data/acquisition/validation/test_websocket_ohlc_schema.py
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from types import MappingProxyType
|
||||
|
||||
import pytest
|
||||
|
||||
from src.market_data.acquisition.exceptions import (
|
||||
CandleWebSocketSchemaError,
|
||||
)
|
||||
from src.market_data.acquisition.validation.schema import (
|
||||
ValidatedWebSocketOhlcDocument,
|
||||
validate_dzengi_websocket_ohlc_schema,
|
||||
)
|
||||
|
||||
|
||||
def _valid_document() -> dict[str, object]:
|
||||
return {
|
||||
"status": "OK",
|
||||
"destination": "ohlc.event",
|
||||
"payload": {
|
||||
"symbol": "BTC/USD_LEVERAGE",
|
||||
"interval": "1m",
|
||||
"type": "classic",
|
||||
"t": 1784224740000,
|
||||
"o": 63992.0,
|
||||
"h": 64032.55,
|
||||
"l": 63984.0,
|
||||
"c": 64032.55,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def test_validate_websocket_ohlc_schema_returns_immutable_document() -> None:
|
||||
result = validate_dzengi_websocket_ohlc_schema(
|
||||
_valid_document()
|
||||
)
|
||||
|
||||
assert isinstance(result, ValidatedWebSocketOhlcDocument)
|
||||
assert isinstance(result.payload, MappingProxyType)
|
||||
|
||||
assert result.status == "OK"
|
||||
assert result.destination == "ohlc.event"
|
||||
assert result.correlation_id is None
|
||||
|
||||
assert result.payload == {
|
||||
"symbol": "BTC/USD_LEVERAGE",
|
||||
"interval": "1m",
|
||||
"type": "classic",
|
||||
"t": 1784224740000,
|
||||
"o": 63992.0,
|
||||
"h": 64032.55,
|
||||
"l": 63984.0,
|
||||
"c": 64032.55,
|
||||
}
|
||||
|
||||
|
||||
def test_validate_websocket_ohlc_schema_preserves_correlation_id() -> None:
|
||||
document = _valid_document()
|
||||
document["correlationId"] = "correlation-1"
|
||||
|
||||
result = validate_dzengi_websocket_ohlc_schema(document)
|
||||
|
||||
assert result.correlation_id == "correlation-1"
|
||||
|
||||
|
||||
def test_validate_websocket_ohlc_schema_copies_payload() -> None:
|
||||
document = _valid_document()
|
||||
payload = document["payload"]
|
||||
|
||||
assert isinstance(payload, dict)
|
||||
|
||||
result = validate_dzengi_websocket_ohlc_schema(document)
|
||||
|
||||
payload["c"] = 1.0
|
||||
|
||||
assert result.payload["c"] == 64032.55
|
||||
|
||||
|
||||
def test_validate_websocket_ohlc_schema_rejects_non_mapping_root() -> None:
|
||||
with pytest.raises(
|
||||
CandleWebSocketSchemaError,
|
||||
match=r"\$ должен быть JSON-объектом",
|
||||
):
|
||||
validate_dzengi_websocket_ohlc_schema([])
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"field_name",
|
||||
[
|
||||
"status",
|
||||
"destination",
|
||||
"payload",
|
||||
],
|
||||
)
|
||||
def test_validate_websocket_ohlc_schema_rejects_missing_root_field(
|
||||
field_name: str,
|
||||
) -> None:
|
||||
document = _valid_document()
|
||||
del document[field_name]
|
||||
|
||||
with pytest.raises(
|
||||
CandleWebSocketSchemaError,
|
||||
match=rf"\$\.{field_name} отсутствует",
|
||||
):
|
||||
validate_dzengi_websocket_ohlc_schema(document)
|
||||
|
||||
|
||||
def test_validate_websocket_ohlc_schema_rejects_non_mapping_payload() -> None:
|
||||
document = _valid_document()
|
||||
document["payload"] = []
|
||||
|
||||
with pytest.raises(
|
||||
CandleWebSocketSchemaError,
|
||||
match=r"\$\.payload должен быть JSON-объектом",
|
||||
):
|
||||
validate_dzengi_websocket_ohlc_schema(document)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"field_name",
|
||||
[
|
||||
"symbol",
|
||||
"interval",
|
||||
"type",
|
||||
"t",
|
||||
"o",
|
||||
"h",
|
||||
"l",
|
||||
"c",
|
||||
],
|
||||
)
|
||||
def test_validate_websocket_ohlc_schema_rejects_missing_payload_field(
|
||||
field_name: str,
|
||||
) -> None:
|
||||
document = _valid_document()
|
||||
payload = document["payload"]
|
||||
|
||||
assert isinstance(payload, dict)
|
||||
|
||||
del payload[field_name]
|
||||
|
||||
with pytest.raises(
|
||||
CandleWebSocketSchemaError,
|
||||
match=rf"обязательные поля WebSocket OHLC: {field_name}",
|
||||
):
|
||||
validate_dzengi_websocket_ohlc_schema(document)
|
||||
|
||||
|
||||
def test_validate_websocket_ohlc_schema_reports_all_missing_fields() -> None:
|
||||
document = _valid_document()
|
||||
payload = document["payload"]
|
||||
|
||||
assert isinstance(payload, dict)
|
||||
|
||||
del payload["symbol"]
|
||||
del payload["t"]
|
||||
del payload["c"]
|
||||
|
||||
with pytest.raises(
|
||||
CandleWebSocketSchemaError,
|
||||
match=r"symbol, t, c",
|
||||
):
|
||||
validate_dzengi_websocket_ohlc_schema(document)
|
||||
|
||||
|
||||
def test_validate_websocket_ohlc_schema_does_not_validate_values() -> None:
|
||||
document = _valid_document()
|
||||
payload = document["payload"]
|
||||
|
||||
assert isinstance(payload, dict)
|
||||
|
||||
document["status"] = 123
|
||||
document["destination"] = None
|
||||
|
||||
payload["symbol"] = None
|
||||
payload["interval"] = []
|
||||
payload["type"] = "unknown"
|
||||
payload["t"] = -1
|
||||
payload["o"] = "NaN"
|
||||
payload["h"] = object()
|
||||
payload["l"] = False
|
||||
payload["c"] = None
|
||||
|
||||
result = validate_dzengi_websocket_ohlc_schema(document)
|
||||
|
||||
assert result.status == 123
|
||||
assert result.destination is None
|
||||
assert result.payload["type"] == "unknown"
|
||||
assert result.payload["t"] == -1
|
||||
|
||||
|
||||
def test_validate_websocket_ohlc_schema_rejects_non_string_root_key() -> None:
|
||||
document = _valid_document()
|
||||
document[1] = "invalid" # type: ignore[index]
|
||||
|
||||
with pytest.raises(
|
||||
CandleWebSocketSchemaError,
|
||||
match=r"\$ содержит нестроковый ключ",
|
||||
):
|
||||
validate_dzengi_websocket_ohlc_schema(document)
|
||||
|
||||
|
||||
def test_validate_websocket_ohlc_schema_rejects_non_string_payload_key() -> None:
|
||||
document = _valid_document()
|
||||
payload = document["payload"]
|
||||
|
||||
assert isinstance(payload, dict)
|
||||
|
||||
payload[1] = "invalid" # type: ignore[index]
|
||||
|
||||
with pytest.raises(
|
||||
CandleWebSocketSchemaError,
|
||||
match=r"\$\.payload содержит нестроковый ключ",
|
||||
):
|
||||
validate_dzengi_websocket_ohlc_schema(document)
|
||||
Reference in New Issue
Block a user