Files
JQC_multi_tenant/tests/test_followup_ownership.py

132 lines
4.8 KiB
Python

"""
tests/test_followup_ownership.py
---------------------------------
phase56 — a follow-up has exactly ONE owner, and every surface must agree.
`Inspection.follow_up_owner` (the loaded-row property) and
`Inspection.follow_up_owned_by()` (the SQL predicate) are two expressions of
the same rule: the assignee when one is set, the inspection's own inspector
otherwise. They are declared next to each other because they must not drift.
What these guard
----------------
The predicate's two arms are mutually exclusive ON PURPOSE. Drop the
`is_(None)` from the second arm and the original inspector keeps matching a
follow-up that was handed to somebody else — two people turn up to do the same
re-inspection, and nothing errors.
The three query surfaces (mobile list filter, web dashboard card, iPad stats
KPI) each used to express ownership by hand, and three of them tested
AUTHORSHIP: an assignee saw the work in their list while both dashboards read
0. These tests pin the predicate itself; the surfaces now call it rather than
re-deriving it.
"""
import pytest
@pytest.fixture
def client(app):
with app.app_context():
from app import db
db.drop_all()
db.create_all()
yield app.test_client()
db.session.remove()
def _user(username, role='inspector'):
from app import db
from app.models.user import User
u = User(username=username, full_name=username.title(), role=role,
email=f'{username}@example.com', active=True, password_set=True)
u.set_password('pw-correct1')
db.session.add(u)
db.session.commit()
return u
def _inspection(inspector, assignee=None, follow_up=True):
from app import db
from app.models.facility import Facility
from app.models.inspection import Inspection, InspectionTemplate
fac = Facility.query.first()
if fac is None:
fac = Facility(name='Main Office', active=True)
db.session.add(fac)
db.session.commit()
tmpl = InspectionTemplate.query.first()
if tmpl is None:
tmpl = InspectionTemplate(name='Restroom Check', active=True, form_schema=[])
db.session.add(tmpl)
db.session.commit()
insp = Inspection(template_id=tmpl.id, facility_id=fac.id,
inspector_id=inspector.id, status='completed',
follow_up_required=follow_up,
follow_up_assigned_to=(assignee.id if assignee else None))
db.session.add(insp)
db.session.commit()
return insp
def _owned_ids(user):
from app.models.inspection import Inspection
return sorted(i.id for i in Inspection.query
.filter(Inspection.follow_up_owned_by(user.id)).all())
# ── the property ─────────────────────────────────────────────────────────────
def test_owner_is_the_inspector_when_unassigned(client):
ivy = _user('ivy')
insp = _inspection(ivy)
assert insp.follow_up_owner.id == ivy.id
def test_owner_is_the_assignee_when_assigned(client):
ivy, sam = _user('ivy'), _user('sam')
insp = _inspection(ivy, assignee=sam)
assert insp.follow_up_owner.id == sam.id
# ── the SQL predicate ────────────────────────────────────────────────────────
def test_predicate_matches_unassigned_own_work(client):
ivy = _user('ivy')
insp = _inspection(ivy)
assert _owned_ids(ivy) == [insp.id]
def test_predicate_matches_work_handed_to_me(client):
ivy, sam = _user('ivy'), _user('sam')
insp = _inspection(ivy, assignee=sam)
assert _owned_ids(sam) == [insp.id]
def test_predicate_releases_the_original_inspector_once_assigned(client):
"""The `is_(None)` on the second arm. Without it Ivy still matches, and two
people turn up to do the same re-inspection."""
ivy, sam = _user('ivy'), _user('sam')
_inspection(ivy, assignee=sam)
assert _owned_ids(ivy) == []
def test_every_row_has_exactly_one_owner(client):
"""The property and the predicate must partition the rows, not overlap."""
from app.models.inspection import Inspection
ivy, sam, zoe = _user('ivy'), _user('sam'), _user('zoe')
_inspection(ivy) # unassigned, Ivy's
_inspection(ivy, assignee=sam) # Ivy's work, Sam's follow-up
_inspection(sam, assignee=sam) # Sam's work, explicitly Sam's
_inspection(zoe) # unassigned, Zoe's
everyone = [ivy, sam, zoe]
for insp in Inspection.query.all():
owners = [u.id for u in everyone if insp.id in _owned_ids(u)]
assert owners == [insp.follow_up_owner.id], (
f'inspection {insp.id}: predicate says {owners}, '
f'property says {insp.follow_up_owner.id}')