flexigo-support-bot / tests /test_verification.py
victor34593993's picture
do it all: write scopes + lockout fix + product-image backfill endpoint
90bea9c verified
Raw
History Blame Contribute Delete
2.88 kB
from __future__ import annotations
from datetime import UTC, datetime, timedelta
from app.models import ChatSession
from app.verification import is_locked, mark_trusted, verify
ORDERS = [
{
"email": "a@b.c",
"name": "#1001",
"zip": "08480",
"customer_name": "Ana García",
"phone": "600111222",
}
]
NOW = datetime(2026, 6, 9, tzinfo=UTC)
def test_verify_success_with_order_number():
s = ChatSession()
r = verify(s, "A@B.C", ORDERS, order_number="1001", now=NOW)
assert r.ok is True
assert r.reason == "verified"
assert r.matched["name"] == "#1001"
assert s.verified is True
def test_verify_success_with_postal_code():
s = ChatSession()
r = verify(s, "a@b.c", ORDERS, zip_code="08480", now=NOW)
assert r.ok is True # email + postal code is enough (no order number needed)
def test_verify_success_with_name():
s = ChatSession()
r = verify(s, "a@b.c", ORDERS, name="ana garcia", now=NOW)
assert r.ok is True
def test_email_alone_asks_for_second_factor_no_attempt():
s = ChatSession()
r = verify(s, "a@b.c", ORDERS, now=NOW)
assert r.ok is False
assert r.reason == "need_info"
assert (s.verify_attempts or 0) == 0 # not counted as a failed attempt
def test_wrong_secondary_is_generic_and_counts():
s = ChatSession()
r = verify(s, "a@b.c", ORDERS, zip_code="99999", now=NOW, max_attempts=3)
assert r.ok is False
assert r.reason == "not_found"
assert s.verify_attempts == 1
def test_lockout_after_max_attempts():
s = ChatSession()
verify(s, "a@b.c", ORDERS, order_number="9999", now=NOW, max_attempts=2)
r2 = verify(s, "a@b.c", ORDERS, order_number="9999", now=NOW, max_attempts=2)
assert r2.locked is True
assert is_locked(s, NOW) is True
assert is_locked(s, NOW + timedelta(seconds=901)) is False
def test_locked_session_short_circuits():
s = ChatSession()
s.locked_until = NOW + timedelta(seconds=500)
r = verify(s, "a@b.c", ORDERS, order_number="1001", now=NOW)
assert r.locked is True
def test_mark_trusted():
s = ChatSession()
r = mark_trusted(s)
assert r.ok is True and r.reason == "trusted" and s.verified is True
def test_mark_trusted_does_not_clear_order_lockout():
"""A logged-in customer must not reset the order-verification brute-force lockout
(else they could keep guessing other people's orders every turn)."""
from datetime import UTC, datetime, timedelta
from app.models import ChatSession
from app.verification import mark_trusted
s = ChatSession(verify_attempts=4, locked_until=datetime.now(UTC) + timedelta(minutes=10))
mark_trusted(s)
assert s.verified is True # recorded as trusted
assert s.verify_attempts == 4 # lockout counter untouched
assert s.locked_until is not None # still locked