Switch FX rates to Frankfurter

This commit is contained in:
Edward Betts 2026-06-20 17:40:12 +01:00
parent a369c44ae9
commit fc82cf280a
2 changed files with 184 additions and 12 deletions

View file

@ -19,7 +19,7 @@ class TestReadCachedRates:
assert result == {}
def test_read_cached_rates_valid_file(self) -> None:
"""Test reading valid cached rates file."""
"""Test reading valid exchangerate.host cached rates file."""
currencies = ["USD", "EUR", "JPY"]
data = {
"quotes": {
@ -46,6 +46,37 @@ class TestReadCachedRates:
finally:
os.unlink(filepath)
def test_read_cached_rates_frankfurter_file(self) -> None:
"""Test reading valid Frankfurter cached rates file."""
currencies = ["USD", "EUR", "JPY"]
data = [
{"date": "2026-06-20", "base": "GBP", "quote": "USD", "rate": 1.25},
{"date": "2026-06-20", "base": "GBP", "quote": "EUR", "rate": 1.15},
{"date": "2026-06-20", "base": "GBP", "quote": "JPY", "rate": 150.0},
{
"date": "2026-06-20",
"base": "GBP",
"quote": "CAD",
"rate": 1.70,
}, # Not requested
]
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
json.dump(data, f)
filepath = f.name
try:
result = read_cached_rates(filepath, currencies)
assert len(result) == 3
assert result["USD"] == Decimal("1.25")
assert result["EUR"] == Decimal("1.15")
assert result["JPY"] == Decimal("150.0")
assert "CAD" not in result # Not requested
finally:
os.unlink(filepath)
def test_read_cached_rates_missing_currencies(self) -> None:
"""Test with some currencies missing from data."""
currencies = ["USD", "EUR", "CHF"] # CHF not in data
@ -158,8 +189,8 @@ class TestReadCachedRates:
os.unlink(filepath)
def test_get_rates_uses_older_valid_cache_when_latest_attempt_is_usage_limit() -> None:
"""A usage-limit API response should not replace usable cached rates."""
def test_get_rates_ignores_old_usage_limit_attempt_when_using_frankfurter() -> None:
"""An old provider usage-limit response should not block Frankfurter refreshes."""
with tempfile.TemporaryDirectory() as temp_dir:
fx_dir = os.path.join(temp_dir, "fx")
os.mkdir(fx_dir)
@ -200,8 +231,31 @@ def test_get_rates_uses_older_valid_cache_when_latest_attempt_is_usage_limit() -
) as mock_client:
mock_datetime.now.return_value = datetime(2026, 6, 20, 12, 35)
mock_datetime.strptime.side_effect = datetime.strptime
mock_response = (
mock_client.return_value.__enter__.return_value.get.return_value
)
mock_response.text = json.dumps(
[
{
"date": "2026-06-20",
"base": "GBP",
"quote": "EUR",
"rate": 1.16,
},
{
"date": "2026-06-20",
"base": "GBP",
"quote": "USD",
"rate": 1.26,
},
]
)
result = get_rates(config)
assert result == {"USD": Decimal("1.25"), "EUR": Decimal("1.15")}
mock_client.assert_not_called()
assert result == {"USD": Decimal("1.26"), "EUR": Decimal("1.16")}
mock_client.return_value.__enter__.return_value.get.assert_called_once_with(
"https://api.frankfurter.dev/v2/rates",
params={"base": "GBP", "quotes": "EUR,USD"},
timeout=10,
)