72 lines
2.2 KiB
Python
72 lines
2.2 KiB
Python
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from django.urls import reverse
|
|
|
|
from apps.accounts.models import OtpPurpose, PhoneOTP, User
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_create_user_rejects_email_only_identity():
|
|
# Phone-first invariant: do not allow creating users without phone_number.
|
|
with pytest.raises(ValueError):
|
|
User.objects.create_user(email="email-only@example.com")
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_register_requires_phone_number(client):
|
|
# Public registration must keep phone as required identifier.
|
|
response = client.post(
|
|
reverse("register"),
|
|
{"email": "new@example.com", "password": "StrongPass123"},
|
|
content_type="application/json",
|
|
)
|
|
|
|
assert response.status_code == 400
|
|
assert "phone_number" in response.json()
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_phone_auth_verify_rejects_verify_purpose_otp(client):
|
|
user = User.objects.create_user(phone_number="+966512345678")
|
|
otp = PhoneOTP.objects.create(
|
|
phone_number=user.phone_number,
|
|
channel="sms",
|
|
purpose=OtpPurpose.VERIFY,
|
|
provider="console",
|
|
code_hash="not-used",
|
|
expires_at=PhoneOTP.expiry_at(),
|
|
)
|
|
|
|
# Purpose boundary: /phone/verify must only accept auth OTP requests.
|
|
with patch("apps.accounts.views.verify_otp", return_value=True):
|
|
response = client.post(
|
|
reverse("phone_auth_verify"),
|
|
{"request_id": str(otp.id), "code": "123456"},
|
|
content_type="application/json",
|
|
)
|
|
|
|
assert response.status_code == 400
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_otp_verify_rejects_auth_purpose_otp(client):
|
|
otp = PhoneOTP.objects.create(
|
|
phone_number="+966512345678",
|
|
channel="sms",
|
|
purpose=OtpPurpose.AUTH,
|
|
provider="console",
|
|
code_hash="not-used",
|
|
expires_at=PhoneOTP.expiry_at(),
|
|
)
|
|
|
|
# Purpose boundary: /otp/verify must only accept verify OTP requests.
|
|
with patch("apps.accounts.views.verify_otp", return_value=True):
|
|
response = client.post(
|
|
reverse("otp_verify"),
|
|
{"request_id": str(otp.id), "code": "123456"},
|
|
content_type="application/json",
|
|
)
|
|
|
|
assert response.status_code == 400
|