aboutsummaryrefslogtreecommitdiff
path: root/tests/models/thl/test_user.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/models/thl/test_user.py')
-rw-r--r--tests/models/thl/test_user.py141
1 files changed, 58 insertions, 83 deletions
diff --git a/tests/models/thl/test_user.py b/tests/models/thl/test_user.py
index 943ae8e..68b413c 100644
--- a/tests/models/thl/test_user.py
+++ b/tests/models/thl/test_user.py
@@ -1,25 +1,35 @@
+from __future__ import annotations
+
import json
-from datetime import datetime, timedelta, timezone
+from collections.abc import Callable
+from datetime import UTC, datetime, timedelta, timezone
from decimal import Decimal
from random import choice as rand_choice
from random import randint
+from typing import TYPE_CHECKING
from uuid import uuid4
import pytest
from pydantic import ValidationError
+from generalresearch.models.thl.user import User
+
+if TYPE_CHECKING:
+ from generalresearch.managers.thl.ledger_manager.thl_ledger import ThlLedgerManager
+ from generalresearch.managers.thl.userhealth import AuditLogManager
+ from generalresearch.models.thl.product import Product
+ from generalresearch.models.thl.userhealth import AuditLog
+
class TestUserUserID:
def test_valid(self):
- from generalresearch.models.thl.user import User
val = randint(1, 2**30)
user = User(user_id=val)
assert user.user_id == val
def test_type(self):
- from generalresearch.models.thl.user import User
# It will cast str to int
assert User(user_id="1").user_id == 1
@@ -44,7 +54,6 @@ class TestUserUserID:
assert "Input should be a valid integer," in str(cm.value)
def test_zero(self):
- from generalresearch.models.thl.user import User
with pytest.raises(expected_exception=ValidationError) as cm:
User(user_id=0)
@@ -52,7 +61,6 @@ class TestUserUserID:
assert "Input should be greater than 0" in str(cm.value)
def test_negative(self):
- from generalresearch.models.thl.user import User
with pytest.raises(expected_exception=ValidationError) as cm:
User(user_id=-1)
@@ -60,7 +68,6 @@ class TestUserUserID:
assert "Input should be greater than 0" in str(cm.value)
def test_too_big(self):
- from generalresearch.models.thl.user import User
val = 2**31
with pytest.raises(expected_exception=ValidationError) as cm:
@@ -69,7 +76,6 @@ class TestUserUserID:
assert "Input should be less than 2147483648" in str(cm.value)
def test_identifiable(self):
- from generalresearch.models.thl.user import User
val = randint(1, 2**30)
user = User(user_id=val)
@@ -80,7 +86,6 @@ class TestUserProductID:
user_id = randint(1, 2**30)
def test_valid(self):
- from generalresearch.models.thl.user import User
product_id = uuid4().hex
@@ -89,7 +94,6 @@ class TestUserProductID:
assert user.product_id == product_id
def test_type(self):
- from generalresearch.models.thl.user import User
with pytest.raises(expected_exception=ValueError) as cm:
User(user_id=self.user_id, product_id=0)
@@ -102,7 +106,6 @@ class TestUserProductID:
assert "Input should be a valid string" in str(cm.value)
def test_empty(self):
- from generalresearch.models.thl.user import User
with pytest.raises(expected_exception=ValueError) as cm:
User(user_id=self.user_id, product_id="")
@@ -110,7 +113,6 @@ class TestUserProductID:
assert "String should have at least 32 characters" in str(cm.value)
def test_invalid_len(self):
- from generalresearch.models.thl.user import User
# Valid uuid4s are 32 char long
product_id = uuid4().hex[:31]
@@ -133,7 +135,6 @@ class TestUserProductID:
assert "String should have at most 32 characters" in str(cm.value)
def test_invalid_uuid(self):
- from generalresearch.models.thl.user import User
# Modify the UUID to break it
product_id = uuid4().hex[:31] + "x"
@@ -144,7 +145,6 @@ class TestUserProductID:
assert "Invalid UUID" in str(cm.value)
def test_invalid_hex_form(self):
- from generalresearch.models.thl.user import User
# Sure not in hex form, but it'll get caught for being the
# wrong length before anything else
@@ -157,7 +157,6 @@ class TestUserProductID:
def test_identifiable(self):
"""Can't create a User with only a product_id because it also
needs to the product_user_id"""
- from generalresearch.models.thl.user import User
product_id = uuid4().hex
with pytest.raises(expected_exception=ValueError) as cm:
@@ -172,10 +171,9 @@ class TestUserProductUserID:
def randomword(self, length: int = 50):
# Raw so nothing is escaped to add additional backslashes
_bpuid_allowed = r"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#$%&()*+,-.:;<=>?@[]^_{|}~"
- return "".join(rand_choice(_bpuid_allowed) for i in range(length))
+ return "".join(rand_choice(_bpuid_allowed) for _ in range(length))
def test_valid(self):
- from generalresearch.models.thl.user import User
product_user_id = uuid4().hex[:12]
user = User(user_id=self.user_id, product_user_id=product_user_id)
@@ -184,7 +182,6 @@ class TestUserProductUserID:
assert user.product_user_id == product_user_id
def test_type(self):
- from generalresearch.models.thl.user import User
with pytest.raises(expected_exception=ValueError) as cm:
User(user_id=self.user_id, product_user_id=0)
@@ -197,12 +194,11 @@ class TestUserProductUserID:
assert "Input should be a valid string" in str(cm.value)
with pytest.raises(ValueError) as cm:
- User(user_id=self.user_id, product_user_id=Decimal("0"))
+ User(user_id=self.user_id, product_user_id=Decimal(0))
assert "1 validation error for User" in str(cm.value)
assert "Input should be a valid string" in str(cm.value)
def test_empty(self):
- from generalresearch.models.thl.user import User
with pytest.raises(expected_exception=ValueError) as cm:
User(user_id=self.user_id, product_user_id="")
@@ -210,7 +206,6 @@ class TestUserProductUserID:
assert "String should have at least 3 characters" in str(cm.value)
def test_invalid_len(self):
- from generalresearch.models.thl.user import User
product_user_id = self.randomword(251)
with pytest.raises(expected_exception=ValueError) as cm:
@@ -225,7 +220,6 @@ class TestUserProductUserID:
assert "String should have at least 3 characters" in str(cm.value)
def test_invalid_chars_space(self):
- from generalresearch.models.thl.user import User
product_user_id = f"{self.randomword(50)} {self.randomword(50)}"
with pytest.raises(expected_exception=ValueError) as cm:
@@ -234,9 +228,8 @@ class TestUserProductUserID:
assert "String cannot contain spaces" in str(cm.value)
def test_invalid_chars_slash(self):
- from generalresearch.models.thl.user import User
- product_user_id = f"{self.randomword(50)}\{self.randomword(50)}"
+ product_user_id = rf"{self.randomword(50)}\{self.randomword(50)}"
with pytest.raises(expected_exception=ValueError) as cm:
User(user_id=self.user_id, product_user_id=product_user_id)
assert "1 validation error for User" in str(cm.value)
@@ -253,7 +246,6 @@ class TestUserProductUserID:
I wanted a test that made sure the regex was hit. I do not know
how we want to provide with the level of specific String checks
we do in here for specific error messages."""
- from generalresearch.models.thl.user import User
product_user_id = f"{self.randomword(50)}`{self.randomword(50)}"
with pytest.raises(expected_exception=ValueError) as cm:
@@ -275,7 +267,6 @@ class TestUserProductUserID:
def test_identifiable(self):
"""Can't create a User with only a product_user_id because it also
needs to the product_id"""
- from generalresearch.models.thl.user import User
product_user_id = uuid4().hex
with pytest.raises(ValueError) as cm:
@@ -288,7 +279,6 @@ class TestUserUUID:
user_id = randint(1, 2**30)
def test_valid(self):
- from generalresearch.models.thl.user import User
uuid_pk = uuid4().hex
@@ -297,7 +287,6 @@ class TestUserUUID:
assert user.uuid == uuid_pk
def test_type(self):
- from generalresearch.models.thl.user import User
with pytest.raises(ValueError) as cm:
User(user_id=self.user_id, uuid=0)
@@ -310,12 +299,11 @@ class TestUserUUID:
assert "Input should be a valid string" in str(cm.value)
with pytest.raises(ValueError) as cm:
- User(user_id=self.user_id, uuid=Decimal("0"))
+ User(user_id=self.user_id, uuid=Decimal(0))
assert "1 validation error for User" in str(cm.value)
assert "Input should be a valid string" in str(cm.value)
def test_empty(self):
- from generalresearch.models.thl.user import User
with pytest.raises(ValueError) as cm:
User(user_id=self.user_id, uuid="")
@@ -323,7 +311,6 @@ class TestUserUUID:
assert "String should have at least 32 characters" in str(cm.value)
def test_invalid_len(self):
- from generalresearch.models.thl.user import User
# Valid uuid4s are 32 char long
uuid_pk = uuid4().hex[:31]
@@ -341,7 +328,6 @@ class TestUserUUID:
assert "String should have at most 32 characters" in str(cm.value)
def test_invalid_uuid(self):
- from generalresearch.models.thl.user import User
# Modify the UUID to break it
uuid_pk = uuid4().hex[:31] + "x"
@@ -352,7 +338,6 @@ class TestUserUUID:
assert "Invalid UUID" in str(cm.value)
def test_invalid_hex_form(self):
- from generalresearch.models.thl.user import User
# Sure not in hex form, but it'll get caught for being the
# wrong length before anything else
@@ -369,7 +354,6 @@ class TestUserUUID:
assert "Invalid UUID" in str(cm.value)
def test_identifiable(self):
- from generalresearch.models.thl.user import User
user_uuid = uuid4().hex
user = User(uuid=user_uuid)
@@ -380,33 +364,29 @@ class TestUserCreated:
user_id = randint(1, 2**30)
def test_valid(self):
- from generalresearch.models.thl.user import User
user = User(user_id=self.user_id)
- dt = datetime.now(tz=timezone.utc)
+ dt = datetime.now(tz=UTC)
user.created = dt
assert user.created == dt
def test_tz_naive_throws_init(self):
- from generalresearch.models.thl.user import User
with pytest.raises(ValueError) as cm:
- User(user_id=self.user_id, created=datetime.now(tz=None))
+ User(user_id=self.user_id, created=datetime.now(tz=None)) # noqa
assert "1 validation error for User" in str(cm.value)
assert "Input should have timezone info" in str(cm.value)
def test_tz_naive_throws_setter(self):
- from generalresearch.models.thl.user import User
user = User(user_id=self.user_id)
with pytest.raises(ValueError) as cm:
- user.created = datetime.now(tz=None)
+ user.created = datetime.now(tz=None) # noqa
assert "1 validation error for User" in str(cm.value)
assert "Input should have timezone info" in str(cm.value)
def test_tz_utc(self):
- from generalresearch.models.thl.user import User
with pytest.raises(ValueError) as cm:
User(
@@ -417,20 +397,18 @@ class TestUserCreated:
assert "Timezone is not UTC" in str(cm.value)
def test_not_in_future(self):
- from generalresearch.models.thl.user import User
- the_future = datetime.now(tz=timezone.utc) + timedelta(minutes=1)
+ the_future = datetime.now(tz=UTC) + timedelta(minutes=1)
with pytest.raises(ValueError) as cm:
User(user_id=self.user_id, created=the_future)
assert "1 validation error for User" in str(cm.value)
assert "Input is in the future" in str(cm.value)
def test_after_anno_domini(self):
- from generalresearch.models.thl.user import User
- before_ad = datetime(
- year=2015, month=1, day=1, tzinfo=timezone.utc
- ) + timedelta(minutes=1)
+ before_ad = datetime(year=2015, month=1, day=1, tzinfo=UTC) + timedelta(
+ minutes=1
+ )
with pytest.raises(ValueError) as cm:
User(user_id=self.user_id, created=before_ad)
assert "1 validation error for User" in str(cm.value)
@@ -441,33 +419,29 @@ class TestUserLastSeen:
user_id = randint(1, 2**30)
def test_valid(self):
- from generalresearch.models.thl.user import User
user = User(user_id=self.user_id)
- dt = datetime.now(tz=timezone.utc)
+ dt = datetime.now(tz=UTC)
user.last_seen = dt
assert user.last_seen == dt
def test_tz_naive_throws_init(self):
- from generalresearch.models.thl.user import User
with pytest.raises(ValueError) as cm:
- User(user_id=self.user_id, last_seen=datetime.now(tz=None))
+ User(user_id=self.user_id, last_seen=datetime.now(tz=None)) # noqa
assert "1 validation error for User" in str(cm.value)
assert "Input should have timezone info" in str(cm.value)
def test_tz_naive_throws_setter(self):
- from generalresearch.models.thl.user import User
user = User(user_id=self.user_id)
with pytest.raises(ValueError) as cm:
- user.last_seen = datetime.now(tz=None)
+ user.last_seen = datetime.now(tz=None) # noqa
assert "1 validation error for User" in str(cm.value)
assert "Input should have timezone info" in str(cm.value)
def test_tz_utc(self):
- from generalresearch.models.thl.user import User
with pytest.raises(ValueError) as cm:
User(
@@ -478,20 +452,18 @@ class TestUserLastSeen:
assert "Timezone is not UTC" in str(cm.value)
def test_not_in_future(self):
- from generalresearch.models.thl.user import User
- the_future = datetime.now(tz=timezone.utc) + timedelta(minutes=1)
+ the_future = datetime.now(tz=UTC) + timedelta(minutes=1)
with pytest.raises(ValueError) as cm:
User(user_id=self.user_id, last_seen=the_future)
assert "1 validation error for User" in str(cm.value)
assert "Input is in the future" in str(cm.value)
def test_after_anno_domini(self):
- from generalresearch.models.thl.user import User
- before_ad = datetime(
- year=2015, month=1, day=1, tzinfo=timezone.utc
- ) + timedelta(minutes=1)
+ before_ad = datetime(year=2015, month=1, day=1, tzinfo=UTC) + timedelta(
+ minutes=1
+ )
with pytest.raises(ValueError) as cm:
User(user_id=self.user_id, last_seen=before_ad)
assert "1 validation error for User" in str(cm.value)
@@ -502,7 +474,6 @@ class TestUserBlocked:
user_id = randint(1, 2**30)
def test_valid(self):
- from generalresearch.models.thl.user import User
user = User(user_id=self.user_id, blocked=True)
assert user.blocked
@@ -510,7 +481,6 @@ class TestUserBlocked:
def test_str_casting(self):
"""We don't want any of these to work, and that's why
we set strict=True on the column"""
- from generalresearch.models.thl.user import User
with pytest.raises(ValueError) as cm:
User(user_id=self.user_id, blocked="true")
@@ -547,20 +517,18 @@ class TestUserTiming:
user_id = randint(1, 2**30)
def test_valid(self):
- from generalresearch.models.thl.user import User
- created = datetime.now(tz=timezone.utc) - timedelta(minutes=60)
- last_seen = datetime.now(tz=timezone.utc) - timedelta(minutes=59)
+ created = datetime.now(tz=UTC) - timedelta(minutes=60)
+ last_seen = datetime.now(tz=UTC) - timedelta(minutes=59)
user = User(user_id=self.user_id, created=created, last_seen=last_seen)
assert user.created == created
assert user.last_seen == last_seen
def test_created_first(self):
- from generalresearch.models.thl.user import User
- created = datetime.now(tz=timezone.utc) - timedelta(minutes=60)
- last_seen = datetime.now(tz=timezone.utc) - timedelta(minutes=59)
+ created = datetime.now(tz=UTC) - timedelta(minutes=60)
+ last_seen = datetime.now(tz=UTC) - timedelta(minutes=59)
with pytest.raises(ValueError) as cm:
User(user_id=self.user_id, created=last_seen, last_seen=created)
@@ -572,7 +540,6 @@ class TestUserModelVerification:
"""Tests that may be dependent on more than 1 attribute"""
def test_identifiable(self):
- from generalresearch.models.thl.user import User
product_id = uuid4().hex
product_user_id = uuid4().hex
@@ -580,7 +547,6 @@ class TestUserModelVerification:
assert user.is_identifiable
def test_valid_helper(self):
- from generalresearch.models.thl.user import User
user_bool = User.is_valid_ubp(
product_id=uuid4().hex, product_user_id=uuid4().hex
@@ -594,7 +560,6 @@ class TestUserModelVerification:
class TestUserSerialization:
def test_basic_json(self):
- from generalresearch.models.thl.user import User
product_id = uuid4().hex
product_user_id = uuid4().hex
@@ -602,7 +567,7 @@ class TestUserSerialization:
user = User(
product_id=product_id,
product_user_id=product_user_id,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
blocked=False,
)
@@ -615,7 +580,6 @@ class TestUserSerialization:
assert d.get("created").endswith("Z")
def test_basic_dict(self):
- from generalresearch.models.thl.user import User
product_id = uuid4().hex
product_user_id = uuid4().hex
@@ -623,7 +587,7 @@ class TestUserSerialization:
user = User(
product_id=product_id,
product_user_id=product_user_id,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
blocked=False,
)
@@ -633,10 +597,11 @@ class TestUserSerialization:
assert not d.get("blocked")
assert d.get("product") is None
- assert d.get("created").tzinfo == timezone.utc
+ created = d.get("created")
+ assert isinstance(created, datetime)
+ assert created.tzinfo == UTC
def test_from_json(self):
- from generalresearch.models.thl.user import User
product_id = uuid4().hex
product_user_id = uuid4().hex
@@ -644,41 +609,51 @@ class TestUserSerialization:
user = User(
product_id=product_id,
product_user_id=product_user_id,
- created=datetime.now(tz=timezone.utc),
+ created=datetime.now(tz=UTC),
blocked=False,
)
u = User.model_validate_json(user.to_json())
assert u.product_id == product_id
assert u.product is None
- assert u.created.tzinfo == timezone.utc
+ assert isinstance(u.created, datetime)
+ assert u.created.tzinfo == UTC
class TestUserMethods:
- def test_audit_log(self, user, audit_log_manager):
+ def test_audit_log(
+ self,
+ audit_log_factory: Callable[..., AuditLog],
+ user: User,
+ audit_log_manager: AuditLogManager,
+ ):
assert user.audit_log is None
user.prefetch_audit_log(audit_log_manager=audit_log_manager)
assert user.audit_log == []
- audit_log_manager.create_dummy(user_id=user.user_id)
+ audit_log_factory(user_id=user.user_id)
user.prefetch_audit_log(audit_log_manager=audit_log_manager)
assert len(user.audit_log) == 1
def test_transactions(
- self, user_factory, thl_lm, session_with_tx_factory, product_user_wallet_yes
+ self,
+ user_factory: Callable[..., User],
+ thl_ledger_manager: ThlLedgerManager,
+ session_with_tx_factory: Callable[..., None],
+ product_user_wallet_yes: Product,
):
u1 = user_factory(product=product_user_wallet_yes)
assert u1.transactions is None
- u1.prefetch_transactions(thl_lm=thl_lm)
+ u1.prefetch_transactions(thl_lm=thl_ledger_manager)
assert u1.transactions == []
session_with_tx_factory(user=u1)
- u1.prefetch_transactions(thl_lm=thl_lm)
+ u1.prefetch_transactions(thl_lm=thl_ledger_manager)
assert len(u1.transactions) == 1
@pytest.mark.skip(reason="TODO")
- def test_location_history(self, user):
+ def test_location_history(self, user: User):
assert user.location_history is None