| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273 |
- """Every client-settable notification provider column must reach the API (#2945).
- The defect this pins is not a wrong value, it is a field that exists everywhere
- except the modules a toggle has to cross. `on_stock_reorder_alert` and
- `on_stock_break_alert` had model columns, service producers, templates, UI
- toggles and a frontend test asserting the PATCH — and no schema field, so
- Pydantic dropped them, the PATCH answered 200, and nothing was written. #1184
- introduced that gap and every layer it did touch worked, which is why it went
- unnoticed for months.
- These are structural checks of structural facts: a column that is absent from a
- schema cannot be sent at all, whatever the routes do with it afterwards. The
- behaviour behind them — create, both read routes and PATCH, over the same
- derived column list — is covered through the API in
- `backend/tests/integration/test_notifications_api.py`.
- The two schemas here are the whole of it. The update route needs nothing
- beyond `NotificationProviderUpdate`, because it applies changes with a generic
- `model_dump(exclude_unset=True)` + `setattr` loop rather than a third
- hand-maintained map: once the field survives the schema, it is written.
- """
- from __future__ import annotations
- import pytest
- from backend.app.models.notification import NotificationProvider
- from backend.app.schemas.notification import (
- NotificationProviderCreate,
- NotificationProviderUpdate,
- )
- from backend.tests._fixtures.notification_toggles import (
- EVENT_TOGGLE_COLUMNS,
- SETTABLE_COLUMNS,
- TOGGLE_TARGET,
- )
- def test_there_are_event_columns_to_check() -> None:
- """Guard the guard: an empty enumeration would make every test below vacuous."""
- assert len(EVENT_TOGGLE_COLUMNS) > 20
- def test_the_targets_cover_both_directions() -> None:
- """Guard the other guard, the one the integration round-trips lean on.
- ``TOGGLE_TARGET`` exists so a test drives each toggle to whatever its
- default is not. If every column defaulted the same way -- or if the default
- lookup quietly started returning one constant -- the targets would collapse
- to a single value and the round-trips would be answered by the default again
- without anything failing. Both values have to appear.
- """
- assert set(TOGGLE_TARGET.values()) == {True, False}
- @pytest.mark.parametrize("column", EVENT_TOGGLE_COLUMNS)
- def test_every_event_column_has_a_python_default(column: str) -> None:
- """``TOGGLE_TARGET`` derives each target from the Python-side default, so a
- toggle that only has a ``server_default`` would get the wrong target and
- its round trip would pass on the default alone. Fail here instead."""
- assert NotificationProvider.__table__.columns[column].default is not None
- @pytest.mark.parametrize("column", SETTABLE_COLUMNS)
- def test_every_settable_column_is_settable_on_create(column: str) -> None:
- """Absent from the Create schema, the field is silently dropped from the POST."""
- assert column in NotificationProviderCreate.model_fields
- @pytest.mark.parametrize("column", SETTABLE_COLUMNS)
- def test_every_settable_column_is_settable_on_update(column: str) -> None:
- """This is the one the report hit: the PATCH succeeds and writes nothing."""
- assert column in NotificationProviderUpdate.model_fields
|