aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMax Nanis2026-09-02 17:40:18 -0700
committerMax Nanis2026-09-02 17:40:18 -0700
commitad620d7586640534a092672b8f3cddf6eff5604b (patch)
tree8fa5161ecf19ad08aafbc4961572223f77770a04
parent97b14e2f133bda76f548ec1a522d9582c657d736 (diff)
downloadgeneralresearch-ad620d7586640534a092672b8f3cddf6eff5604b.tar.gz
generalresearch-ad620d7586640534a092672b8f3cddf6eff5604b.zip
gr mangers all green ✅
-rw-r--r--Jenkinsfile16
-rw-r--r--generalresearch/managers/gr/team.py7
-rw-r--r--generalresearch/models/thl/product.py4
-rw-r--r--generalresearch/thl_django/app/test_settings.py2
-rw-r--r--test_utils/managers/gr/conftest.py22
-rw-r--r--test_utils/models/conftest.py31
-rw-r--r--test_utils/models/gr/conftest.py10
-rw-r--r--test_utils/models/thl/conftest.py61
-rw-r--r--tests/managers/gr/test_authentication.py32
-rw-r--r--tests/managers/gr/test_business.py22
-rw-r--r--tests/managers/gr/test_team.py91
11 files changed, 180 insertions, 118 deletions
diff --git a/Jenkinsfile b/Jenkinsfile
index de909b2..a646d22 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -62,11 +62,27 @@ pipeline {
stage('base') {
steps {
dir("generalresearch-${VER}") {
+ sh "${VENV}-${VER}/bin/pytest tests/test_postgres.py -vs"
+ }
+ }
+ }
+
+ stage('models') {
+ steps {
+ dir("generalresearch-${VER}") {
sh "${VENV}-${VER}/bin/pytest tests/models/gr/test_base.py -vs"
}
}
}
+ stage('managers') {
+ steps {
+ dir("generalresearch-${VER}") {
+ sh "${VENV}-${VER}/bin/pytest tests/managers/gr/ -vs"
+ }
+ }
+ }
+
}
}
}
diff --git a/generalresearch/managers/gr/team.py b/generalresearch/managers/gr/team.py
index e551f85..41af709 100644
--- a/generalresearch/managers/gr/team.py
+++ b/generalresearch/managers/gr/team.py
@@ -11,6 +11,7 @@ from generalresearch.managers.base import (
PostgresManager,
PostgresManagerWithRedis,
)
+from generalresearch.managers.gr.authentication import GRUserManager
from generalresearch.models.custom_types import UUIDStr
from generalresearch.models.gr.team import (
Membership,
@@ -187,10 +188,12 @@ class TeamManager(PostgresManagerWithRedis):
return team
- def add_user(self, team: Team, gr_user: GRUser) -> Membership:
+ def add_user(
+ self, team: Team, gr_user: GRUser, gr_user_manager: GRUserManager
+ ) -> Membership:
"""Create a Membership between a GRUser and a Team"""
- team.prefetch_gr_users(pg_config=self.pg_config, redis_config=self.redis_config)
+ team.prefetch_gr_users(gr_user_manager=gr_user_manager)
assert gr_user not in team.gr_users, (
"Can't create multiple Memberships for " "the same User to the same Team"
diff --git a/generalresearch/models/thl/product.py b/generalresearch/models/thl/product.py
index 346a98b..3677ff2 100644
--- a/generalresearch/models/thl/product.py
+++ b/generalresearch/models/thl/product.py
@@ -1396,8 +1396,8 @@ class Product(BaseModel, validate_assignment=True):
# --- ORM ---
- def model_dump_mysql(self) -> dict[str, Any]:
- d = self.model_dump(mode="json")
+ def model_dump_mysql(self, *args, **kwargs) -> dict[str, Any]:
+ d = self.model_dump(mode="json", *args, **kwargs)
assert self.created
if "created" in d:
diff --git a/generalresearch/thl_django/app/test_settings.py b/generalresearch/thl_django/app/test_settings.py
index 2738aed..276b94a 100644
--- a/generalresearch/thl_django/app/test_settings.py
+++ b/generalresearch/thl_django/app/test_settings.py
@@ -1,7 +1,7 @@
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
- "NAME": 'unittest-2026-09-02-77ae16',
+ "NAME": 'unittest-2026-09-03-ab1271',
"USER": 'jenkins',
"PASSWORD": '123456789',
"HOST": 'unittest-postgresql.fmt2.grl.internal',
diff --git a/test_utils/managers/gr/conftest.py b/test_utils/managers/gr/conftest.py
index b5db2a5..cc1053c 100644
--- a/test_utils/managers/gr/conftest.py
+++ b/test_utils/managers/gr/conftest.py
@@ -7,7 +7,6 @@ from typing import TYPE_CHECKING
import pytest
import redis
-import redis.asyncio as redis_async
from pydantic import PostgresDsn
from generalresearch.managers.gr.business import (
@@ -15,12 +14,14 @@ from generalresearch.managers.gr.business import (
BusinessBankAccountManager,
BusinessManager,
)
+from generalresearch.managers.gr.team import MembershipManager
from generalresearch.pg_helper import PostgresConfig
from generalresearch.redis_helper import RedisConfig
if TYPE_CHECKING:
from generalresearch.config import GRLBaseSettings
from generalresearch.managers.gr.authentication import GRTokenManager, GRUserManager
+ from generalresearch.managers.gr.team import TeamManager
# === Msc ===
@@ -89,7 +90,17 @@ def gr_user_manager(
@pytest.fixture(scope="session")
-def gr_team_manager(gr_db: PostgresConfig) -> GRTokenManager:
+def gr_team_manager(gr_db: PostgresConfig, gr_redis_config: RedisConfig) -> TeamManager:
+ assert gr_db.dsn.path
+ assert "/unittest-" in gr_db.dsn.path
+
+ from generalresearch.managers.gr.team import TeamManager
+
+ return TeamManager(pg_config=gr_db, redis_config=gr_redis_config)
+
+
+@pytest.fixture(scope="session")
+def gr_token_manager(gr_db: PostgresConfig) -> GRTokenManager:
assert gr_db.dsn.path
assert "/unittest-" in gr_db.dsn.path
@@ -117,3 +128,10 @@ def gr_business_address_manager(
gr_db: PostgresConfig,
) -> BusinessAddressManager:
return BusinessAddressManager(pg_config=gr_db)
+
+
+@pytest.fixture(scope="session")
+def gr_membership_manager(
+ gr_db: PostgresConfig,
+) -> MembershipManager:
+ return MembershipManager(pg_config=gr_db)
diff --git a/test_utils/models/conftest.py b/test_utils/models/conftest.py
index ed4da08..d71593f 100644
--- a/test_utils/models/conftest.py
+++ b/test_utils/models/conftest.py
@@ -286,36 +286,7 @@ def session(
return session
-@pytest.fixture
-def product(request: Request, product_manager: ProductManager) -> Product:
-
- team = getattr(request, "team", None)
- business = getattr(request, "business", None)
-
- return product_manager.create_dummy(
- team_id=team.uuid if team else None,
- business_id=business.uuid if business else None,
- )
-
-
-@pytest.fixture
-def product_factory(product_manager: ProductManager) -> Callable[..., Product]:
-
- def _inner(
- team: Team | None = None,
- business: Business | None = None,
- commission_pct: Decimal = Decimal("0.05"),
- ) -> Product:
- return product_manager.create_dummy(
- team_id=team.uuid if team else None,
- business_id=business.uuid if business else None,
- commission_pct=commission_pct,
- )
-
- return _inner
-
-
-@pytest.fixture
+@pytest.fixture()
def payout_config(request: Request) -> PayoutConfig:
from generalresearch.models.thl.product import (
PayoutConfig,
diff --git a/test_utils/models/gr/conftest.py b/test_utils/models/gr/conftest.py
index a5abf74..3dd73a1 100644
--- a/test_utils/models/gr/conftest.py
+++ b/test_utils/models/gr/conftest.py
@@ -207,8 +207,10 @@ def gr_team_factory(
**kwargs,
) -> Team:
+ name = name or f"<Team ({uuid4().hex[:6]})>"
+
if save:
- return gr_team_manager.create(uuid=uuid, name=name, **kwargs)
+ return gr_team_manager.create(name=name, uuid=uuid, **kwargs)
else:
raise ValueError("BusinessBankAccount Business not supported yet")
@@ -325,12 +327,12 @@ def gr_user_token_header(gr_user_token: GRToken) -> dict[str, str]:
@pytest.fixture()
def gr_membership_factory(
- gr_team: Team,
- gr_user: GRUser,
gr_membership_manager: MembershipManager,
) -> Callable[..., Membership]:
- def _inner(save: bool = True, **kwargs) -> Membership:
+ def _inner(
+ gr_team: Team, gr_user: GRUser, save: bool = True, **kwargs
+ ) -> Membership:
if save:
return gr_membership_manager.create(team=gr_team, gr_user=gr_user, **kwargs)
else:
diff --git a/test_utils/models/thl/conftest.py b/test_utils/models/thl/conftest.py
index 3545509..badd87c 100644
--- a/test_utils/models/thl/conftest.py
+++ b/test_utils/models/thl/conftest.py
@@ -39,6 +39,7 @@ if TYPE_CHECKING:
from generalresearch.managers.thl.userhealth import AuditLogManager, IPRecordManager
from generalresearch.managers.thl.wall import WallManager
from generalresearch.models.definitions import DeviceType
+ from generalresearch.models.gr.team import Team
from generalresearch.models.legacy.bucket import Bucket
from generalresearch.models.thl.ipinfo import IPGeoname, IPInformation
from generalresearch.models.thl.payout import UserPayoutEvent
@@ -144,12 +145,18 @@ def wall_factory(
return _inner
-@pytest.fixture
+# --- Product ---
+
+
+@pytest.fixture()
def product_factory(product_manager: ProductManager) -> Callable[..., Product]:
def _inner(
+ save: bool = True,
+ team: Team | None = None,
+ # business: Business | None = None,
+ # commission_pct: Decimal = Decimal("0.05"),
product_id: UUIDStr | None = None,
- team_id: UUIDStr | None = None,
business_id: UUIDStr | None = None,
name: str | None = None,
redirect_url: str | None = None,
@@ -165,30 +172,46 @@ def product_factory(product_manager: ProductManager) -> Callable[..., Product]:
) -> Product:
"""To be used in tests, where we don't care about certain fields"""
product_id = product_id if product_id else uuid4().hex
- team_id = team_id if team_id else uuid4().hex
+ team_id = team.uuid if team else uuid4().hex
name = name if name else f"name-{product_id[:12]}"
redirect_url = redirect_url if redirect_url else "https://www.example.com/"
- return product_manager.create(
- product_id=product_id,
- team_id=team_id,
- business_id=business_id,
- name=name,
- redirect_url=redirect_url,
- harmonizer_domain=harmonizer_domain,
- commission_pct=commission_pct,
- sources_config=sources_config,
- payout_config=payout_config,
- session_config=session_config,
- profiling_config=profiling_config,
- user_wallet_config=user_wallet_config,
- user_create_config=user_create_config,
- user_health_config=user_health_config,
- )
+ if save:
+ return product_manager.create(
+ product_id=product_id,
+ team_id=team_id,
+ business_id=business_id,
+ name=name,
+ redirect_url=redirect_url,
+ harmonizer_domain=harmonizer_domain,
+ commission_pct=commission_pct,
+ sources_config=sources_config,
+ payout_config=payout_config,
+ session_config=session_config,
+ profiling_config=profiling_config,
+ user_wallet_config=user_wallet_config,
+ user_create_config=user_create_config,
+ user_health_config=user_health_config,
+ )
+ else:
+ raise ValueError("Unsaved Product not yet supported")
return _inner
+@pytest.fixture()
+def product(product_factory: Callable[..., Product]) -> Product:
+ return product_factory(save=True)
+
+
+@pytest.fixture()
+def unsaved_product(product_factory: Callable[..., Product]) -> Product:
+ return product_factory(save=False)
+
+
+# --- Session ---
+
+
@pytest.fixture
def session_factory(session_manager: SessionManager):
diff --git a/tests/managers/gr/test_authentication.py b/tests/managers/gr/test_authentication.py
index 0bcabc5..1310c79 100644
--- a/tests/managers/gr/test_authentication.py
+++ b/tests/managers/gr/test_authentication.py
@@ -84,29 +84,32 @@ class TestGRUserManager:
class TestGRTokenManager:
- def test_create(self, gr_user: GRUser, gr_team_manager: TeamManager):
- assert gr_team_manager.create(user_id=gr_user.id) is None
+ def test_create(self, gr_user: GRUser, gr_token_manager: GRTokenManager):
+ assert gr_token_manager.create(user_id=gr_user.id) is None
- token = gr_team_manager.get_by_user_id(user_id=gr_user.id)
+ token = gr_token_manager.get_by_user_id(user_id=gr_user.id)
+ assert isinstance(token, GRToken)
assert gr_user.id == token.user_id
- def test_get_by_user_id(self, gr_user: GRUser, gr_team_manager: TeamManager):
- assert gr_team_manager.create(user_id=gr_user.id) is None
+ def test_get_by_user_id(self, gr_user: GRUser, gr_token_manager: GRTokenManager):
+ assert gr_token_manager.create(user_id=gr_user.id) is None
- token = gr_team_manager.get_by_user_id(user_id=gr_user.id)
+ token = gr_token_manager.get_by_user_id(user_id=gr_user.id)
+ assert isinstance(token, GRToken)
assert gr_user.id == token.user_id
def test_prefetch_user(
self,
gr_user: GRUser,
- gr_team_manager: TeamManager,
+ gr_token_manager: GRTokenManager,
gr_db: PostgresConfig,
gr_redis_config: RedisConfig,
):
- gr_team_manager.create(user_id=gr_user.id)
+ gr_token_manager.create(user_id=gr_user.id)
- token: GRToken = gr_team_manager.get_by_user_id(user_id=gr_user.id)
+ token: GRToken | None = gr_token_manager.get_by_user_id(user_id=gr_user.id)
+ assert isinstance(token, GRToken)
assert token.user is None
token.prefetch_user(pg_config=gr_db, redis_config=gr_redis_config)
@@ -115,17 +118,18 @@ class TestGRTokenManager:
def test_get_by_key(
self,
gr_user: GRUser,
- gr_team_manager: TeamManager,
+ gr_token_manager: GRTokenManager,
):
- gr_team_manager.create(user_id=gr_user.id)
- token = gr_team_manager.get_by_user_id(user_id=gr_user.id)
+ gr_token_manager.create(user_id=gr_user.id)
+ token = gr_token_manager.get_by_user_id(user_id=gr_user.id)
+ assert isinstance(token, GRToken)
- instance = gr_team_manager.get_by_key(api_key=token.key)
+ instance = gr_token_manager.get_by_key(api_key=token.key)
assert token.created == instance.created
# Search for non-existent key
with pytest.raises(expected_exception=Exception) as cm:
- gr_team_manager.get_by_key(api_key=uuid4().hex)
+ gr_token_manager.get_by_key(api_key=uuid4().hex)
assert "No GRUser with token of " in str(cm.value)
@pytest.mark.skip(reason="no idea how to actually test this...")
diff --git a/tests/managers/gr/test_business.py b/tests/managers/gr/test_business.py
index 3513af5..0d5b0d5 100644
--- a/tests/managers/gr/test_business.py
+++ b/tests/managers/gr/test_business.py
@@ -1,3 +1,4 @@
+from collections.abc import Callable
from typing import TYPE_CHECKING
from uuid import uuid4
@@ -9,6 +10,7 @@ from generalresearch.models.gr.business import (
BusinessBankAccount,
)
from generalresearch.models.gr.definitions import TransferMethod
+from generalresearch.models.gr.team import Team
if TYPE_CHECKING:
from generalresearch.managers.gr.business import (
@@ -68,9 +70,9 @@ class TestBusinessAddressManager:
class TestBusinessManager:
- def test_create(self, business_manager: BusinessManager):
+ def test_create(self, gr_business_factory: Callable[..., Business]):
- instance = business_manager.create_dummy()
+ instance = gr_business_factory()
assert isinstance(instance, Business)
assert isinstance(instance.id, int)
@@ -88,11 +90,15 @@ class TestBusinessManager:
assert isinstance(res, Business)
assert res.id == instance.id
- def test_get_all(self, business_manager: BusinessManager):
+ def test_get_all(
+ self,
+ business_manager: BusinessManager,
+ gr_business_factory: Callable[..., Business],
+ ):
res1 = business_manager.get_all()
assert isinstance(res1, list)
- business_manager.create_dummy()
+ gr_business_factory()
res2 = business_manager.get_all()
assert len(res1) == len(res2) - 1
@@ -106,17 +112,19 @@ class TestBusinessManager:
gr_user: GRUser,
team_manager: TeamManager,
membership_manager: MembershipManager,
+ gr_business_factory: Callable[..., Business],
+ gr_team_factory: Callable[..., Team],
):
res = business_manager.get_by_user_id(user_id=gr_user.id)
assert len(res) == 0
# Create a business: Business, but don't add it to anything
- b1 = business_manager.create_dummy()
+ b1 = gr_business_factory()
res = business_manager.get_by_user_id(user_id=gr_user.id)
assert len(res) == 0
# Create a Team, but don't create any Memberships
- t1 = team_manager.create_dummy()
+ t1 = gr_team_factory()
res = business_manager.get_by_user_id(user_id=gr_user.id)
assert len(res) == 0
@@ -133,7 +141,7 @@ class TestBusinessManager:
assert len(res) == 1
# Add another Business to the Team!
- b2 = business_manager.create_dummy()
+ b2 = gr_business_factory()
team_manager.add_business(team=t1, business=b2)
res = business_manager.get_by_user_id(user_id=gr_user.id)
assert len(res) == 2
diff --git a/tests/managers/gr/test_team.py b/tests/managers/gr/test_team.py
index 17e0470..751e33c 100644
--- a/tests/managers/gr/test_team.py
+++ b/tests/managers/gr/test_team.py
@@ -4,6 +4,7 @@ from collections.abc import Callable
from typing import TYPE_CHECKING
from uuid import uuid4
+from generalresearch.models.gr.authentication import GRUser
from generalresearch.models.gr.team import Membership, Team
if TYPE_CHECKING:
@@ -23,94 +24,110 @@ class TestMembershipManager:
class TestTeamManager:
- def test_init(self, team_manager: TeamManager, gr_db: PostgresConfig):
- assert team_manager.pg_config == gr_db
+ def test_init(self, gr_team_manager: TeamManager, gr_db: PostgresConfig):
+ assert gr_team_manager.pg_config == gr_db
- def test_get_or_create(self, team_manager: TeamManager):
+ def test_get_or_create(self, gr_team_manager: TeamManager):
from generalresearch.models.gr.team import Team
new_uuid = uuid4().hex
- team: Team = team_manager.get_or_create(uuid=new_uuid)
+ team: Team = gr_team_manager.get_or_create(uuid=new_uuid)
assert isinstance(team, Team)
assert isinstance(team.id, int)
assert team.uuid == new_uuid
assert team.name == "< Unknown >"
- def test_get_all(self, team_manager: TeamManager):
- res1 = team_manager.get_all()
+ def test_get_all(
+ self, gr_team_factory: Callable[..., Team], gr_team_manager: TeamManager
+ ):
+ res1 = gr_team_manager.get_all()
assert isinstance(res1, list)
- team_manager.create_dummy()
- res2 = team_manager.get_all()
+ gr_team_factory()
+ res2 = gr_team_manager.get_all()
assert len(res1) == len(res2) - 1
- def test_create(self, team_manager: TeamManager):
+ def test_create(
+ self, gr_team_factory: Callable[..., Team], gr_team_manager: TeamManager
+ ):
- team: Team = team_manager.create_dummy()
+ team: Team = gr_team_factory()
assert isinstance(team, Team)
assert isinstance(team.id, int)
def test_add_user(
self,
- team: Team,
- team_manager: TeamManager,
- gr_um: GRUserManager,
- gr_db: PostgresConfig,
- gr_redis_config: RedisConfig,
+ gr_team: Team,
+ gr_team_manager: TeamManager,
+ gr_user_manager: GRUserManager,
+ gr_user_factory: Callable[..., GRUser],
):
- user: GRUser = gr_um.create_dummy()
+ user: GRUser = gr_user_factory()
- instance = team_manager.add_user(team=team, gr_user=user)
+ instance = gr_team_manager.add_user(
+ gr_user_manager=gr_user_manager, team=gr_team, gr_user=user
+ )
assert isinstance(instance, Membership)
# assert team.gr_users is None
- team.prefetch_gr_users(pg_config=gr_db, redis_config=gr_redis_config)
- assert isinstance(team.gr_users, list)
- assert len(team.gr_users)
- assert team.gr_users == [user]
+ gr_team.prefetch_gr_users(gr_user_manager=gr_user_manager)
+ assert isinstance(gr_team.gr_users, list)
+ assert len(gr_team.gr_users)
+ assert gr_team.gr_users == [user]
- def test_get_by_uuid(self, team_manager: TeamManager):
+ def test_get_by_uuid(
+ self, gr_team_factory: Callable[..., Team], gr_team_manager: TeamManager
+ ):
- team: Team = team_manager.create_dummy()
+ team: Team = gr_team_factory()
- instance = team_manager.get_by_uuid(team_uuid=team.uuid)
+ instance = gr_team_manager.get_by_uuid(team_uuid=team.uuid)
+ assert isinstance(instance, Team)
assert team.id == instance.id
- def test_get_by_id(self, team_manager: TeamManager):
+ def test_get_by_id(
+ self, gr_team_factory: Callable[..., Team], gr_team_manager: TeamManager
+ ):
- team: Team = team_manager.create_dummy()
+ team: Team = gr_team_factory()
- instance = team_manager.get_by_id(team_id=team.id)
+ instance = gr_team_manager.get_by_id(team_id=team.id)
+ assert isinstance(instance, Team)
assert team.uuid == instance.uuid
def test_get_by_user(
- self, team: Team, team_manager: TeamManager, gr_um: GRUserManager
+ self,
+ gr_team: Team,
+ gr_user_factory: Callable[..., GRUser],
+ gr_team_manager: TeamManager,
+ gr_user_manager: GRUserManager,
):
+ user: GRUser = gr_user_factory()
+ gr_team_manager.add_user(
+ gr_user_manager=gr_user_manager, team=gr_team, gr_user=user
+ )
- user: GRUser = gr_um.create_dummy()
- team_manager.add_user(team=team, gr_user=user)
-
- res = team_manager.get_by_user(gr_user=user)
+ res = gr_team_manager.get_by_user(gr_user=user)
assert isinstance(res, list)
assert len(res) == 1
instance = res[0]
assert isinstance(instance, Team)
- assert instance.uuid == team.uuid
+ assert instance.uuid == gr_team.uuid
def test_get_by_user_duplicates(
self,
gr_user: GRUser,
product_factory: Callable[..., Product],
- membership_factory: Callable[..., Membership],
- team: Team,
+ gr_membership_factory: Callable[..., Membership],
+ gr_team: Team,
gr_redis_config: RedisConfig,
gr_db: PostgresConfig,
):
- product_factory(team=team)
- membership_factory(team=team, gr_user=gr_user)
+ product_factory(team=gr_team)
+ gr_membership_factory(gr_team=gr_team, gr_user=gr_user)
gr_user.prefetch_teams(
pg_config=gr_db,