mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-09-30 03:01:21 +02:00
67 lines
3.1 KiB
Python
67 lines
3.1 KiB
Python
"""The per-event notification toggles, derived from the model's own columns (#2945).
|
|
|
|
A hardcoded list only covers the toggles someone remembered to add to it, so it
|
|
carries the same hazard as the field maps it is meant to police, one layer up.
|
|
Derived, a toggle added tomorrow is exercised the day its column lands.
|
|
|
|
This lives here rather than in either test module because the unit parity checks
|
|
and the integration round-trips need the same two answers, and a derivation
|
|
duplicated across files is a list with extra steps.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from sqlalchemy import Boolean
|
|
from sqlalchemy.sql.schema import Column
|
|
|
|
from backend.app.models.notification import NotificationProvider
|
|
|
|
# The Boolean check is not decoration. An on_* column of some other type would
|
|
# turn `{field: True}` into a 422 and break every test parametrised off this
|
|
# list, in whichever unrelated PR happened to add that column -- and a spurious
|
|
# failure is how a derivation gets edited until it passes.
|
|
_EVENT_TOGGLES: list[Column] = [
|
|
column
|
|
for column in NotificationProvider.__table__.columns
|
|
if column.name.startswith("on_") and isinstance(column.type, Boolean)
|
|
]
|
|
|
|
EVENT_TOGGLE_COLUMNS: list[str] = sorted(column.name for column in _EVENT_TOGGLES)
|
|
|
|
# Every column a client is meant to be able to set. The hazard #2945 describes is
|
|
# per-column -- a field that exists everywhere except one of the maps it has to
|
|
# cross -- and `enabled`, the quiet-hours and digest fields cross the same two
|
|
# maps as the on_* toggles. The prefix is a naming convention, not the boundary.
|
|
# What is left out is what the server owns: the key, the timestamps, and the
|
|
# delivery status it records itself.
|
|
_SERVER_OWNED = {"id", "created_at", "updated_at", "last_success", "last_error", "last_error_at"}
|
|
|
|
SETTABLE_COLUMNS: list[str] = sorted(
|
|
column.name for column in NotificationProvider.__table__.columns if column.name not in _SERVER_OWNED
|
|
)
|
|
|
|
|
|
def _model_default(column: Column) -> bool:
|
|
"""The value a row gets for this column when the caller sends nothing.
|
|
|
|
Reads the Python-side default only. That is exact while every toggle
|
|
declares one, which ``test_every_event_column_has_a_python_default`` holds
|
|
in place: a column added with only a ``server_default`` would read as False
|
|
here, get a target of True, and for a server-default-true column the round
|
|
trip would send True and assert True -- vacuous again, and silently.
|
|
"""
|
|
if column.default is None:
|
|
return False
|
|
return bool(column.default.arg)
|
|
|
|
|
|
# The value each toggle has to be driven to for the assertion to mean anything.
|
|
#
|
|
# Nine of these columns default to True on the model and on the response schema,
|
|
# so a test that sends True and asserts True is answered by the default alone:
|
|
# a field dropped by a hand-maintained map still reads back True, and the
|
|
# mutation that would prove the map is load-bearing survives. Driving each
|
|
# toggle to whatever its default is not makes the round trip the only thing that
|
|
# can supply the answer.
|
|
TOGGLE_TARGET: dict[str, bool] = {column.name: not _model_default(column) for column in _EVENT_TOGGLES}
|