phase 14-15: docker build validation and helm deployment
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
"""Tests for the Query API app structure and helper functions."""
|
||||
import json
|
||||
from datetime import datetime, timezone
|
||||
|
||||
import pytest
|
||||
|
||||
from services.api.app import _parse_jsonb, _row_to_dict, app
|
||||
|
||||
|
||||
# --- _parse_jsonb ---
|
||||
|
||||
def test_parse_jsonb_dict():
|
||||
assert _parse_jsonb({"a": 1}) == {"a": 1}
|
||||
|
||||
|
||||
def test_parse_jsonb_list():
|
||||
assert _parse_jsonb([1, 2]) == [1, 2]
|
||||
|
||||
|
||||
def test_parse_jsonb_string():
|
||||
assert _parse_jsonb('{"x": 1}') == {"x": 1}
|
||||
|
||||
|
||||
def test_parse_jsonb_list_string():
|
||||
assert _parse_jsonb('["a", "b"]') == ["a", "b"]
|
||||
|
||||
|
||||
def test_parse_jsonb_none():
|
||||
assert _parse_jsonb(None) is None
|
||||
|
||||
|
||||
def test_parse_jsonb_invalid_string():
|
||||
assert _parse_jsonb("not json") == "not json"
|
||||
|
||||
|
||||
# --- _row_to_dict ---
|
||||
|
||||
class FakeRecord(dict):
|
||||
"""Mimics asyncpg.Record enough for _row_to_dict."""
|
||||
def items(self):
|
||||
return super().items()
|
||||
|
||||
|
||||
def test_row_to_dict_converts_datetime():
|
||||
dt = datetime(2026, 4, 11, 12, 0, 0, tzinfo=timezone.utc)
|
||||
row = FakeRecord({"created_at": dt, "name": "test"})
|
||||
result = _row_to_dict(row)
|
||||
assert result["created_at"] == dt.isoformat()
|
||||
assert result["name"] == "test"
|
||||
|
||||
|
||||
def test_row_to_dict_passes_primitives():
|
||||
row = FakeRecord({"count": 42, "active": True, "label": "ok", "val": None})
|
||||
result = _row_to_dict(row)
|
||||
assert result == {"count": 42, "active": True, "label": "ok", "val": None}
|
||||
|
||||
|
||||
# --- App structure ---
|
||||
|
||||
def test_app_has_expected_routes():
|
||||
paths = [route.path for route in app.routes]
|
||||
assert "/health" in paths
|
||||
assert "/api/companies" in paths
|
||||
assert "/api/companies/{company_id}" in paths
|
||||
assert "/api/documents" in paths
|
||||
assert "/api/documents/{document_id}" in paths
|
||||
assert "/api/trends" in paths
|
||||
assert "/api/trends/{trend_id}" in paths
|
||||
assert "/api/trends/{trend_id}/evidence" in paths
|
||||
assert "/api/recommendations" in paths
|
||||
assert "/api/recommendations/{recommendation_id}" in paths
|
||||
assert "/api/recommendations/{recommendation_id}/evidence" in paths
|
||||
assert "/api/orders" in paths
|
||||
assert "/api/orders/{order_id}" in paths
|
||||
assert "/api/positions" in paths
|
||||
assert "/api/audit/{entity_type}/{entity_id}" in paths
|
||||
|
||||
|
||||
def test_app_has_admin_routes():
|
||||
paths = [route.path for route in app.routes]
|
||||
# Source health
|
||||
assert "/api/admin/sources/health" in paths
|
||||
assert "/api/admin/sources/{source_id}/runs" in paths
|
||||
assert "/api/admin/sources/{source_id}/toggle" in paths
|
||||
assert "/api/admin/sources/{source_id}/credibility" in paths
|
||||
# Symbol configs
|
||||
assert "/api/admin/companies/{company_id}/toggle" in paths
|
||||
assert "/api/admin/companies/{company_id}/sector" in paths
|
||||
assert "/api/admin/companies/coverage" in paths
|
||||
# Trading mode
|
||||
assert "/api/admin/trading/config" in paths
|
||||
assert "/api/admin/trading/mode" in paths
|
||||
assert "/api/admin/trading/approvals" in paths
|
||||
assert "/api/admin/trading/approvals/{approval_id}" in paths
|
||||
assert "/api/admin/trading/lockouts" in paths
|
||||
|
||||
|
||||
def test_app_has_ops_dashboard_routes():
|
||||
paths = [route.path for route in app.routes]
|
||||
assert "/api/ops/ingestion/throughput" in paths
|
||||
assert "/api/ops/ingestion/summary" in paths
|
||||
assert "/api/ops/model/failures" in paths
|
||||
assert "/api/ops/model/performance" in paths
|
||||
assert "/api/ops/pipeline/health" in paths
|
||||
assert "/api/ops/sources/coverage-gaps" in paths
|
||||
Reference in New Issue
Block a user