mirror of
https://github.com/shawnkim1997/All-in-one-Financial-Analysis.git
synced 2026-08-16 11:58:07 +00:00
85 lines
2.4 KiB
Python
85 lines
2.4 KiB
Python
"""Unit tests for the v2 Data Gateway foundation."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import asyncio
|
|
|
|
import pytest
|
|
|
|
from server.core.cache import CachedGateway
|
|
from server.core.chained_gateway import ChainedGateway
|
|
from server.core.data_gateway import Quote
|
|
from server.core.provider_metrics import provider_metrics
|
|
from server.core.providers.base import BaseProvider, DataUnavailable, ProviderError
|
|
|
|
|
|
class FailingProvider(BaseProvider):
|
|
name = "failing"
|
|
|
|
async def quote(self, symbol: str) -> Quote:
|
|
raise ProviderError("boom")
|
|
|
|
|
|
class CountingProvider(BaseProvider):
|
|
name = "counting"
|
|
|
|
def __init__(self) -> None:
|
|
self.calls = 0
|
|
|
|
async def quote(self, symbol: str) -> Quote:
|
|
self.calls += 1
|
|
return Quote(symbol=symbol.upper(), price=123.45, currency="USD", source=self.name)
|
|
|
|
|
|
class ExplodingProvider(BaseProvider):
|
|
name = "exploding"
|
|
|
|
async def quote(self, symbol: str) -> Quote:
|
|
raise RuntimeError("sdk timeout")
|
|
|
|
|
|
def test_chained_gateway_falls_back_to_next_provider() -> None:
|
|
provider_metrics.clear()
|
|
gateway = ChainedGateway([FailingProvider(), CountingProvider()])
|
|
|
|
quote = asyncio.run(gateway.quote("aapl"))
|
|
|
|
assert quote.symbol == "AAPL"
|
|
assert quote.price == 123.45
|
|
assert quote.source == "counting"
|
|
rows = provider_metrics.snapshot()
|
|
assert {(row.provider, row.method, row.attempts, row.successes, row.failures) for row in rows} == {
|
|
("counting", "quote", 1, 1, 0),
|
|
("failing", "quote", 1, 0, 1),
|
|
}
|
|
|
|
|
|
def test_chained_gateway_raises_after_all_providers_fail() -> None:
|
|
gateway = ChainedGateway([FailingProvider()])
|
|
|
|
with pytest.raises(DataUnavailable):
|
|
asyncio.run(gateway.quote("AAPL"))
|
|
|
|
|
|
def test_chained_gateway_falls_back_after_unexpected_provider_exception() -> None:
|
|
provider_metrics.clear()
|
|
gateway = ChainedGateway([ExplodingProvider(), CountingProvider()])
|
|
|
|
quote = asyncio.run(gateway.quote("AAPL"))
|
|
|
|
assert quote.price == 123.45
|
|
rows = provider_metrics.snapshot()
|
|
assert any(row.provider == "exploding" and row.failures == 1 for row in rows)
|
|
|
|
|
|
def test_cached_gateway_reuses_quote_result() -> None:
|
|
provider_metrics.clear()
|
|
provider = CountingProvider()
|
|
gateway = CachedGateway(ChainedGateway([provider]))
|
|
|
|
first = asyncio.run(gateway.quote("AAPL"))
|
|
second = asyncio.run(gateway.quote("aapl"))
|
|
|
|
assert first is second
|
|
assert provider.calls == 1
|