- Fix 71 invalid-syntax files (class-body newline-broken assignments) - Add from/None chain to 307 B904 raise-without-from sites - Add B008 ignore to ruff.toml (already in pyproject.toml) - Noqa F401 on __init__.py re-exports (137 sites) - Noqa E402 on deferred imports (63 sites) - Bulk-add stdlib/FastAPI/project imports for F821 (127 sites) - Replace ×→x, –→-, …→... in docstrings (4093 chars) - Manual refactor of 5 SIM103/SIM116 patterns Tests: 791 passed (66 deselected due to pre-existing Redis issues in test_rag.py) Co-authored-by: opencode <opencode@rugmunch.io>
86 lines
2.6 KiB
Python
86 lines
2.6 KiB
Python
"""Integration tests for DataBus provider chains.
|
|
|
|
Tests cache layers, circuit breakers, provider fallbacks.
|
|
Uses mocked external APIs to avoid real API calls.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
|
|
class TestDataBusCache:
|
|
"""Test L1 (memory) and L2 (Redis) cache layers."""
|
|
|
|
@pytest.mark.integration
|
|
async def test_l1_cache_hit_returns_data(self):
|
|
"""L1 memory cache should return cached data on second fetch."""
|
|
pass # TODO: mock databus.fetch() with cache
|
|
|
|
@pytest.mark.integration
|
|
async def test_l2_redis_fallback_on_l1_miss(self):
|
|
"""L2 Redis should serve when L1 misses."""
|
|
pass
|
|
|
|
@pytest.mark.integration
|
|
async def test_stale_while_revalidate_returns_stale(self):
|
|
"""SWR should return stale data while refreshing in background."""
|
|
pass
|
|
|
|
|
|
class TestCircuitBreakers:
|
|
"""Test provider circuit breakers - 3 failures → open → half-open → closed."""
|
|
|
|
@pytest.mark.integration
|
|
async def test_circuit_opens_after_three_failures(self):
|
|
"""Circuit should open after 3 consecutive provider failures."""
|
|
pass
|
|
|
|
@pytest.mark.integration
|
|
async def test_half_open_allows_one_probe(self):
|
|
"""After timeout, half-open state should allow one probe request."""
|
|
pass
|
|
|
|
@pytest.mark.integration
|
|
async def test_closed_after_successful_probe(self):
|
|
"""Successful probe in half-open should close the circuit."""
|
|
pass
|
|
|
|
|
|
class TestProviderFallback:
|
|
"""Test provider chain fallback - first fails, second succeeds."""
|
|
|
|
@pytest.mark.integration
|
|
async def test_fallback_to_secondary_provider(self):
|
|
"""When primary fails, secondary provider should be tried."""
|
|
pass
|
|
|
|
@pytest.mark.integration
|
|
async def test_all_providers_fail_returns_none(self):
|
|
"""When all providers fail, databus should return None."""
|
|
pass
|
|
|
|
|
|
class TestDataBusSmoke:
|
|
"""Smoke tests for all 78 DataBus provider chains."""
|
|
|
|
CHAINS = [ # noqa: RUF012
|
|
"token_price",
|
|
"market_overview",
|
|
"trending",
|
|
"fear_greed",
|
|
"wallet_labels",
|
|
"entity_intel",
|
|
"scanner",
|
|
"rag_search",
|
|
"wallet_tokens",
|
|
"token_metadata",
|
|
"token_security",
|
|
]
|
|
|
|
@pytest.mark.integration
|
|
@pytest.mark.parametrize("chain", CHAINS)
|
|
async def test_chain_exists_in_providers(self, chain):
|
|
"""Every chain should exist in build_provider_chains()."""
|
|
from app.databus.providers import build_provider_chains
|
|
|
|
chains = build_provider_chains()
|
|
assert chain in chains, f"Chain '{chain}' missing from provider chains"
|