"""The saved proxy hop count against a real database. What only a real database shows: the count is read back after a save, saving leaves exactly one copy however many admins there are, saving None removes it, and a saved count reaches `client_ip()` through the worker's cache. """ import pytest from quart import Quart from sqlalchemy import select from grimoire import proxy from grimoire.config import Config from grimoire.models import async_session from grimoire.models.setting import Setting from grimoire.proxy import client_ip from grimoire.services import proxy_settings from tests.helpers import ensure_user pytestmark = [pytest.mark.integration, pytest.mark.usefixtures("_dispose_engine")] async def _copies() -> list[Setting]: async with async_session() as s: return list((await s.execute( select(Setting).where(Setting.key == proxy_settings.SETTING_KEY) )).scalars().all()) @pytest.fixture async def two_admins(): async with async_session() as s: first = await ensure_user(s, "proxy_hops_admin_a", role="admin") second = await ensure_user(s, "proxy_hops_admin_b", role="admin") await s.commit() ids = (first.id, second.id) yield ids await proxy_settings.save_hops(None) proxy.set_saved_hops(None) async def test_a_saved_count_reads_back_and_leaves_one_copy(two_admins): # A stale copy on the second admin, as an older write path could leave. async with async_session() as s: s.add(Setting(user_id=two_admins[1], key=proxy_settings.SETTING_KEY, value="4")) await s.commit() await proxy_settings.save_hops(2) assert await proxy_settings.saved_hops() == 2 copies = await _copies() assert len(copies) == 1 and copies[0].value == "2" async def test_saving_none_removes_the_count(two_admins): await proxy_settings.save_hops(3) await proxy_settings.save_hops(None) assert await proxy_settings.saved_hops() is None assert await _copies() == [] assert proxy.saved_hops_in_force() is None async def test_a_saved_count_reaches_the_client_address(two_admins, monkeypatch): monkeypatch.setattr(Config, "TRUSTED_PROXY_HOPS", 1) await proxy_settings.save_hops(2) proxy.set_saved_hops(None) # as in another worker, before its refresh await proxy_settings.refresh() app = Quart(__name__) headers = {"Remote-Addr": "10.0.0.5", "X-Forwarded-For": "203.0.113.7, 172.70.1.1"} async with app.test_request_context("/", headers=headers): assert client_ip() == "203.0.113.7"