dodil/erp-brick-time-off

DODIL ERP brick: time off

tests/test_statement_budget.py

"""Statement budgets: every statement is a round trip (100-300 ms on the live pg wire), so a request's statements must not grow with the days it
covers or with unrelated people's rows. Counted at the engine, one request at a time (erp_platform.testing.count_statements)."""
import pytest
from conftest import EMPLOYEE, MANAGER, api, approve, balance, decided, get, must, request
from erp_platform.testing import count_statements
from test_invariants import seed_others


@pytest.fixture
def counted(engine):
    return lambda: count_statements(engine)


def _show(label, c):
    print(f"BUDGET {label}: statements={c.statements} round_trips={c.round_trips}")


def test_asking_does_not_grow_with_the_days_asked_for(counted):
    with counted() as two:
        request("2026-11-09", "2026-11-10")                                    # 2 working days
    with counted() as twenty:
        request("2026-11-16", "2026-12-11")                                    # 20 working days
    _show("request (2 days)", two)
    _show("request (20 days)", twenty)
    assert twenty.statements == two.statements and two.statements <= 16, (two.statements, twenty.statements)


def test_reading_a_balance_and_a_request_does_not_grow_with_the_days_booked(counted):
    short = decided("2026-11-09", "2026-11-10")["request_id"]
    long = decided("2026-11-16", "2026-12-11")["request_id"]
    with counted() as few:
        get(short)
    with counted() as many:
        get(long)
    _show("get request (2 days)", few)
    _show("get request (20 days)", many)
    assert many.statements == few.statements and few.statements <= 4, (few.statements, many.statements)
    with counted() as bal:
        balance()
    _show("balance (22 days booked)", bal)
    assert bal.statements <= 8


def test_approving_does_not_grow_with_the_days(counted):
    a, b = request("2026-11-09", "2026-11-10")["request_id"], request("2026-11-16", "2026-12-11")["request_id"]
    with counted() as few:
        must(approve(a))
    with counted() as many:
        must(approve(b))
    _show("approve (2 days)", few)
    _show("approve (20 days)", many)
    assert many.statements == few.statements and few.statements <= 12, (few.statements, many.statements)


def test_cancelling_does_not_grow_with_the_days(counted):
    a, b = decided("2026-11-09", "2026-11-10")["request_id"], decided("2026-11-16", "2026-12-11")["request_id"]
    with counted() as few:
        must(api("POST", f"/leave-requests/{a}/cancel", MANAGER, {"reason": "x"}))
    with counted() as many:
        must(api("POST", f"/leave-requests/{b}/cancel", MANAGER, {"reason": "x"}))
    _show("cancel (2 days)", few)
    _show("cancel (20 days)", many)
    assert many.statements == few.statements and few.statements <= 12, (few.statements, many.statements)


def test_the_hr_calls_do_not_grow_with_the_days_either(hr):
    request("2026-11-09", "2026-11-10")
    short = len(hr.calls)
    request("2026-11-16", "2026-12-11")
    assert len(hr.calls) - short == short                                         # the same four calls: person, employment, one pattern, manager... for 20 days


def test_nothing_grows_with_fifty_unrelated_people(counted):
    mine = decided("2026-11-09", "2026-11-10")["request_id"]
    with counted() as few:
        balance()
        must(api("GET", "/leave-requests", EMPLOYEE))
        must(api("GET", "/leave-requests", MANAGER, {"scope": "waiting"}))
        get(mine)
    seed_others(50)
    with counted() as many:
        balance()
        must(api("GET", "/leave-requests", EMPLOYEE))
        must(api("GET", "/leave-requests", MANAGER, {"scope": "waiting"}))
        get(mine)
    _show("balance + lists + get (1 person around)", few)
    _show("balance + lists + get (51 people around)", many)
    assert many.statements == few.statements and few.statements <= 20, (few.statements, many.statements)


def test_asking_approving_and_cancelling_do_not_grow_with_fifty_unrelated_people(counted):
    seed_others(2)
    with counted() as few:
        rid = request("2026-11-09", "2026-11-10")["request_id"]
        must(approve(rid))
        must(api("POST", f"/leave-requests/{rid}/cancel", MANAGER, {"reason": "x"}))
    seed_others(50, first=2)
    with counted() as many:
        rid = request("2026-11-09", "2026-11-10")["request_id"]
        must(approve(rid))
        must(api("POST", f"/leave-requests/{rid}/cancel", MANAGER, {"reason": "x"}))
    _show("ask+approve+cancel (3 people around)", few)
    _show("ask+approve+cancel (52 people around)", many)
    assert many.statements == few.statements, (few.statements, many.statements)