aboutsummaryrefslogtreecommitdiff
path: root/test_utils
diff options
context:
space:
mode:
Diffstat (limited to 'test_utils')
-rw-r--r--test_utils/conftest.py228
-rw-r--r--test_utils/grliq/conftest.py124
-rw-r--r--test_utils/incite/collections/conftest.py38
-rw-r--r--test_utils/incite/conftest.py34
-rw-r--r--test_utils/incite/mergers/conftest.py105
-rw-r--r--test_utils/managers/conftest.py578
-rw-r--r--test_utils/managers/contest/conftest.py294
-rw-r--r--test_utils/managers/gr/conftest.py197
-rw-r--r--test_utils/managers/grliq/conftest.py61
-rw-r--r--test_utils/managers/ledger/conftest.py778
-rw-r--r--test_utils/managers/network/conftest.py143
-rw-r--r--test_utils/managers/thl/conftest.py362
-rw-r--r--test_utils/managers/upk/conftest.py188
-rw-r--r--test_utils/models/conftest.py86
-rw-r--r--test_utils/models/contest/__init__.py (renamed from test_utils/grliq/managers/__init__.py)0
-rw-r--r--test_utils/models/contest/conftest.py292
-rw-r--r--test_utils/models/gr/__init__.py (renamed from test_utils/grliq/models/__init__.py)0
-rw-r--r--test_utils/models/gr/conftest.py213
-rw-r--r--test_utils/models/ledger/__init__.py (renamed from test_utils/managers/grliq/__init__.py)0
-rw-r--r--test_utils/models/ledger/conftest.py724
-rw-r--r--test_utils/models/network/__init__.py (renamed from test_utils/grliq/managers/conftest.py)0
-rw-r--r--test_utils/models/network/conftest.py144
-rw-r--r--test_utils/models/thl/__init__.py (renamed from test_utils/grliq/models/conftest.py)0
-rw-r--r--test_utils/models/thl/conftest.py434
-rw-r--r--test_utils/models/upk/__init__.py0
-rw-r--r--test_utils/models/upk/conftest.py178
-rw-r--r--test_utils/models/upk/marketplace_category.csv.gz (renamed from test_utils/managers/upk/marketplace_category.csv.gz)bin100990 -> 100990 bytes
-rw-r--r--test_utils/models/upk/marketplace_item.csv.gz (renamed from test_utils/managers/upk/marketplace_item.csv.gz)bin3225 -> 3225 bytes
-rw-r--r--test_utils/models/upk/marketplace_property.csv.gz (renamed from test_utils/managers/upk/marketplace_property.csv.gz)bin3315 -> 3315 bytes
-rw-r--r--test_utils/models/upk/marketplace_propertycategoryassociation.csv.gz (renamed from test_utils/managers/upk/marketplace_propertycategoryassociation.csv.gz)bin2079 -> 2079 bytes
-rw-r--r--test_utils/models/upk/marketplace_propertycountry.csv.gz (renamed from test_utils/managers/upk/marketplace_propertycountry.csv.gz)bin71359 -> 71359 bytes
-rw-r--r--test_utils/models/upk/marketplace_propertyitemrange.csv.gz (renamed from test_utils/managers/upk/marketplace_propertyitemrange.csv.gz)bin65389 -> 65389 bytes
-rw-r--r--test_utils/models/upk/marketplace_propertymarketplaceassociation.csv.gz (renamed from test_utils/managers/upk/marketplace_propertymarketplaceassociation.csv.gz)bin4272 -> 4272 bytes
-rw-r--r--test_utils/models/upk/marketplace_question.csv.gz (renamed from test_utils/managers/upk/marketplace_question.csv.gz)bin283465 -> 283465 bytes
34 files changed, 2769 insertions, 2432 deletions
diff --git a/test_utils/conftest.py b/test_utils/conftest.py
index 9c80065..cd7f282 100644
--- a/test_utils/conftest.py
+++ b/test_utils/conftest.py
@@ -1,29 +1,27 @@
+from __future__ import annotations
+
import os
import shutil
+import stat
+import subprocess
+import tempfile
from datetime import datetime, timedelta, timezone
from os.path import join as pjoin
from pathlib import Path
-from typing import TYPE_CHECKING, Callable, Generator
+from typing import Callable, Generator
from uuid import uuid4
import pytest
-import redis
from _pytest.config import Config
from dotenv import load_dotenv
from pydantic import MariaDBDsn, PostgresDsn, TypeAdapter
-from pydantic_core import MultiHostHost
-from redis import Redis
+from generalresearch.config import GRLBaseSettings
+from generalresearch.currency import USDCent
from generalresearch.models.custom_types import InternalHostname, PostgresDict
from generalresearch.pg_helper import PostgresConfig
-from generalresearch.redis_helper import RedisConfig
from generalresearch.sql_helper import SqlHelper
-if TYPE_CHECKING:
- from generalresearch.config import GRLBaseSettings
- from generalresearch.currency import USDCent
- from generalresearch.models.thl.session import Status
-
@pytest.fixture(scope="session")
def env_file_path(pytestconfig: Config) -> Path:
@@ -44,7 +42,7 @@ def env_file_path(pytestconfig: Config) -> Path:
@pytest.fixture(scope="session")
-def settings(env_file_path: Path) -> "GRLBaseSettings":
+def settings(env_file_path: Path) -> GRLBaseSettings:
from generalresearch.config import GRLBaseSettings
s = GRLBaseSettings()
@@ -64,7 +62,7 @@ def settings(env_file_path: Path) -> "GRLBaseSettings":
@pytest.fixture(scope="session")
-def postgres_instance(settings: "GRLBaseSettings") -> Generator[PostgresDsn]:
+def postgres_instance(settings: GRLBaseSettings) -> Generator[PostgresDsn]:
"""Create a ephemeral postgresql instance for us to use during pytest.
This does not create any tables, or schema definitions within the instance.
@@ -153,13 +151,61 @@ def postgres_instance_host(
yield value
+# @pytest.fixture(scope="session")
+# def git_key_path(settings: GRLBaseSettings) -> Path:
+# return Path('/tmp/')
+
+
+@pytest.fixture(scope="session")
+def git_key_path(
+ settings: GRLBaseSettings,
+) -> Generator[Path]:
+
+ assert settings.git_creds
+ with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix="_id_rsa") as f:
+ f.write(settings.git_creds)
+ key_path = f.name
+
+ os.chmod(key_path, stat.S_IRUSR | stat.S_IWUSR)
+
+ yield Path(key_path)
+
+ os.unlink(key_path)
+
+
+@pytest.fixture(scope="session")
+def gr_models(git_key_path: Path) -> Callable[..., Path]:
+ repo_url = "ssh://code.g-r-l.com/general-research/gr-carer.git"
+ repo_path = Path("/tmp/gr-carer")
+
+ def _inner() -> Path:
+ ssh_cmd = (
+ f"ssh -i {git_key_path} "
+ "-o IdentitiesOnly=yes "
+ "-o StrictHostKeyChecking=no " # or accept-new, see note below
+ )
+ env = {"GIT_SSH_COMMAND": ssh_cmd}
+
+ if repo_path.exists():
+ subprocess.run(["git", "-C", str(repo_path), "pull"], check=True, env=env)
+ else:
+ subprocess.run(
+ ["git", "clone", "--depth", "1", repo_url, str(repo_path)],
+ check=True,
+ env=env,
+ )
+
+ return repo_path
+
+ return _inner
+
+
@pytest.fixture(scope="session")
def django_db_factory(
postgres_instance: PostgresDsn, postgres_instance_dict: PostgresDict
) -> Callable[..., PostgresDsn]:
import django
- from django.apps import apps
from django.conf import settings as django_settings
from django.core.management import call_command
@@ -199,46 +245,7 @@ def django_db_factory(
@pytest.fixture(scope="session")
-def thl_web_rr(django_db_factory: Callable[..., PostgresDsn]) -> PostgresConfig:
-
- return PostgresConfig(
- dsn=django_db_factory("generalresearch.thl_django"),
- connect_timeout=1,
- statement_timeout=5,
- )
-
-
-@pytest.fixture(scope="session")
-def thl_web_rw(thl_web_rr: PostgresConfig) -> PostgresConfig:
- return thl_web_rr
-
-
-@pytest.fixture(scope="session")
-def gr_db(django_db_factory: Callable[..., PostgresDsn]) -> PostgresConfig:
-
- return PostgresConfig(
- dsn=django_db_factory("gr_carer"),
- connect_timeout=1,
- statement_timeout=5,
- )
-
-
-@pytest.fixture(scope="session")
-def grliq_db(postgres_instance: PostgresDsn) -> PostgresConfig:
-
- # test_words = {"localhost", "127.0.0.1", "unittest", "grliq-test"}
- # assert any(w in str(postgres_config.dsn) for w in test_words), "check grliq postgres_config"
- # assert "grliqdeceezpocymo" not in str(postgres_config.dsn), "check grliq postgres_config"
-
- return PostgresConfig(
- dsn=postgres_instance,
- connect_timeout=1,
- statement_timeout=5,
- )
-
-
-@pytest.fixture(scope="session")
-def spectrum_rw(settings: "GRLBaseSettings") -> SqlHelper:
+def spectrum_rw(settings: GRLBaseSettings) -> SqlHelper:
dsn = settings.spectrum_rw_db
assert dsn
assert dsn.path
@@ -254,94 +261,15 @@ def spectrum_rw(settings: "GRLBaseSettings") -> SqlHelper:
)
-@pytest.fixture(scope="session")
-def thl_redis(settings: "GRLBaseSettings") -> "Redis":
- # todo: this should get replaced with redisconfig (in most places)
- # I'm not sure where this would be? in the domain name?
- assert "unittest" in str(settings.thl_redis) or "127.0.0.1" in str(
- settings.thl_redis
- )
-
- return redis.Redis.from_url(
- **{
- "url": str(settings.thl_redis),
- "decode_responses": True,
- "socket_timeout": settings.redis_timeout,
- "socket_connect_timeout": settings.redis_timeout,
- }
- )
-
-
-@pytest.fixture(scope="session")
-def thl_redis_config(settings: "GRLBaseSettings") -> RedisConfig:
- assert "unittest" in str(settings.thl_redis) or "127.0.0.1" in str(
- settings.thl_redis
- )
- return RedisConfig(
- dsn=settings.thl_redis,
- decode_responses=True,
- socket_timeout=settings.redis_timeout,
- socket_connect_timeout=settings.redis_timeout,
- )
-
-
-@pytest.fixture(scope="session")
-def gr_redis_config(settings: "GRLBaseSettings") -> "RedisConfig":
- assert "unittest" in str(settings.gr_redis) or "127.0.0.1" in str(settings.gr_redis)
-
- return RedisConfig(
- dsn=settings.gr_redis,
- decode_responses=True,
- socket_timeout=settings.redis_timeout,
- socket_connect_timeout=settings.redis_timeout,
- )
-
-
-@pytest.fixture(scope="session")
-def gr_redis(settings: "GRLBaseSettings") -> "Redis":
- assert "unittest" in str(settings.gr_redis) or "127.0.0.1" in str(settings.gr_redis)
- return redis.Redis.from_url(
- **{
- "url": str(settings.gr_redis),
- "decode_responses": True,
- "socket_timeout": settings.redis_timeout,
- "socket_connect_timeout": settings.redis_timeout,
- }
- )
-
-
-@pytest.fixture
-def gr_redis_async(settings: "GRLBaseSettings"):
- assert "unittest" in str(settings.gr_redis) or "127.0.0.1" in str(settings.gr_redis)
-
- import redis.asyncio as redis_async
-
- return redis_async.Redis.from_url(
- str(settings.gr_redis),
- decode_responses=True,
- socket_timeout=0.20,
- socket_connect_timeout=0.20,
- )
-
-
# === Random helpers ===
@pytest.fixture
-def start() -> "datetime":
- from datetime import datetime, timezone
-
+def start() -> datetime:
return datetime(year=1900, month=1, day=1, tzinfo=timezone.utc)
@pytest.fixture
-def wall_status(request) -> "Status":
- from generalresearch.models.thl.session import Status
-
- return request.param if hasattr(request, "wall_status") else Status.COMPLETE
-
-
-@pytest.fixture
def utc_now() -> datetime:
return datetime.now(tz=timezone.utc)
@@ -352,30 +280,22 @@ def utc_hour_ago() -> datetime:
@pytest.fixture
-def utc_day_ago() -> "datetime":
- from datetime import datetime, timedelta, timezone
-
+def utc_day_ago() -> datetime:
return datetime.now(tz=timezone.utc) - timedelta(hours=24)
@pytest.fixture
-def utc_90days_ago() -> "datetime":
- from datetime import datetime, timedelta, timezone
-
+def utc_90days_ago() -> datetime:
return datetime.now(tz=timezone.utc) - timedelta(days=90)
@pytest.fixture
-def utc_60days_ago() -> "datetime":
- from datetime import datetime, timedelta, timezone
-
+def utc_60days_ago() -> datetime:
return datetime.now(tz=timezone.utc) - timedelta(days=60)
@pytest.fixture
-def utc_30days_ago() -> "datetime":
- from datetime import datetime, timedelta, timezone
-
+def utc_30days_ago() -> datetime:
return datetime.now(tz=timezone.utc) - timedelta(days=30)
@@ -425,6 +345,8 @@ def delete_df_collection(
)
case _:
+ assert coll.data_type
+
thl_web_rw.execute_write(
query=f"DELETE FROM {coll.data_type.value};",
)
@@ -436,23 +358,23 @@ def delete_df_collection(
@pytest.fixture(scope="function")
-def amount_1(request) -> "USDCent":
- from generalresearch.currency import USDCent
-
+def amount_1() -> USDCent:
return USDCent(1)
@pytest.fixture(scope="function")
-def amount_100(request) -> "USDCent":
- from generalresearch.currency import USDCent
-
+def amount_100() -> USDCent:
return USDCent(100)
-def clear_directory(path: Path):
- for entry in os.listdir(path):
+def clear_directory(path: Path | str):
+ dir_path = Path(path)
+
+ for entry in os.listdir(dir_path):
+
full_path = os.path.join(path, entry)
if os.path.isfile(full_path) or os.path.islink(full_path):
os.unlink(full_path) # remove file or symlink
+
elif os.path.isdir(full_path):
shutil.rmtree(full_path) # remove folder
diff --git a/test_utils/grliq/conftest.py b/test_utils/grliq/conftest.py
index edd777e..e8175a5 100644
--- a/test_utils/grliq/conftest.py
+++ b/test_utils/grliq/conftest.py
@@ -1,23 +1,83 @@
+from __future__ import annotations
+
from datetime import datetime, timedelta, timezone
-from typing import TYPE_CHECKING, Optional
+from typing import Callable
from uuid import uuid4
import pytest
+from pydantic import PostgresDsn
+
+from generalresearch.config import GRLBaseSettings
+from generalresearch.grliq.managers import DUMMY_GRLIQ_DATA
+from generalresearch.grliq.managers.forensic_data import (
+ GrlIqDataManager,
+)
+from generalresearch.grliq.managers.forensic_events import (
+ GrlIqEventManager,
+)
+from generalresearch.grliq.managers.forensic_results import (
+ GrlIqCategoryResultsReader,
+)
+from generalresearch.grliq.models.forensic_data import GrlIqData
+from generalresearch.pg_helper import PostgresConfig
-if TYPE_CHECKING:
- from generalresearch.config import GRLBaseSettings
- from generalresearch.grliq.models.forensic_data import GrlIqData
+# === Miscellaneous ===
@pytest.fixture(scope="function")
-def mnt_grliq_archive_dir(settings: "GRLBaseSettings") -> Optional[str]:
+def mnt_grliq_archive_dir(settings: GRLBaseSettings) -> str | None:
return settings.mnt_grliq_archive_dir
+@pytest.fixture(scope="session")
+def grliq_db(postgres_instance: PostgresDsn) -> PostgresConfig:
+ # TODO: This will need to specificy a different DATABASE on the
+ # Postgres SERVER. That selection process will also need to
+ # selectively migrate only the tables from grliq
+
+ return PostgresConfig(
+ dsn=postgres_instance,
+ connect_timeout=1,
+ statement_timeout=5,
+ )
+
+
+# === Managers ===
+
+
+@pytest.fixture(scope="session")
+def grliq_dm(grliq_db: PostgresConfig) -> GrlIqDataManager:
+ assert grliq_db.dsn.path
+ assert "/unittest-" in grliq_db.dsn.path
+ return GrlIqDataManager(postgres_config=grliq_db)
+
+
+@pytest.fixture(scope="session")
+def grliq_em(grliq_db: PostgresConfig) -> GrlIqEventManager:
+ assert grliq_db.dsn.path
+ assert "/unittest-" in grliq_db.dsn.path
+
+ from generalresearch.grliq.managers.forensic_events import (
+ GrlIqEventManager,
+ )
+
+ return GrlIqEventManager(postgres_config=grliq_db)
+
+
+@pytest.fixture(scope="session")
+def grliq_crr(grliq_db: PostgresConfig) -> GrlIqCategoryResultsReader:
+ assert grliq_db.dsn.path
+ assert "/unittest-" in grliq_db.dsn.path
+
+ return GrlIqCategoryResultsReader(postgres_config=grliq_db)
+
+
+# === Models ===
+
+
@pytest.fixture(scope="function")
-def grliq_data() -> "GrlIqData":
+def grliq_data() -> GrlIqData:
from generalresearch.grliq.managers import DUMMY_GRLIQ_DATA
- from generalresearch.grliq.models.forensic_data import GrlIqData
g: GrlIqData = DUMMY_GRLIQ_DATA[1]["data"]
@@ -26,3 +86,53 @@ def grliq_data() -> "GrlIqData":
g.created_at = datetime.now(tz=timezone.utc)
g.timestamp = g.created_at - timedelta(seconds=10)
return g
+
+
+@pytest.fixture
+def grliq_data_factory(grliq_dm: GrlIqDataManager) -> Callable[..., GrlIqData]:
+
+ def _inner(
+ is_attempt_allowed: bool = True,
+ product_id: str | None = None,
+ product_user_id: str | None = None,
+ uuid: str | None = None,
+ mid: str | None = None,
+ created_at: datetime | None = None,
+ ) -> GrlIqData:
+ """
+ Creates a dummy record in the db with a GrlIqData (data), GrlIqCheckerResults (result_data),
+ and GrlIqForensicCategoryResult (category_results)
+ :param is_attempt_allowed: Whether the attempt is allowed.
+ :param product_id: product_id of user
+ :param product_user_id: product_user_id of user
+ :param uuid: uuid for the grliq data record
+ :param mid: the thl_session:uuid / mid for the attempt.
+ :return:
+ """
+ import copy
+
+ res: GrlIqData = copy.deepcopy(DUMMY_GRLIQ_DATA[int(is_attempt_allowed)])
+
+ product_id = product_id or uuid4().hex
+ product_user_id = product_user_id or uuid4().hex
+ uuid = uuid or uuid4().hex
+ mid = mid or uuid4().hex
+ created_at = created_at or datetime.now(tz=timezone.utc)
+
+ res["data"].product_id = product_id
+ res["data"].product_user_id = product_user_id
+ res["data"].uuid = uuid
+ res["data"].mid = mid
+ res["data"].created_at = created_at
+ res["result_data"].uuid = uuid
+ res["category_result"].uuid = uuid
+
+ return grliq_dm.create(
+ iq_data=res["data"],
+ result_data=res["result_data"],
+ category_result=res["category_result"],
+ fraud_score=res["category_result"].fraud_score,
+ is_attempt_allowed=res["category_result"].is_attempt_allowed(),
+ )
+
+ return _inner
diff --git a/test_utils/incite/collections/conftest.py b/test_utils/incite/collections/conftest.py
index 74e4081..88eef72 100644
--- a/test_utils/incite/collections/conftest.py
+++ b/test_utils/incite/collections/conftest.py
@@ -1,5 +1,7 @@
+from __future__ import annotations
+
from datetime import datetime, timedelta
-from typing import TYPE_CHECKING, Callable, Optional
+from typing import TYPE_CHECKING, Callable
import pytest
@@ -21,12 +23,12 @@ if TYPE_CHECKING:
@pytest.fixture
def user_collection(
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
offset: str,
duration: timedelta,
start: datetime,
thl_web_rr: PostgresConfig,
-) -> "UserDFCollection":
+) -> UserDFCollection:
from generalresearch.incite.collections.thl_web import (
DFCollectionType,
UserDFCollection,
@@ -43,12 +45,12 @@ def user_collection(
@pytest.fixture
def wall_collection(
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
offset: str,
duration: timedelta,
start: datetime,
thl_web_rr: PostgresConfig,
-) -> "WallDFCollection":
+) -> WallDFCollection:
from generalresearch.incite.collections.thl_web import (
DFCollectionType,
WallDFCollection,
@@ -65,12 +67,12 @@ def wall_collection(
@pytest.fixture
def session_collection(
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
offset: str,
duration: timedelta,
start: datetime,
thl_web_rr: PostgresConfig,
-) -> "SessionDFCollection":
+) -> SessionDFCollection:
from generalresearch.incite.collections.thl_web import (
DFCollectionType,
SessionDFCollection,
@@ -103,12 +105,12 @@ def session_collection(
@pytest.fixture
def task_adj_collection(
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
offset: str,
- duration: Optional[timedelta],
+ duration: timedelta | None,
start: datetime,
thl_web_rr: PostgresConfig,
-) -> "TaskAdjustmentDFCollection":
+) -> TaskAdjustmentDFCollection:
from generalresearch.incite.collections.thl_web import (
DFCollectionType,
TaskAdjustmentDFCollection,
@@ -127,12 +129,12 @@ def task_adj_collection(
@pytest.fixture
def auditlog_collection(
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
offset: str,
duration: timedelta,
start: datetime,
thl_web_rr: PostgresConfig,
-) -> "AuditLogDFCollection":
+) -> AuditLogDFCollection:
from generalresearch.incite.collections.thl_web import (
AuditLogDFCollection,
DFCollectionType,
@@ -149,12 +151,12 @@ def auditlog_collection(
@pytest.fixture
def ledger_collection(
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
offset: str,
duration: timedelta,
start: datetime,
thl_web_rr: PostgresConfig,
-) -> "LedgerDFCollection":
+) -> LedgerDFCollection:
from generalresearch.incite.collections.thl_web import (
DFCollectionType,
LedgerDFCollection,
@@ -171,7 +173,7 @@ def ledger_collection(
@pytest.fixture
def rm_ledger_collection(
- ledger_collection: "LedgerDFCollection",
+ ledger_collection: LedgerDFCollection,
) -> Callable[..., None]:
def _inner():
@@ -187,13 +189,13 @@ def rm_ledger_collection(
@pytest.fixture
def df_collection(
- mnt_filepath: "GRLDatasets",
- df_collection_data_type: "DFCollectionType",
+ mnt_filepath: GRLDatasets,
+ df_collection_data_type: DFCollectionType,
offset: str,
duration: timedelta,
utc_90days_ago: datetime,
thl_web_rr: PostgresConfig,
-) -> "DFCollection":
+) -> DFCollection:
from generalresearch.incite.collections import DFCollection
start = utc_90days_ago.replace(microsecond=0)
diff --git a/test_utils/incite/conftest.py b/test_utils/incite/conftest.py
index 0e2f7bd..12e57c5 100644
--- a/test_utils/incite/conftest.py
+++ b/test_utils/incite/conftest.py
@@ -1,9 +1,11 @@
+from __future__ import annotations
+
from datetime import datetime, timedelta, timezone
from os.path import join as pjoin
from pathlib import Path
from random import choice as randchoice
from shutil import rmtree
-from typing import TYPE_CHECKING, Callable, Optional
+from typing import TYPE_CHECKING, Callable
from uuid import uuid4
import pytest
@@ -30,7 +32,7 @@ fake = Faker()
@pytest.fixture
-def mnt_gr_api_dir(request: SubRequest, settings: "GRLBaseSettings") -> Path:
+def mnt_gr_api_dir(request: SubRequest, settings: GRLBaseSettings) -> Path:
p = Path(settings.mnt_gr_api_dir)
p.mkdir(parents=True, exist_ok=True)
@@ -53,7 +55,7 @@ def mnt_gr_api_dir(request: SubRequest, settings: "GRLBaseSettings") -> Path:
@pytest.fixture
-def event_report_request(utc_hour_ago: datetime, start: datetime) -> "ReportRequest":
+def event_report_request(utc_hour_ago: datetime, start: datetime) -> ReportRequest:
from generalresearch.models.admin.request import (
ReportRequest,
ReportType,
@@ -69,7 +71,7 @@ def event_report_request(utc_hour_ago: datetime, start: datetime) -> "ReportRequ
@pytest.fixture
-def session_report_request(utc_hour_ago: datetime, start: datetime) -> "ReportRequest":
+def session_report_request(utc_hour_ago: datetime, start: datetime) -> ReportRequest:
from generalresearch.models.admin.request import (
ReportRequest,
ReportType,
@@ -85,7 +87,7 @@ def session_report_request(utc_hour_ago: datetime, start: datetime) -> "ReportRe
@pytest.fixture
-def mnt_filepath(request: SubRequest) -> "GRLDatasets":
+def mnt_filepath(request: SubRequest) -> GRLDatasets:
"""
Creates a temporary file path for all DFCollections &
Mergers parquet files.
@@ -111,7 +113,7 @@ def mnt_filepath(request: SubRequest) -> "GRLDatasets":
@pytest.fixture
-def start(utc_90days_ago: datetime) -> "datetime":
+def start(utc_90days_ago: datetime) -> datetime:
s = utc_90days_ago.replace(microsecond=0)
return s
@@ -122,19 +124,19 @@ def offset() -> str:
@pytest.fixture
-def duration() -> Optional["timedelta"]:
+def duration() -> timedelta | None:
return timedelta(hours=1)
@pytest.fixture
-def df_collection_data_type() -> "DFCollectionType":
+def df_collection_data_type() -> DFCollectionType:
from generalresearch.incite.collections import DFCollectionType
return DFCollectionType.TEST
@pytest.fixture
-def merge_type() -> "MergeType":
+def merge_type() -> MergeType:
from generalresearch.incite.mergers import MergeType
return MergeType.TEST
@@ -142,16 +144,16 @@ def merge_type() -> "MergeType":
@pytest.fixture
def incite_item_factory(
- session_factory: Callable[..., "Session"],
- product: "Product",
- user_factory: Callable[..., "User"],
- session_with_tx_factory: Callable[..., "Session"],
+ session_factory: Callable[..., Session],
+ product: Product,
+ user_factory: Callable[..., User],
+ session_with_tx_factory: Callable[..., Session],
) -> Callable[..., None]:
def _inner(
- item: "DFCollectionItem",
+ item: DFCollectionItem,
observations: int = 3,
- user: Optional["User"] = None,
+ user: User | None = None,
):
from generalresearch.incite.collections import (
DFCollection,
@@ -201,6 +203,4 @@ def incite_item_factory(
case _:
raise ValueError("Unsupported DFCollectionItem")
- return None
-
return _inner
diff --git a/test_utils/incite/mergers/conftest.py b/test_utils/incite/mergers/conftest.py
index d094b84..e9970c2 100644
--- a/test_utils/incite/mergers/conftest.py
+++ b/test_utils/incite/mergers/conftest.py
@@ -1,46 +1,45 @@
+from __future__ import annotations
+
from datetime import datetime, timedelta
-from typing import TYPE_CHECKING, Callable
+from typing import Callable
import pytest
+from generalresearch.incite.base import GRLDatasets
+from generalresearch.incite.mergers import MergeType
+from generalresearch.incite.mergers.foundations.enriched_session import (
+ EnrichedSessionMerge,
+)
+from generalresearch.incite.mergers.foundations.enriched_task_adjust import (
+ EnrichedTaskAdjustMerge,
+)
+from generalresearch.incite.mergers.foundations.enriched_wall import (
+ EnrichedWallMerge,
+)
+from generalresearch.incite.mergers.foundations.user_id_product import (
+ UserIdProductMerge,
+)
+from generalresearch.incite.mergers.pop_ledger import (
+ PopLedgerMerge,
+ PopLedgerMergeItem,
+)
+from generalresearch.incite.mergers.ym_survey_wall import (
+ YMSurveyWallMerge,
+ YMSurveyWallMergeCollectionItem,
+)
+from generalresearch.incite.mergers.ym_wall_summary import (
+ YMWallSummaryMerge,
+ YMWallSummaryMergeItem,
+)
from test_utils.conftest import clear_directory
-if TYPE_CHECKING:
- from generalresearch.incite.base import GRLDatasets
- from generalresearch.incite.mergers import MergeType
- from generalresearch.incite.mergers.foundations.enriched_session import (
- EnrichedSessionMerge,
- )
- from generalresearch.incite.mergers.foundations.enriched_task_adjust import (
- EnrichedTaskAdjustMerge,
- )
- from generalresearch.incite.mergers.foundations.enriched_wall import (
- EnrichedWallMerge,
- )
- from generalresearch.incite.mergers.foundations.user_id_product import (
- UserIdProductMerge,
- )
- from generalresearch.incite.mergers.pop_ledger import (
- PopLedgerMerge,
- PopLedgerMergeItem,
- )
- from generalresearch.incite.mergers.ym_survey_wall import (
- YMSurveyWallMerge,
- YMSurveyWallMergeCollectionItem,
- )
- from generalresearch.incite.mergers.ym_wall_summary import (
- YMWallSummaryMerge,
- YMWallSummaryMergeItem,
- )
-
-
# --------------------------
# Merges
# --------------------------
@pytest.fixture
-def rm_pop_ledger_merge(pop_ledger_merge: "PopLedgerMerge") -> Callable[..., None]:
+def rm_pop_ledger_merge(pop_ledger_merge: PopLedgerMerge) -> Callable[..., None]:
def _inner():
clear_directory(pop_ledger_merge.archive_path)
@@ -50,11 +49,11 @@ def rm_pop_ledger_merge(pop_ledger_merge: "PopLedgerMerge") -> Callable[..., Non
@pytest.fixture
def pop_ledger_merge(
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
offset: str,
start: datetime,
duration: timedelta,
-) -> "PopLedgerMerge":
+) -> PopLedgerMerge:
from generalresearch.incite.mergers import MergeType
from generalresearch.incite.mergers.pop_ledger import PopLedgerMerge
@@ -70,8 +69,8 @@ def pop_ledger_merge(
@pytest.fixture
def pop_ledger_merge_item(
start: datetime,
- pop_ledger_merge: "PopLedgerMerge",
-) -> "PopLedgerMergeItem":
+ pop_ledger_merge: PopLedgerMerge,
+) -> PopLedgerMergeItem:
from generalresearch.incite.mergers.pop_ledger import PopLedgerMergeItem
@@ -83,9 +82,9 @@ def pop_ledger_merge_item(
@pytest.fixture
def ym_survey_wall_merge(
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
start: datetime,
-) -> "YMSurveyWallMerge":
+) -> YMSurveyWallMerge:
from generalresearch.incite.mergers import MergeType
from generalresearch.incite.mergers.ym_survey_wall import YMSurveyWallMerge
@@ -98,8 +97,8 @@ def ym_survey_wall_merge(
@pytest.fixture
def ym_survey_wall_merge_item(
- start: datetime, ym_survey_wall_merge: "YMSurveyWallMerge"
-) -> "YMSurveyWallMergeCollectionItem":
+ start: datetime, ym_survey_wall_merge: YMSurveyWallMerge
+) -> YMSurveyWallMergeCollectionItem:
from generalresearch.incite.mergers.ym_survey_wall import (
YMSurveyWallMergeCollectionItem,
)
@@ -112,11 +111,11 @@ def ym_survey_wall_merge_item(
@pytest.fixture
def ym_wall_summary_merge(
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
offset: str,
duration: timedelta,
start: datetime,
-) -> "YMWallSummaryMerge":
+) -> YMWallSummaryMerge:
from generalresearch.incite.mergers import MergeType
from generalresearch.incite.mergers.ym_wall_summary import YMWallSummaryMerge
@@ -129,8 +128,8 @@ def ym_wall_summary_merge(
def ym_wall_summary_merge_item(
- start: datetime, ym_wall_summary_merge: "YMWallSummaryMerge"
-) -> "YMWallSummaryMergeItem":
+ start: datetime, ym_wall_summary_merge: YMWallSummaryMerge
+) -> YMWallSummaryMergeItem:
from generalresearch.incite.mergers.ym_wall_summary import (
YMWallSummaryMergeItem,
)
@@ -148,11 +147,11 @@ def ym_wall_summary_merge_item(
@pytest.fixture
def enriched_session_merge(
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
offset: str,
duration: timedelta,
start: datetime,
-) -> "EnrichedSessionMerge":
+) -> EnrichedSessionMerge:
from generalresearch.incite.mergers import MergeType
from generalresearch.incite.mergers.foundations.enriched_session import (
EnrichedSessionMerge,
@@ -168,11 +167,11 @@ def enriched_session_merge(
@pytest.fixture
def enriched_task_adjust_merge(
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
offset: str,
duration: timedelta,
start: datetime,
-) -> "EnrichedTaskAdjustMerge":
+) -> EnrichedTaskAdjustMerge:
from generalresearch.incite.mergers import MergeType
from generalresearch.incite.mergers.foundations.enriched_task_adjust import (
EnrichedTaskAdjustMerge,
@@ -190,11 +189,11 @@ def enriched_task_adjust_merge(
@pytest.fixture
def enriched_wall_merge(
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
offset: str,
duration: timedelta,
start: datetime,
-) -> "EnrichedWallMerge":
+) -> EnrichedWallMerge:
from generalresearch.incite.mergers import MergeType
from generalresearch.incite.mergers.foundations.enriched_wall import (
EnrichedWallMerge,
@@ -210,11 +209,11 @@ def enriched_wall_merge(
@pytest.fixture
def user_id_product_merge(
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
duration: timedelta,
offset: str,
start: datetime,
-) -> "UserIdProductMerge":
+) -> UserIdProductMerge:
from generalresearch.incite.mergers import MergeType
from generalresearch.incite.mergers.foundations.user_id_product import (
UserIdProductMerge,
@@ -235,8 +234,8 @@ def user_id_product_merge(
@pytest.fixture
def merge_collection(
- mnt_filepath: "GRLDatasets",
- merge_type: "MergeType",
+ mnt_filepath: GRLDatasets,
+ merge_type: MergeType,
offset: str,
duration: timedelta,
start: datetime,
diff --git a/test_utils/managers/conftest.py b/test_utils/managers/conftest.py
index c8a6e2f..d2e5d20 100644
--- a/test_utils/managers/conftest.py
+++ b/test_utils/managers/conftest.py
@@ -1,9 +1,33 @@
-from typing import TYPE_CHECKING, Callable
+from __future__ import annotations
+
+from typing import Callable
import pytest
-from generalresearch.managers.base import Permission
+from generalresearch.managers.gr.business import (
+ BusinessAddressManager,
+ BusinessBankAccountManager,
+ BusinessManager,
+)
+from generalresearch.managers.gr.team import (
+ MembershipManager,
+ TeamManager,
+)
+from generalresearch.managers.spectrum.survey import SpectrumSurveyManager
+from generalresearch.managers.thl.buyer import BuyerManager
+from generalresearch.managers.thl.ipinfo import (
+ GeoIpInfoManager,
+ IPGeonameManager,
+ IPInformationManager,
+)
+from generalresearch.managers.thl.profiling.uqa import UQAManager
+from generalresearch.managers.thl.userhealth import (
+ AuditLogManager,
+ IPRecordManager,
+ UserIpHistoryManager,
+)
from generalresearch.models import Source
+from generalresearch.models.thl.user import User
from generalresearch.pg_helper import PostgresConfig
from generalresearch.redis_helper import RedisConfig
from generalresearch.sql_helper import SqlHelper
@@ -11,437 +35,11 @@ from test_utils.managers.cashout_methods import (
EXAMPLE_TANGO_CASHOUT_METHODS,
)
-if TYPE_CHECKING:
- from generalresearch.config import GRLBaseSettings
- from generalresearch.grliq.managers.forensic_data import (
- GrlIqDataManager,
- )
- from generalresearch.grliq.managers.forensic_events import (
- GrlIqEventManager,
- )
- from generalresearch.grliq.managers.forensic_results import (
- GrlIqCategoryResultsReader,
- )
- from generalresearch.managers.gr.authentication import (
- GRTokenManager,
- GRUserManager,
- )
- from generalresearch.managers.gr.business import (
- BusinessAddressManager,
- BusinessBankAccountManager,
- BusinessManager,
- )
- from generalresearch.managers.gr.team import (
- MembershipManager,
- TeamManager,
- )
- from generalresearch.managers.thl.buyer import BuyerManager
- from generalresearch.managers.thl.category import CategoryManager
- from generalresearch.managers.thl.contest_manager import ContestManager
- from generalresearch.managers.thl.ipinfo import (
- GeoIpInfoManager,
- IPGeonameManager,
- IPInformationManager,
- )
- from generalresearch.managers.thl.ledger_manager.ledger import (
- LedgerAccountManager,
- LedgerManager,
- LedgerTransactionManager,
- )
- from generalresearch.managers.thl.ledger_manager.thl_ledger import (
- ThlLedgerManager,
- )
- from generalresearch.managers.thl.maxmind import MaxmindManager
- from generalresearch.managers.thl.maxmind.basic import (
- MaxmindBasicManager,
- )
- from generalresearch.managers.thl.payout import (
- BrokerageProductPayoutEventManager,
- BusinessPayoutEventManager,
- PayoutEventManager,
- UserPayoutEventManager,
- )
- from generalresearch.managers.thl.product import ProductManager
- from generalresearch.managers.thl.session import SessionManager
- from generalresearch.managers.thl.task_adjustment import (
- TaskAdjustmentManager,
- )
- from generalresearch.managers.thl.user_manager.user_manager import (
- UserManager,
- )
- from generalresearch.managers.thl.user_manager.user_metadata_manager import (
- UserMetadataManager,
- )
- from generalresearch.managers.thl.userhealth import (
- AuditLogManager,
- IPRecordManager,
- UserIpHistoryManager,
- )
- from generalresearch.managers.thl.wall import (
- WallCacheManager,
- WallManager,
- )
- from generalresearch.models.thl.user import User
-
-
# === THL ===
@pytest.fixture(scope="session")
-def ltxm(
- thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
-) -> "LedgerTransactionManager":
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.ledger_manager.ledger import (
- LedgerTransactionManager,
- )
-
- return LedgerTransactionManager(
- pg_config=thl_web_rw,
- permissions=[Permission.CREATE, Permission.READ],
- testing=True,
- redis_config=thl_redis_config,
- )
-
-
-@pytest.fixture(scope="session")
-def lam(
- thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
-) -> "LedgerAccountManager":
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.ledger_manager.ledger import (
- LedgerAccountManager,
- )
-
- return LedgerAccountManager(
- pg_config=thl_web_rw,
- permissions=[Permission.CREATE, Permission.READ],
- testing=True,
- redis_config=thl_redis_config,
- )
-
-
-@pytest.fixture(scope="session")
-def lm(thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig) -> "LedgerManager":
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.ledger_manager.ledger import (
- LedgerManager,
- )
-
- return LedgerManager(
- pg_config=thl_web_rw,
- permissions=[
- Permission.CREATE,
- Permission.READ,
- Permission.UPDATE,
- Permission.DELETE,
- ],
- testing=True,
- redis_config=thl_redis_config,
- )
-
-
-@pytest.fixture(scope="session")
-def thl_lm(
- thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
-) -> "ThlLedgerManager":
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.ledger_manager.thl_ledger import (
- ThlLedgerManager,
- )
-
- return ThlLedgerManager(
- pg_config=thl_web_rw,
- permissions=[
- Permission.CREATE,
- Permission.READ,
- Permission.UPDATE,
- Permission.DELETE,
- ],
- testing=True,
- redis_config=thl_redis_config,
- )
-
-
-@pytest.fixture(scope="session")
-def payout_event_manager(
- thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
-) -> "PayoutEventManager":
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.payout import PayoutEventManager
-
- return PayoutEventManager(
- pg_config=thl_web_rw,
- permissions=[Permission.CREATE, Permission.READ],
- redis_config=thl_redis_config,
- )
-
-
-@pytest.fixture(scope="session")
-def user_payout_event_manager(
- thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
-) -> "UserPayoutEventManager":
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.payout import UserPayoutEventManager
-
- return UserPayoutEventManager(
- pg_config=thl_web_rw,
- permissions=[Permission.CREATE, Permission.READ],
- redis_config=thl_redis_config,
- )
-
-
-@pytest.fixture(scope="session")
-def brokerage_product_payout_event_manager(
- thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
-) -> "BrokerageProductPayoutEventManager":
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.payout import (
- BrokerageProductPayoutEventManager,
- )
-
- return BrokerageProductPayoutEventManager(
- pg_config=thl_web_rw,
- permissions=[Permission.CREATE, Permission.READ],
- redis_config=thl_redis_config,
- )
-
-
-@pytest.fixture(scope="session")
-def business_payout_event_manager(
- thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
-) -> "BusinessPayoutEventManager":
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.payout import (
- BusinessPayoutEventManager,
- )
-
- return BusinessPayoutEventManager(
- pg_config=thl_web_rw,
- permissions=[Permission.CREATE, Permission.READ],
- redis_config=thl_redis_config,
- )
-
-
-@pytest.fixture(scope="session")
-def product_manager(thl_web_rw: PostgresConfig) -> "ProductManager":
- assert thl_web_rw.dsn
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.product import ProductManager
-
- return ProductManager(pg_config=thl_web_rw)
-
-
-@pytest.fixture(scope="session")
-def user_manager(
- settings: "GRLBaseSettings", thl_web_rw: PostgresConfig, thl_web_rr: PostgresConfig
-) -> "UserManager":
- assert thl_web_rw.dsn
- assert thl_web_rw.dsn.path
- assert thl_web_rr.dsn
- assert thl_web_rr.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rr.dsn.path
-
- from generalresearch.managers.thl.user_manager.user_manager import (
- UserManager,
- )
-
- return UserManager(
- pg_config=thl_web_rw,
- pg_config_rr=thl_web_rr,
- redis=settings.redis,
- )
-
-
-@pytest.fixture(scope="session")
-def user_metadata_manager(thl_web_rw: PostgresConfig) -> "UserMetadataManager":
- assert thl_web_rw.dsn
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.user_manager.user_metadata_manager import (
- UserMetadataManager,
- )
-
- return UserMetadataManager(pg_config=thl_web_rw)
-
-
-@pytest.fixture(scope="session")
-def session_manager(thl_web_rw: PostgresConfig) -> "SessionManager":
- assert thl_web_rw.dsn
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.session import SessionManager
-
- return SessionManager(pg_config=thl_web_rw)
-
-
-@pytest.fixture(scope="session")
-def wall_manager(thl_web_rw: PostgresConfig) -> "WallManager":
- assert thl_web_rw.dsn
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.wall import WallManager
-
- return WallManager(pg_config=thl_web_rw)
-
-
-@pytest.fixture(scope="session")
-def wall_cache_manager(
- thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
-) -> "WallCacheManager":
- # assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.wall import WallCacheManager
-
- return WallCacheManager(pg_config=thl_web_rw, redis_config=thl_redis_config)
-
-
-@pytest.fixture(scope="session")
-def task_adjustment_manager(thl_web_rw: PostgresConfig) -> "TaskAdjustmentManager":
- # assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.task_adjustment import (
- TaskAdjustmentManager,
- )
-
- return TaskAdjustmentManager(pg_config=thl_web_rw)
-
-
-@pytest.fixture(scope="session")
-def contest_manager(thl_web_rw: PostgresConfig) -> "ContestManager":
- assert thl_web_rw.dsn
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.contest_manager import ContestManager
-
- return ContestManager(
- pg_config=thl_web_rw,
- permissions=[
- Permission.CREATE,
- Permission.READ,
- Permission.UPDATE,
- Permission.DELETE,
- ],
- )
-
-
-@pytest.fixture(scope="session")
-def category_manager(thl_web_rw: PostgresConfig) -> "CategoryManager":
- assert thl_web_rw.dsn
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
- from generalresearch.managers.thl.category import CategoryManager
-
- return CategoryManager(pg_config=thl_web_rw)
-
-
-@pytest.fixture(scope="session")
-def buyer_manager(thl_web_rw: PostgresConfig) -> "BuyerManager":
- # assert "/unittest-" in thl_web_rw.dsn.path
- from generalresearch.managers.thl.buyer import BuyerManager
-
- return BuyerManager(pg_config=thl_web_rw)
-
-
-@pytest.fixture(scope="session")
-def survey_manager(thl_web_rw: PostgresConfig):
- # assert "/unittest-" in thl_web_rw.dsn.path
- from generalresearch.managers.thl.survey import SurveyManager
-
- return SurveyManager(pg_config=thl_web_rw)
-
-
-@pytest.fixture(scope="session")
-def surveystat_manager(thl_web_rw: PostgresConfig):
- # assert "/unittest-" in thl_web_rw.dsn.path
- from generalresearch.managers.thl.survey import SurveyStatManager
-
- return SurveyStatManager(pg_config=thl_web_rw)
-
-
-@pytest.fixture(scope="session")
-def surveypenalty_manager(thl_redis_config: RedisConfig):
- from generalresearch.managers.thl.survey_penalty import SurveyPenaltyManager
-
- return SurveyPenaltyManager(redis_config=thl_redis_config)
-
-
-@pytest.fixture(scope="session")
-def upk_schema_manager(thl_web_rw: PostgresConfig):
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
- from generalresearch.managers.thl.profiling.schema import (
- UpkSchemaManager,
- )
-
- return UpkSchemaManager(pg_config=thl_web_rw)
-
-
-@pytest.fixture(scope="session")
-def user_upk_manager(thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig):
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
- from generalresearch.managers.thl.profiling.user_upk import (
- UserUpkManager,
- )
-
- return UserUpkManager(pg_config=thl_web_rw, redis_config=thl_redis_config)
-
-
-@pytest.fixture(scope="session")
-def question_manager(thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig):
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
- from generalresearch.managers.thl.profiling.question import (
- QuestionManager,
- )
-
- return QuestionManager(pg_config=thl_web_rw)
-
-
-@pytest.fixture(scope="session")
-def uqa_manager(thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig):
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
- from generalresearch.managers.thl.profiling.uqa import UQAManager
-
- return UQAManager(redis_config=thl_redis_config, pg_config=thl_web_rw)
-
-
-@pytest.fixture(scope="function")
-def uqa_manager_clear_cache(uqa_manager, user: "User"):
- # On successive py-test/jenkins runs, the cache may contain
- # the previous run's info (keyed under the same user_id)
- uqa_manager.clear_cache(user)
- yield
- uqa_manager.clear_cache(user)
-
-
-@pytest.fixture(scope="session")
-def audit_log_manager(thl_web_rw: PostgresConfig) -> "AuditLogManager":
+def audit_log_manager(thl_web_rw: PostgresConfig) -> AuditLogManager:
assert thl_web_rw.dsn.path
assert "/unittest-" in thl_web_rw.dsn.path
@@ -451,7 +49,7 @@ def audit_log_manager(thl_web_rw: PostgresConfig) -> "AuditLogManager":
@pytest.fixture(scope="session")
-def ip_geoname_manager(thl_web_rw: PostgresConfig) -> "IPGeonameManager":
+def ip_geoname_manager(thl_web_rw: PostgresConfig) -> IPGeonameManager:
assert thl_web_rw.dsn.path
assert "/unittest-" in thl_web_rw.dsn.path
@@ -461,7 +59,7 @@ def ip_geoname_manager(thl_web_rw: PostgresConfig) -> "IPGeonameManager":
@pytest.fixture(scope="session")
-def ip_information_manager(thl_web_rw: PostgresConfig) -> "IPInformationManager":
+def ip_information_manager(thl_web_rw: PostgresConfig) -> IPInformationManager:
assert thl_web_rw.dsn.path
assert "/unittest-" in thl_web_rw.dsn.path
@@ -473,7 +71,7 @@ def ip_information_manager(thl_web_rw: PostgresConfig) -> "IPInformationManager"
@pytest.fixture(scope="session")
def ip_record_manager(
thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
-) -> "IPRecordManager":
+) -> IPRecordManager:
assert thl_web_rw.dsn.path
assert "/unittest-" in thl_web_rw.dsn.path
@@ -485,7 +83,7 @@ def ip_record_manager(
@pytest.fixture(scope="session")
def user_iphistory_manager(
thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
-) -> "UserIpHistoryManager":
+) -> UserIpHistoryManager:
assert thl_web_rw.dsn.path
assert "/unittest-" in thl_web_rw.dsn.path
@@ -508,7 +106,7 @@ def user_iphistory_manager_clear_cache(user_iphistory_manager, user):
@pytest.fixture(scope="session")
def geoipinfo_manager(
thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
-) -> "GeoIpInfoManager":
+) -> GeoIpInfoManager:
assert thl_web_rw.dsn.path
assert "/unittest-" in thl_web_rw.dsn.path
@@ -518,38 +116,6 @@ def geoipinfo_manager(
@pytest.fixture(scope="session")
-def maxmind_basic_manager(settings: "GRLBaseSettings") -> "MaxmindBasicManager":
- from generalresearch.managers.thl.maxmind.basic import (
- MaxmindBasicManager,
- )
-
- return MaxmindBasicManager(
- data_dir="/tmp/",
- maxmind_account_id=settings.maxmind_account_id,
- maxmind_license_key=settings.maxmind_license_key,
- )
-
-
-@pytest.fixture(scope="session")
-def maxmind_manager(
- settings: "GRLBaseSettings",
- thl_web_rw: PostgresConfig,
- thl_redis_config: RedisConfig,
-) -> "MaxmindManager":
- assert thl_web_rw.dsn.path
- assert "/unittest-" in thl_web_rw.dsn.path
-
- from generalresearch.managers.thl.maxmind import MaxmindManager
-
- return MaxmindManager(
- pg_config=thl_web_rw,
- redis_config=thl_redis_config,
- maxmind_account_id=settings.maxmind_account_id,
- maxmind_license_key=settings.maxmind_license_key,
- )
-
-
-@pytest.fixture(scope="session")
def cashout_method_manager(thl_web_rw: PostgresConfig):
assert thl_web_rw.dsn.path
assert "/unittest-" in thl_web_rw.dsn.path
@@ -592,7 +158,6 @@ def uqa_db_index(thl_web_rw: PostgresConfig):
# except pymysql.OperationalError as e:
# if "Duplicate key name 'idx_user_id'" not in str(e):
# raise
- return None
@pytest.fixture(scope="session")
@@ -606,9 +171,7 @@ def delete_cashoutmethod_db(thl_web_rw: PostgresConfig) -> Callable[..., None]:
@pytest.fixture(scope="session")
-def setup_cashoutmethod_db(
- settings: "GRLBaseSettings", cashout_method_manager, delete_cashoutmethod_db
-):
+def setup_cashoutmethod_db(cashout_method_manager, delete_cashoutmethod_db):
delete_cashoutmethod_db()
for x in EXAMPLE_TANGO_CASHOUT_METHODS:
cashout_method_manager.create(x)
@@ -621,14 +184,12 @@ def setup_cashoutmethod_db(
# cashout_method_manager.create(AMT_BONUS_CASHOUT_METHOD)
raise NotImplementedError("Need to implement setup_cashoutmethod_db")
- return None
-
# === THL: Marketplaces ===
@pytest.fixture(scope="session")
-def spectrum_manager(spectrum_rw: SqlHelper) -> "SpectrumSurveyManager":
+def spectrum_manager(spectrum_rw: SqlHelper) -> SpectrumSurveyManager:
from generalresearch.managers.spectrum.survey import (
SpectrumSurveyManager,
)
@@ -640,7 +201,7 @@ def spectrum_manager(spectrum_rw: SqlHelper) -> "SpectrumSurveyManager":
@pytest.fixture(scope="session")
def business_manager(
gr_db: PostgresConfig, gr_redis_config: RedisConfig
-) -> "BusinessManager":
+) -> BusinessManager:
from generalresearch.redis_helper import RedisConfig
assert gr_db.dsn.path
@@ -656,7 +217,7 @@ def business_manager(
@pytest.fixture(scope="session")
-def business_address_manager(gr_db: PostgresConfig) -> "BusinessAddressManager":
+def business_address_manager(gr_db: PostgresConfig) -> BusinessAddressManager:
assert gr_db.dsn.path
assert "/unittest-" in gr_db.dsn.path
@@ -668,7 +229,7 @@ def business_address_manager(gr_db: PostgresConfig) -> "BusinessAddressManager":
@pytest.fixture(scope="session")
def business_bank_account_manager(
gr_db: PostgresConfig,
-) -> "BusinessBankAccountManager":
+) -> BusinessBankAccountManager:
assert gr_db.dsn.path
assert "/unittest-" in gr_db.dsn.path
@@ -680,7 +241,7 @@ def business_bank_account_manager(
@pytest.fixture(scope="session")
-def team_manager(gr_db: PostgresConfig, gr_redis_config: RedisConfig) -> "TeamManager":
+def team_manager(gr_db: PostgresConfig, gr_redis_config: RedisConfig) -> TeamManager:
assert gr_db.dsn.path
assert "/unittest-" in gr_db.dsn.path
@@ -690,27 +251,7 @@ def team_manager(gr_db: PostgresConfig, gr_redis_config: RedisConfig) -> "TeamMa
@pytest.fixture(scope="session")
-def gr_um(gr_db: PostgresConfig, gr_redis_config: RedisConfig) -> "GRUserManager":
- assert gr_db.dsn.path
- assert "/unittest-" in gr_db.dsn.path
-
- from generalresearch.managers.gr.authentication import GRUserManager
-
- return GRUserManager(pg_config=gr_db, redis_config=gr_redis_config)
-
-
-@pytest.fixture(scope="session")
-def gr_tm(gr_db: PostgresConfig) -> "GRTokenManager":
- assert gr_db.dsn.path
- assert "/unittest-" in gr_db.dsn.path
-
- from generalresearch.managers.gr.authentication import GRTokenManager
-
- return GRTokenManager(pg_config=gr_db)
-
-
-@pytest.fixture(scope="session")
-def membership_manager(gr_db: PostgresConfig) -> "MembershipManager":
+def membership_manager(gr_db: PostgresConfig) -> MembershipManager:
assert gr_db.dsn.path
assert "/unittest-" in gr_db.dsn.path
@@ -719,47 +260,8 @@ def membership_manager(gr_db: PostgresConfig) -> "MembershipManager":
return MembershipManager(pg_config=gr_db)
-# === GRL IQ ===
-
-
-@pytest.fixture(scope="session")
-def grliq_dm(grliq_db: PostgresConfig) -> "GrlIqDataManager":
- assert grliq_db.dsn.path
- assert "/unittest-" in grliq_db.dsn.path
-
- from generalresearch.grliq.managers.forensic_data import (
- GrlIqDataManager,
- )
-
- return GrlIqDataManager(postgres_config=grliq_db)
-
-
-@pytest.fixture(scope="session")
-def grliq_em(grliq_db: PostgresConfig) -> "GrlIqEventManager":
- assert grliq_db.dsn.path
- assert "/unittest-" in grliq_db.dsn.path
-
- from generalresearch.grliq.managers.forensic_events import (
- GrlIqEventManager,
- )
-
- return GrlIqEventManager(postgres_config=grliq_db)
-
-
-@pytest.fixture(scope="session")
-def grliq_crr(grliq_db: PostgresConfig) -> "GrlIqCategoryResultsReader":
- assert grliq_db.dsn.path
- assert "/unittest-" in grliq_db.dsn.path
-
- from generalresearch.grliq.managers.forensic_results import (
- GrlIqCategoryResultsReader,
- )
-
- return GrlIqCategoryResultsReader(postgres_config=grliq_db)
-
-
@pytest.fixture(scope="session")
-def delete_buyers_surveys(thl_web_rw: PostgresConfig, buyer_manager: "BuyerManager"):
+def delete_buyers_surveys(thl_web_rw: PostgresConfig, buyer_manager: BuyerManager):
# assert "/unittest-" in thl_web_rw.dsn.path
thl_web_rw.execute_write(
"""
diff --git a/test_utils/managers/contest/conftest.py b/test_utils/managers/contest/conftest.py
index fb0b44b..67935e7 100644
--- a/test_utils/managers/contest/conftest.py
+++ b/test_utils/managers/contest/conftest.py
@@ -1,286 +1,24 @@
-from datetime import datetime, timezone
-from decimal import Decimal
-from typing import TYPE_CHECKING, Callable
-from uuid import uuid4
-
import pytest
-from generalresearch.currency import USDCent
-
-if TYPE_CHECKING:
- from generalresearch.managers.thl.contest_manager import ContestManager
- from generalresearch.managers.thl.ledger_manager.thl_ledger import ThlLedgerManager
- from generalresearch.models.thl.contest.contest import Contest
- from generalresearch.models.thl.contest.leaderboard import (
- LeaderboardContestCreate,
- )
- from generalresearch.models.thl.contest.milestone import (
- MilestoneContestCreate,
- )
- from generalresearch.models.thl.contest.raffle import (
- RaffleContestCreate,
- )
- from generalresearch.models.thl.product import Product
- from generalresearch.models.thl.user import User
-
-
-@pytest.fixture
-def raffle_contest_create() -> "RaffleContestCreate":
- from generalresearch.models.thl.contest import (
- ContestEndCondition,
- ContestPrize,
- )
- from generalresearch.models.thl.contest.definitions import (
- ContestPrizeKind,
- ContestType,
- )
- from generalresearch.models.thl.contest.raffle import (
- ContestEntryType,
- RaffleContestCreate,
- )
-
- # This is what we'll get from the fastapi endpoint
- return RaffleContestCreate(
- name="test",
- contest_type=ContestType.RAFFLE,
- entry_type=ContestEntryType.CASH,
- prizes=[
- ContestPrize(
- name="iPod 64GB White",
- kind=ContestPrizeKind.PHYSICAL,
- estimated_cash_value=USDCent(100),
- )
- ],
- end_condition=ContestEndCondition(target_entry_amount=USDCent(100)),
- )
-
-
-@pytest.fixture
-def raffle_contest_in_db(
- product_user_wallet_yes: "Product",
- raffle_contest_create: "RaffleContestCreate",
- contest_manager: "ContestManager",
-) -> "Contest":
- return contest_manager.create(
- product_id=product_user_wallet_yes.uuid, contest_create=raffle_contest_create
- )
-
-
-@pytest.fixture
-def raffle_contest(
- product_user_wallet_yes: "Product", raffle_contest_create: "RaffleContestCreate"
-) -> "Contest":
- from generalresearch.models.thl.contest.io import contest_create_to_contest
-
- return contest_create_to_contest(
- product_id=product_user_wallet_yes.uuid, contest_create=raffle_contest_create
- )
-
-
-@pytest.fixture(scope="function")
-def raffle_contest_factory(
- product_user_wallet_yes: "Product",
- raffle_contest_create: "RaffleContestCreate",
- contest_manager: "ContestManager",
-) -> Callable[..., "Contest"]:
-
- def _inner(**kwargs):
- raffle_contest_create.update(**kwargs)
- return contest_manager.create(
- product_id=product_user_wallet_yes.uuid,
- contest_create=raffle_contest_create,
- )
+from generalresearch.managers.base import Permission
+from generalresearch.managers.thl.contest_manager import ContestManager
+from generalresearch.pg_helper import PostgresConfig
- return _inner
-
-
-@pytest.fixture
-def milestone_contest_create() -> "MilestoneContestCreate":
- from generalresearch.models.thl.contest import (
- ContestPrize,
- )
- from generalresearch.models.thl.contest.definitions import (
- ContestPrizeKind,
- ContestType,
- )
- from generalresearch.models.thl.contest.milestone import (
- ContestEntryTrigger,
- MilestoneContestCreate,
- MilestoneContestEndCondition,
- )
-
- # This is what we'll get from the fastapi endpoint
- return MilestoneContestCreate(
- name="Win a 50% bonus for 7 days and a $1 bonus after your first 3 completes!",
- description="only valid for the first 5 users",
- contest_type=ContestType.MILESTONE,
- prizes=[
- ContestPrize(
- name="50% for 7 days",
- kind=ContestPrizeKind.PROMOTION,
- estimated_cash_value=USDCent(0),
- ),
- ContestPrize(
- name="$1 Bonus",
- kind=ContestPrizeKind.CASH,
- cash_amount=USDCent(1_00),
- estimated_cash_value=USDCent(1_00),
- ),
- ],
- end_condition=MilestoneContestEndCondition(
- ends_at=datetime(year=2030, month=1, day=1, tzinfo=timezone.utc),
- max_winners=5,
- ),
- entry_trigger=ContestEntryTrigger.TASK_COMPLETE,
- target_amount=3,
- )
+@pytest.fixture(scope="session")
+def contest_manager(thl_web_rw: PostgresConfig) -> ContestManager:
+ assert thl_web_rw.dsn
+ assert thl_web_rw.dsn.path
+ assert "/unittest-" in thl_web_rw.dsn.path
-@pytest.fixture
-def milestone_contest_in_db(
- product_user_wallet_yes: "Product",
- milestone_contest_create: "MilestoneContestCreate",
- contest_manager: "ContestManager",
-) -> "Contest":
- return contest_manager.create(
- product_id=product_user_wallet_yes.uuid, contest_create=milestone_contest_create
- )
-
-
-@pytest.fixture
-def milestone_contest(
- product_user_wallet_yes: "Product",
- milestone_contest_create: "MilestoneContestCreate",
-) -> "Contest":
- from generalresearch.models.thl.contest.io import contest_create_to_contest
-
- return contest_create_to_contest(
- product_id=product_user_wallet_yes.uuid, contest_create=milestone_contest_create
- )
-
-
-@pytest.fixture(scope="function")
-def milestone_contest_factory(
- product_user_wallet_yes: "Product",
- milestone_contest_create: "MilestoneContestCreate",
- contest_manager: "ContestManager",
-) -> Callable[..., "Contest"]:
-
- def _inner(**kwargs):
- milestone_contest_create.update(**kwargs)
- return contest_manager.create(
- product_id=product_user_wallet_yes.uuid,
- contest_create=milestone_contest_create,
- )
-
- return _inner
-
-
-@pytest.fixture
-def leaderboard_contest_create(
- product_user_wallet_yes: "Product",
-) -> "LeaderboardContestCreate":
- from generalresearch.models.thl.contest import (
- ContestPrize,
- )
- from generalresearch.models.thl.contest.definitions import (
- ContestPrizeKind,
- ContestType,
- )
- from generalresearch.models.thl.contest.leaderboard import (
- LeaderboardContestCreate,
- )
+ from generalresearch.managers.thl.contest_manager import ContestManager
- # This is what we'll get from the fastapi endpoint
- return LeaderboardContestCreate(
- name="test",
- contest_type=ContestType.LEADERBOARD,
- prizes=[
- ContestPrize(
- name="$15 Cash",
- estimated_cash_value=USDCent(15_00),
- cash_amount=USDCent(15_00),
- kind=ContestPrizeKind.CASH,
- leaderboard_rank=1,
- ),
- ContestPrize(
- name="$10 Cash",
- estimated_cash_value=USDCent(10_00),
- cash_amount=USDCent(10_00),
- kind=ContestPrizeKind.CASH,
- leaderboard_rank=2,
- ),
+ return ContestManager(
+ pg_config=thl_web_rw,
+ permissions=[
+ Permission.CREATE,
+ Permission.READ,
+ Permission.UPDATE,
+ Permission.DELETE,
],
- leaderboard_key=f"leaderboard:{product_user_wallet_yes.uuid}:us:daily:2025-01-01:complete_count",
)
-
-
-@pytest.fixture
-def leaderboard_contest_in_db(
- product_user_wallet_yes: "Product",
- leaderboard_contest_create: "LeaderboardContestCreate",
- contest_manager: "ContestManager",
-) -> "Contest":
- return contest_manager.create(
- product_id=product_user_wallet_yes.uuid,
- contest_create=leaderboard_contest_create,
- )
-
-
-@pytest.fixture
-def leaderboard_contest(
- product_user_wallet_yes: "Product",
- leaderboard_contest_create: "LeaderboardContestCreate",
-):
- from generalresearch.models.thl.contest.io import contest_create_to_contest
-
- return contest_create_to_contest(
- product_id=product_user_wallet_yes.uuid,
- contest_create=leaderboard_contest_create,
- )
-
-
-@pytest.fixture(scope="function")
-def leaderboard_contest_factory(
- product_user_wallet_yes: "Product",
- leaderboard_contest_create: "LeaderboardContestCreate",
- contest_manager: "ContestManager",
-) -> Callable[..., "Contest"]:
-
- def _inner(**kwargs):
- leaderboard_contest_create.update(**kwargs)
- return contest_manager.create(
- product_id=product_user_wallet_yes.uuid,
- contest_create=leaderboard_contest_create,
- )
-
- return _inner
-
-
-@pytest.fixture
-def user_with_money(
- request,
- user_factory: Callable[..., "User"],
- product_user_wallet_yes: "Product",
- thl_lm: "ThlLedgerManager",
-) -> "User":
- from generalresearch.models.thl.user import User
-
- params = getattr(request, "param", dict()) or {}
- min_balance = int(params.get("min_balance", USDCent(1_00)))
-
- user: User = user_factory(product=product_user_wallet_yes)
- wallet = thl_lm.get_account_or_create_user_wallet(user)
- balance = thl_lm.get_account_balance(wallet)
- todo = min_balance - balance
- if todo > 0:
- # # Put money in user's wallet
- thl_lm.create_tx_user_bonus(
- user=user,
- ref_uuid=uuid4().hex,
- description="bonus",
- amount=Decimal(todo) / 100,
- )
- print(f"wallet balance: {thl_lm.get_user_wallet_balance(user=user)}")
-
- return user
diff --git a/test_utils/managers/gr/conftest.py b/test_utils/managers/gr/conftest.py
index 3e3a4ad..37da164 100644
--- a/test_utils/managers/gr/conftest.py
+++ b/test_utils/managers/gr/conftest.py
@@ -1,151 +1,110 @@
from __future__ import annotations
from typing import Callable
-from uuid import uuid4
import pytest
-from pydantic import PositiveInt
-from pydantic_extra_types.phone_numbers import PhoneNumber
+import redis.asyncio as redis_async
+from pydantic import PostgresDsn
+from redis import Redis
-from generalresearch.managers.gr.authentication import GRUserManager
+from generalresearch.config import GRLBaseSettings
+from generalresearch.managers.gr.authentication import GRTokenManager, GRUserManager
from generalresearch.managers.gr.business import (
BusinessAddressManager,
BusinessBankAccountManager,
BusinessManager,
)
-from generalresearch.managers.gr.team import TeamManager
-from generalresearch.models.custom_types import UUIDStr
-from generalresearch.models.gr.authentication import GRUser
-from generalresearch.models.gr.business import (
- Business,
- BusinessAddress,
- BusinessBankAccount,
- BusinessType,
- TransferMethod,
-)
-from generalresearch.models.gr.team import Team
+from generalresearch.pg_helper import PostgresConfig
+from generalresearch.redis_helper import RedisConfig
+
+
+# === Msc ===
+@pytest.fixture(scope="session")
+def gr_redis(settings: GRLBaseSettings) -> Redis:
+ assert "unittest" in str(settings.gr_redis) or "127.0.0.1" in str(settings.gr_redis)
+ return Redis.from_url(
+ url=str(settings.gr_redis),
+ decode_responses=True,
+ socket_timeout=settings.redis_timeout,
+ socket_connect_timeout=settings.redis_timeout,
+ )
@pytest.fixture
-def gr_user_factory(gr_um: GRUserManager) -> Callable[..., GRUser]:
+def gr_redis_async(settings: GRLBaseSettings) -> redis_async.Redis:
+ assert "unittest" in str(settings.gr_redis) or "127.0.0.1" in str(settings.gr_redis)
- def _inner(
- sub: str | None = None,
- is_superuser: bool = False,
- ) -> GRUser:
- sub = sub or f"{uuid4().hex}-{uuid4().hex}"
+ return redis_async.Redis.from_url(
+ str(settings.gr_redis),
+ decode_responses=True,
+ socket_timeout=0.20,
+ socket_connect_timeout=0.20,
+ )
- return gr_um.create(
- sub=sub,
- is_superuser=is_superuser,
- )
- return _inner
+@pytest.fixture(scope="session")
+def gr_redis_config(settings: GRLBaseSettings) -> RedisConfig:
+ assert "unittest" in str(settings.gr_redis) or "127.0.0.1" in str(settings.gr_redis)
+ return RedisConfig(
+ dsn=settings.gr_redis,
+ decode_responses=True,
+ socket_timeout=settings.redis_timeout,
+ socket_connect_timeout=settings.redis_timeout,
+ )
-@pytest.fixture
-def gr_business_bank_account_factory(
- gr_bbam: BusinessBankAccountManager,
-) -> Callable[..., BusinessBankAccount]:
-
- def _inner(
- business_id: PositiveInt,
- uuid: UUIDStr | None = None,
- transfer_method: TransferMethod | None = None,
- account_number: str | None = None,
- routing_number: str | None = None,
- iban: str | None = None,
- swift: str | None = None,
- ):
- from generalresearch.models.gr.business import TransferMethod
-
- return gr_bbam.create(
- business_id=business_id,
- uuid=uuid or uuid4().hex,
- transfer_method=transfer_method or TransferMethod.ACH,
- account_number=account_number or uuid4().hex[:6],
- routing_number=routing_number or uuid4().hex[:6],
- iban=iban or uuid4().hex[:6],
- swift=swift or uuid4().hex[:6],
- )
-
- return _inner
+@pytest.fixture(scope="session")
+def gr_db(django_db_factory: Callable[..., PostgresDsn]) -> PostgresConfig:
-@pytest.fixture
-def gr_business_address_factory(
- gr_bam: BusinessAddressManager,
-) -> Callable[..., BusinessAddress]:
-
- def _inner(
- business_id: PositiveInt,
- uuid: UUIDStr | None = None,
- line_1: str | None = None,
- line_2: str | None = None,
- city: str | None = None,
- state: str | None = None,
- postal_code: str | None = None,
- phone_number: PhoneNumber | None = None,
- country: str | None = None,
- ):
- uuid = uuid or uuid4().hex
- line_1 = line_1 or "abc"
- line_2 = line_2 or "bczx"
- city = city or "Downingtown"
- state = state or "CA"
- postal_code = postal_code or "94041"
- phone_number = None
- country = country or "US"
-
- return gr_bam.create(
- business_id=business_id,
- uuid=uuid,
- line_1=line_1,
- line_2=line_2,
- city=city,
- state=state,
- postal_code=postal_code,
- phone_number=phone_number,
- country=country,
- )
-
- return _inner
+ return PostgresConfig(
+ dsn=django_db_factory("gr_carer"),
+ connect_timeout=1,
+ statement_timeout=5,
+ )
-@pytest.fixture
-def gr_business_factory(
- gr_bm: BusinessManager,
-) -> Callable[..., Business]:
+# === Managers ===
- def _inner(
- uuid: UUIDStr | None = None,
- name: str | None = None,
- team: Team | None = None,
- kind: BusinessType | None = None,
- tax_number: str | None = None,
- ) -> Business:
- from random import randint
- uuid = uuid or uuid4().hex
- name = name or "< Unknown >"
- tax_number = tax_number or str(randint(1, 999_999_999))
+@pytest.fixture(scope="session")
+def gr_user_manager(
+ gr_db: PostgresConfig, gr_redis_config: RedisConfig
+) -> GRUserManager:
+ assert gr_db.dsn.path
+ assert "/unittest-" in gr_db.dsn.path
- return gr_bm.create(
- uuid=uuid, name=name, team=team, kind=kind, tax_number=tax_number
- )
+ from generalresearch.managers.gr.authentication import GRUserManager
- return _inner
+ return GRUserManager(pg_config=gr_db, redis_config=gr_redis_config)
-@pytest.fixture
-def gr_team(
- gr_tm: TeamManager,
-) -> Callable[..., Team]:
+@pytest.fixture(scope="session")
+def gr_team_manager(gr_db: PostgresConfig) -> GRTokenManager:
+ assert gr_db.dsn.path
+ assert "/unittest-" in gr_db.dsn.path
+
+ from generalresearch.managers.gr.authentication import GRTokenManager
+
+ return GRTokenManager(pg_config=gr_db)
+
+
+@pytest.fixture(scope="session")
+def gr_business_manager(
+ gr_db: PostgresConfig, gr_redis_config: RedisConfig
+) -> BusinessManager:
+ return BusinessManager(pg_config=gr_db, redis_config=gr_redis_config)
+
- def _inner(uuid: UUIDStr | None = None, name: str | None = None) -> Team:
- uuid = uuid or uuid4().hex
- name = name or f"name-{uuid4().hex[:12]}"
+@pytest.fixture(scope="session")
+def gr_business_bank_account_manager(
+ gr_db: PostgresConfig,
+) -> BusinessBankAccountManager:
+ return BusinessBankAccountManager(pg_config=gr_db)
- return gr_tm.create(uuid=uuid, name=name)
- return _inner
+@pytest.fixture(scope="session")
+def gr_business_address_manager(
+ gr_db: PostgresConfig,
+) -> BusinessAddressManager:
+ return BusinessAddressManager(pg_config=gr_db)
diff --git a/test_utils/managers/grliq/conftest.py b/test_utils/managers/grliq/conftest.py
deleted file mode 100644
index 525d8c8..0000000
--- a/test_utils/managers/grliq/conftest.py
+++ /dev/null
@@ -1,61 +0,0 @@
-from __future__ import annotations
-
-from datetime import datetime, timezone
-from typing import Callable
-from uuid import uuid4
-
-import pytest
-
-from generalresearch.grliq.managers import DUMMY_GRLIQ_DATA
-from generalresearch.grliq.managers.forensic_data import GrlIqDataManager
-from generalresearch.grliq.models.forensic_data import GrlIqData
-
-
-@pytest.fixture
-def grliq_data_factory(grliq_dm: GrlIqDataManager) -> Callable[..., GrlIqData]:
-
- def _inner(
- is_attempt_allowed: bool = True,
- product_id: str | None = None,
- product_user_id: str | None = None,
- uuid: str | None = None,
- mid: str | None = None,
- created_at: datetime | None = None,
- ) -> GrlIqData:
- """
- Creates a dummy record in the db with a GrlIqData (data), GrlIqCheckerResults (result_data),
- and GrlIqForensicCategoryResult (category_results)
- :param is_attempt_allowed: Whether the attempt is allowed.
- :param product_id: product_id of user
- :param product_user_id: product_user_id of user
- :param uuid: uuid for the grliq data record
- :param mid: the thl_session:uuid / mid for the attempt.
- :return:
- """
- import copy
-
- res: GrlIqData = copy.deepcopy(DUMMY_GRLIQ_DATA[int(is_attempt_allowed)])
-
- product_id = product_id or uuid4().hex
- product_user_id = product_user_id or uuid4().hex
- uuid = uuid or uuid4().hex
- mid = mid or uuid4().hex
- created_at = created_at or datetime.now(tz=timezone.utc)
-
- res["data"].product_id = product_id
- res["data"].product_user_id = product_user_id
- res["data"].uuid = uuid
- res["data"].mid = mid
- res["data"].created_at = created_at
- res["result_data"].uuid = uuid
- res["category_result"].uuid = uuid
-
- return grliq_dm.create(
- iq_data=res["data"],
- result_data=res["result_data"],
- category_result=res["category_result"],
- fraud_score=res["category_result"].fraud_score,
- is_attempt_allowed=res["category_result"].is_attempt_allowed(),
- )
-
- return _inner
diff --git a/test_utils/managers/ledger/conftest.py b/test_utils/managers/ledger/conftest.py
index 0aa6cb3..ce8348e 100644
--- a/test_utils/managers/ledger/conftest.py
+++ b/test_utils/managers/ledger/conftest.py
@@ -1,740 +1,94 @@
-from datetime import datetime
-from decimal import Decimal
-from random import randint
-from typing import TYPE_CHECKING, Callable, Dict, Optional
-from uuid import uuid4
+from __future__ import annotations
import pytest
-from generalresearch.currency import USDCent
-from generalresearch.managers.base import PostgresManager
-from test_utils.models.conftest import (
- payout_config,
- product_amt_true,
- product_user_wallet_no,
- product_user_wallet_yes,
- session,
- session_factory,
- user_factory,
- wall,
- wall_factory,
+from generalresearch.managers.base import Permission
+from generalresearch.managers.thl.ledger_manager.ledger import (
+ LedgerAccountManager,
+ LedgerManager,
+ LedgerTransactionManager,
)
-
-_ = (
- user_factory,
- product_user_wallet_no,
- wall,
- product_amt_true,
- product_user_wallet_yes,
- session_factory,
- session,
- wall_factory,
- payout_config,
+from generalresearch.managers.thl.ledger_manager.thl_ledger import (
+ ThlLedgerManager,
)
+from generalresearch.pg_helper import PostgresConfig
+from generalresearch.redis_helper import RedisConfig
-if TYPE_CHECKING:
-
- from generalresearch.currency import LedgerCurrency
- from generalresearch.managers.thl.ledger_manager.ledger import LedgerManager
- from generalresearch.managers.thl.ledger_manager.thl_ledger import (
- ThlLedgerManager,
- )
- from generalresearch.managers.thl.payout import (
- BrokerageProductPayoutEventManager,
- BusinessPayoutEventManager,
- )
- from generalresearch.managers.thl.session import SessionManager
- from generalresearch.managers.thl.wall import WallManager
- from generalresearch.models.thl.ledger import (
- LedgerAccount,
- LedgerTransaction,
- )
- from generalresearch.models.thl.payout import (
- BrokerageProductPayoutEvent,
- )
- from generalresearch.models.thl.product import Product
- from generalresearch.models.thl.session import Session
- from generalresearch.models.thl.user import User
-
-
-@pytest.fixture
-def ledger_account(
- request, lm: "LedgerManager", currency: "LedgerCurrency"
-) -> "LedgerAccount":
- from generalresearch.models.thl.ledger import (
- AccountType,
- Direction,
- LedgerAccount,
- )
+# --- Ledger ---
- account_type = getattr(request, "account_type", AccountType.CASH)
- direction = getattr(request, "direction", Direction.CREDIT)
- acct_uuid = uuid4().hex
- qn = ":".join([currency, account_type, acct_uuid])
+@pytest.fixture(scope="session")
+def ledger_manager(
+ thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
+) -> LedgerManager:
- acct_model = LedgerAccount(
- uuid=acct_uuid,
- display_name=f"test-{acct_uuid}",
- currency=currency,
- qualified_name=qn,
- account_type=account_type,
- normal_balance=direction,
+ return LedgerManager(
+ pg_config=thl_web_rw,
+ permissions=[
+ Permission.CREATE,
+ Permission.READ,
+ Permission.UPDATE,
+ Permission.DELETE,
+ ],
+ testing=True,
+ redis_config=thl_redis_config,
)
- return lm.create_account(account=acct_model)
-
-
-@pytest.fixture
-def ledger_account_factory(
- request, thl_lm: "ThlLedgerManager", lm: "LedgerManager", currency: "LedgerCurrency"
-) -> Callable[..., "LedgerAccount"]:
-
- from generalresearch.models.thl.ledger import (
- AccountType,
- Direction,
- LedgerAccount,
- )
-
- def _inner(
- product: "Product",
- account_type: AccountType = AccountType.CASH,
- direction: Direction = Direction.CREDIT,
- ) -> "LedgerAccount":
- thl_lm.get_account_or_create_bp_wallet(product=product)
- acct_uuid = uuid4().hex
- qn = ":".join([currency, account_type, acct_uuid])
-
- acct_model = LedgerAccount(
- uuid=acct_uuid,
- display_name=f"test-{acct_uuid}",
- currency=currency,
- qualified_name=qn,
- account_type=account_type,
- normal_balance=direction,
- )
- return lm.create_account(account=acct_model)
-
- return _inner
-
-@pytest.fixture
-def ledger_account_credit(
- request, lm: "LedgerManager", currency: "LedgerCurrency"
-) -> "LedgerAccount":
- from generalresearch.models.thl.ledger import AccountType, Direction
- account_type = AccountType.REVENUE
- acct_uuid = uuid4().hex
+@pytest.fixture(scope="session")
+def ledger_tx_manager(
+ thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
+) -> LedgerTransactionManager:
+ assert thl_web_rw.dsn.path
+ assert "/unittest-" in thl_web_rw.dsn.path
- qn = ":".join([currency, account_type, acct_uuid])
- from generalresearch.models.thl.ledger import LedgerAccount
-
- acct_model = LedgerAccount(
- uuid=acct_uuid,
- display_name=f"test-{acct_uuid}",
- currency=currency,
- qualified_name=qn,
- account_type=account_type,
- normal_balance=Direction.CREDIT,
+ from generalresearch.managers.thl.ledger_manager.ledger import (
+ LedgerTransactionManager,
)
- return lm.create_account(account=acct_model)
-
-
-@pytest.fixture
-def ledger_account_debit(
- request, lm: "LedgerManager", currency: "LedgerCurrency"
-) -> "LedgerAccount":
- from generalresearch.models.thl.ledger import AccountType, Direction
-
- account_type = AccountType.EXPENSE
- acct_uuid = uuid4().hex
-
- qn = ":".join([currency, account_type, acct_uuid])
- from generalresearch.models.thl.ledger import LedgerAccount
- acct_model = LedgerAccount(
- uuid=acct_uuid,
- display_name=f"test-{acct_uuid}",
- currency=currency,
- qualified_name=qn,
- account_type=account_type,
- normal_balance=Direction.DEBIT,
+ return LedgerTransactionManager(
+ pg_config=thl_web_rw,
+ permissions=[Permission.CREATE, Permission.READ],
+ testing=True,
+ redis_config=thl_redis_config,
)
- return lm.create_account(account=acct_model)
-@pytest.fixture
-def tag(request, lm: "LedgerManager") -> str:
- from generalresearch.currency import LedgerCurrency
+@pytest.fixture(scope="session")
+def ledger_account_manager(
+ thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
+) -> LedgerAccountManager:
+ assert thl_web_rw.dsn.path
+ assert "/unittest-" in thl_web_rw.dsn.path
- return (
- request.param
- if hasattr(request, "tag")
- else f"{LedgerCurrency.TEST}:{uuid4().hex}"
+ from generalresearch.managers.thl.ledger_manager.ledger import (
+ LedgerAccountManager,
)
-
-@pytest.fixture
-def usd_cent(request) -> USDCent:
- amount = randint(99, 9_999)
- return request.param if hasattr(request, "usd_cent") else USDCent(amount)
-
-
-@pytest.fixture
-def bp_payout_event(
- product: "Product",
- usd_cent: "USDCent",
- business_payout_event_manager: "BusinessPayoutEventManager",
- thl_lm: "ThlLedgerManager",
-) -> "BrokerageProductPayoutEvent":
-
- return business_payout_event_manager.create_bp_payout_event(
- thl_ledger_manager=thl_lm,
- product=product,
- amount=usd_cent,
- skip_wallet_balance_check=True,
- skip_one_per_day_check=True,
+ return LedgerAccountManager(
+ pg_config=thl_web_rw,
+ permissions=[Permission.CREATE, Permission.READ],
+ testing=True,
+ redis_config=thl_redis_config,
)
-@pytest.fixture
-def bp_payout_event_factory(
- brokerage_product_payout_event_manager: "BrokerageProductPayoutEventManager",
- thl_lm: "ThlLedgerManager",
-) -> Callable[..., "BrokerageProductPayoutEvent"]:
+# --- THL Ledger ---
- from generalresearch.currency import USDCent
- from generalresearch.models.thl.product import Product
-
- def _inner(
- product: Product, usd_cent: USDCent, ext_ref_id: Optional[str] = None
- ) -> "BrokerageProductPayoutEvent":
-
- return brokerage_product_payout_event_manager.create_bp_payout_event(
- thl_ledger_manager=thl_lm,
- product=product,
- amount=usd_cent,
- ext_ref_id=ext_ref_id,
- skip_wallet_balance_check=True,
- skip_one_per_day_check=True,
- )
-
- return _inner
-
-
-@pytest.fixture
-def currency(lm: "LedgerManager") -> "LedgerCurrency":
- # return request.param if hasattr(request, "currency") else LedgerCurrency.TEST
- assert lm.currency, "LedgerManager must have a currency specified for these tests"
- return lm.currency
-
-
-@pytest.fixture
-def tx_metadata(request) -> Optional[Dict[str, str]]:
- return (
- request.param
- if hasattr(request, "tx_metadata")
- else {f"key-{uuid4().hex[:10]}": uuid4().hex}
- )
-
-
-@pytest.fixture
-def ledger_tx(
- request,
- ledger_account_credit: "LedgerAccount",
- ledger_account_debit: "LedgerAccount",
- tag: str,
- currency: "LedgerCurrency",
- tx_metadata: Optional[Dict[str, str]],
- lm: "LedgerManager",
-) -> "LedgerTransaction":
- from generalresearch.models.thl.ledger import Direction, LedgerEntry
-
- amount = int(Decimal("1.00") * 100)
-
- entries = [
- LedgerEntry(
- direction=Direction.CREDIT,
- account_uuid=ledger_account_credit.uuid,
- amount=amount,
- ),
- LedgerEntry(
- direction=Direction.DEBIT,
- account_uuid=ledger_account_debit.uuid,
- amount=amount,
- ),
- ]
-
- return lm.create_tx(entries=entries, tag=tag, metadata=tx_metadata)
-
-
-@pytest.fixture
-def create_main_accounts(
- lm: "LedgerManager", currency: "LedgerCurrency"
-) -> Callable[..., None]:
-
- def _inner() -> None:
- from generalresearch.models.thl.ledger import (
- AccountType,
- Direction,
- LedgerAccount,
- )
-
- account = LedgerAccount(
- display_name="Cash flow task complete",
- qualified_name=f"{currency.value}:revenue:task_complete",
- normal_balance=Direction.CREDIT,
- account_type=AccountType.REVENUE,
- currency=lm.currency,
- )
- lm.get_account_or_create(account=account)
-
- account = LedgerAccount(
- display_name="Operating Cash Account",
- qualified_name=f"{currency.value}:cash",
- normal_balance=Direction.DEBIT,
- account_type=AccountType.CASH,
- currency=currency,
- )
-
- lm.get_account_or_create(account=account)
-
- return None
-
- return _inner
-
-
-@pytest.fixture
-def delete_ledger_db(thl_web_rw: "PostgresManager") -> Callable[..., None]:
-
- def _inner():
- for table in [
- "ledger_transactionmetadata",
- "ledger_entry",
- "ledger_transaction",
- "ledger_account",
- ]:
- thl_web_rw.execute_write(
- query=f"DELETE FROM {table};",
- )
-
- return _inner
-
-
-@pytest.fixture
-def wipe_main_accounts(
- thl_web_rw: "PostgresManager", lm: "LedgerManager", currency: "LedgerCurrency"
-) -> Callable[..., None]:
-
- def _inner() -> None:
- db_table = thl_web_rw.db_name
- qual_names = [
- f"{currency.value}:revenue:task_complete",
- f"{currency.value}:cash",
- ]
-
- res = thl_web_rw.execute_sql_query(
- query=f"""
- SELECT lt.id as ltid, le.id as leid, tmd.id as tmdid, la.uuid as lauuid
- FROM `{db_table}`.`ledger_transaction` AS lt
- LEFT JOIN `{db_table}`.ledger_entry le
- ON lt.id = le.transaction_id
- LEFT JOIN `{db_table}`.ledger_account la
- ON la.uuid = le.account_id
- LEFT JOIN `{db_table}`.ledger_transactionmetadata tmd
- ON lt.id = tmd.transaction_id
- WHERE la.qualified_name IN %s
- """,
- params=[qual_names],
- )
-
- lt = {x["ltid"] for x in res if x["ltid"]}
- le = {x["leid"] for x in res if x["leid"]}
- tmd = {x["tmdid"] for x in res if x["tmdid"]}
- la = {x["lauuid"] for x in res if x["lauuid"]}
-
- thl_web_rw.execute_sql_query(
- query=f"""
- DELETE FROM `{db_table}`.`ledger_transactionmetadata`
- WHERE id IN %s
- """,
- params=[tmd],
- commit=True,
- )
-
- thl_web_rw.execute_sql_query(
- query=f"""
- DELETE FROM `{db_table}`.`ledger_entry`
- WHERE id IN %s
- """,
- params=[le],
- commit=True,
- )
-
- thl_web_rw.execute_sql_query(
- query=f"""
- DELETE FROM `{db_table}`.`ledger_transaction`
- WHERE id IN %s
- """,
- params=[lt],
- commit=True,
- )
-
- thl_web_rw.execute_sql_query(
- query=f"""
- DELETE FROM `{db_table}`.`ledger_account`
- WHERE uuid IN %s
- """,
- params=[la],
- commit=True,
- )
-
- return None
-
- return _inner
-
-
-@pytest.fixture
-def account_cash(lm: "LedgerManager", currency: "LedgerCurrency") -> "LedgerAccount":
- from generalresearch.models.thl.ledger import (
- AccountType,
- Direction,
- LedgerAccount,
- )
-
- account = LedgerAccount(
- display_name="Operating Cash Account",
- qualified_name=f"{currency.value}:cash",
- normal_balance=Direction.DEBIT,
- account_type=AccountType.CASH,
- currency=currency,
- )
- return lm.get_account_or_create(account=account)
+@pytest.fixture(scope="session")
+def thl_ledger_manager(
+ thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
+) -> ThlLedgerManager:
-@pytest.fixture
-def account_revenue_task_complete(
- lm: "LedgerManager", currency: "LedgerCurrency"
-) -> "LedgerAccount":
- from generalresearch.models.thl.ledger import (
- AccountType,
- Direction,
- LedgerAccount,
+ return ThlLedgerManager(
+ pg_config=thl_web_rw,
+ permissions=[
+ Permission.CREATE,
+ Permission.READ,
+ Permission.UPDATE,
+ Permission.DELETE,
+ ],
+ testing=True,
+ redis_config=thl_redis_config,
)
-
- account = LedgerAccount(
- display_name="Cash flow task complete",
- qualified_name=f"{currency.value}:revenue:task_complete",
- normal_balance=Direction.CREDIT,
- account_type=AccountType.REVENUE,
- currency=currency,
- )
- return lm.get_account_or_create(account=account)
-
-
-@pytest.fixture
-def account_expense_tango(
- lm: "LedgerManager", currency: "LedgerCurrency"
-) -> "LedgerAccount":
- from generalresearch.models.thl.ledger import (
- AccountType,
- Direction,
- LedgerAccount,
- )
-
- account = LedgerAccount(
- display_name="Tango Fee",
- qualified_name=f"{currency.value}:expense:tango_fee",
- normal_balance=Direction.DEBIT,
- account_type=AccountType.EXPENSE,
- currency=currency,
- )
- return lm.get_account_or_create(account=account)
-
-
-@pytest.fixture
-def user_account_user_wallet(
- lm: "LedgerManager", user: "User", currency: "LedgerCurrency"
-) -> "LedgerAccount":
- from generalresearch.models.thl.ledger import (
- AccountType,
- Direction,
- LedgerAccount,
- )
-
- account = LedgerAccount(
- display_name=f"{user.uuid} Wallet",
- qualified_name=f"{currency.value}:user_wallet:{user.uuid}",
- normal_balance=Direction.CREDIT,
- account_type=AccountType.USER_WALLET,
- reference_type="user",
- reference_uuid=user.uuid,
- currency=currency,
- )
- return lm.get_account_or_create(account=account)
-
-
-@pytest.fixture
-def product_account_bp_wallet(
- lm: "LedgerManager", product: "Product", currency: "LedgerCurrency"
-) -> "LedgerAccount":
- from generalresearch.models.thl.ledger import (
- AccountType,
- Direction,
- LedgerAccount,
- )
-
- account = LedgerAccount.model_validate(
- dict(
- display_name=f"{product.name} Wallet",
- qualified_name=f"{currency.value}:bp_wallet:{product.uuid}",
- normal_balance=Direction.CREDIT,
- account_type=AccountType.BP_WALLET,
- reference_type="bp",
- reference_uuid=product.uuid,
- currency=currency,
- )
- )
- return lm.get_account_or_create(account=account)
-
-
-@pytest.fixture
-def setup_accounts(
- product_factory: Callable[..., "Product"],
- lm: "LedgerManager",
- user: "User",
- currency: "LedgerCurrency",
-) -> None:
- from generalresearch.models.thl.ledger import (
- AccountType,
- Direction,
- LedgerAccount,
- )
-
- # BP's wallet and a revenue from their commissions account.
- p1 = product_factory()
-
- account = LedgerAccount(
- display_name=f"Revenue from {p1.name} commission",
- qualified_name=f"{currency.value}:revenue:bp_commission:{p1.uuid}",
- normal_balance=Direction.CREDIT,
- account_type=AccountType.REVENUE,
- reference_type="bp",
- reference_uuid=p1.uuid,
- currency=currency,
- )
- lm.get_account_or_create(account=account)
-
- account = LedgerAccount.model_validate(
- dict(
- display_name=f"{p1.name} Wallet",
- qualified_name=f"{currency.value}:bp_wallet:{p1.uuid}",
- normal_balance=Direction.CREDIT,
- account_type=AccountType.BP_WALLET,
- reference_type="bp",
- reference_uuid=p1.uuid,
- currency=currency,
- )
- )
- lm.get_account_or_create(account=account)
-
- # BP's wallet, user's wallet, and a revenue from their commissions account.
- p2 = product_factory()
- account = LedgerAccount(
- display_name=f"Revenue from {p2.name} commission",
- qualified_name=f"{currency.value}:revenue:bp_commission:{p2.uuid}",
- normal_balance=Direction.CREDIT,
- account_type=AccountType.REVENUE,
- reference_type="bp",
- reference_uuid=p2.uuid,
- currency=currency,
- )
- lm.get_account_or_create(account)
-
- account = LedgerAccount(
- display_name=f"{p2.name} Wallet",
- qualified_name=f"{currency.value}:bp_wallet:{p2.uuid}",
- normal_balance=Direction.CREDIT,
- account_type=AccountType.BP_WALLET,
- reference_type="bp",
- reference_uuid=p2.uuid,
- currency=currency,
- )
- lm.get_account_or_create(account)
-
- account = LedgerAccount(
- display_name=f"{user.uuid} Wallet",
- qualified_name=f"{currency.value}:user_wallet:{user.uuid}",
- normal_balance=Direction.CREDIT,
- account_type=AccountType.USER_WALLET,
- reference_type="user",
- reference_uuid=user.uuid,
- currency="test",
- )
- lm.get_account_or_create(account=account)
-
-
-@pytest.fixture
-def session_with_tx_factory(
- user_factory: Callable[..., "User"],
- product: "Product",
- session_factory: Callable[..., "Session"],
- session_manager: "SessionManager",
- wall_manager: "WallManager",
- utc_hour_ago: datetime,
- thl_lm: "ThlLedgerManager",
-) -> Callable[..., "Session"]:
-
- from generalresearch.models.thl.session import (
- Status,
- StatusCode1,
- )
- from generalresearch.models.thl.user import User
-
- def _inner(
- user: User,
- final_status: Status = Status.COMPLETE,
- wall_req_cpi: Decimal = Decimal(".50"),
- started: datetime = utc_hour_ago,
- ) -> Session:
- s: Session = session_factory(
- user=user,
- wall_count=2,
- final_status=final_status,
- wall_req_cpi=wall_req_cpi,
- started=started,
- )
- last_wall = s.wall_events[-1]
-
- wall_manager.finish(
- wall=last_wall,
- status=Status.COMPLETE,
- status_code_1=StatusCode1.COMPLETE,
- finished=last_wall.finished,
- )
-
- status, status_code_1 = s.determine_session_status()
- _, _, bp_pay, user_pay = s.determine_payments()
- session_manager.finish_with_status(
- session=s,
- finished=last_wall.finished,
- payout=bp_pay,
- user_payout=user_pay,
- status=status,
- status_code_1=status_code_1,
- )
-
- thl_lm.create_tx_task_complete(
- wall=last_wall,
- user=user,
- created=last_wall.finished,
- force=True,
- )
-
- thl_lm.create_tx_bp_payment(session=s, created=last_wall.finished, force=True)
-
- return s
-
- return _inner
-
-
-@pytest.fixture
-def adj_to_fail_with_tx_factory(
- session_manager: "SessionManager",
- wall_manager: "WallManager",
- thl_lm: "ThlLedgerManager",
-) -> Callable[..., None]:
- from datetime import datetime, timedelta
-
- from generalresearch.models.thl.definitions import WallAdjustedStatus
- from generalresearch.models.thl.session import (
- Session,
- )
-
- def _inner(
- session: Session,
- created: datetime,
- ) -> None:
- w1 = wall_manager.get_wall_events(session_id=session.id)[-1]
-
- # This is defined in `thl-grpc/thl/user_quality_history/recons.py:150`
- # so we can't use it as part of this test anyway to add rows to the
- # thl_taskadjustment table anyway.. until we created a
- # TaskAdjustment Manager to put into generalresearch!
-
- # create_task_adjustment_event(
- # wall,
- # user,
- # adjusted_status,
- # amount_usd=amount_usd,
- # alert_time=alert_time,
- # ext_status_code=ext_status_code,
- # )
-
- wall_manager.adjust_status(
- wall=w1,
- adjusted_status=WallAdjustedStatus.ADJUSTED_TO_FAIL,
- adjusted_cpi=Decimal("0.00"),
- adjusted_timestamp=created,
- )
-
- thl_lm.create_tx_task_adjustment(
- wall=w1,
- user=session.user,
- created=created + timedelta(milliseconds=1),
- )
-
- session.wall_events = wall_manager.get_wall_events(session_id=session.id)
- session_manager.adjust_status(session=session)
-
- thl_lm.create_tx_bp_adjustment(
- session=session, created=created + timedelta(milliseconds=2)
- )
-
- return None
-
- return _inner
-
-
-@pytest.fixture
-def adj_to_complete_with_tx_factory(
- session_manager: "SessionManager",
- wall_manager: "WallManager",
- thl_lm: "ThlLedgerManager",
-) -> Callable[..., None]:
- from datetime import timedelta
-
- from generalresearch.models.thl.definitions import WallAdjustedStatus
- from generalresearch.models.thl.session import (
- Session,
- )
-
- def _inner(
- session: Session,
- created: datetime,
- ) -> None:
- w1 = wall_manager.get_wall_events(session_id=session.id)[-1]
-
- wall_manager.adjust_status(
- wall=w1,
- adjusted_status=WallAdjustedStatus.ADJUSTED_TO_COMPLETE,
- adjusted_cpi=w1.req_cpi,
- adjusted_timestamp=created,
- )
-
- thl_lm.create_tx_task_adjustment(
- wall=w1,
- user=session.user,
- created=created + timedelta(milliseconds=1),
- )
-
- session.wall_events = wall_manager.get_wall_events(session_id=session.id)
- session_manager.adjust_status(session=session)
-
- thl_lm.create_tx_bp_adjustment(
- session=session, created=created + timedelta(milliseconds=2)
- )
-
- return None
-
- return _inner
diff --git a/test_utils/managers/network/conftest.py b/test_utils/managers/network/conftest.py
index 6c5ea23..e69de29 100644
--- a/test_utils/managers/network/conftest.py
+++ b/test_utils/managers/network/conftest.py
@@ -1,143 +0,0 @@
-import os
-from datetime import datetime, timedelta, timezone
-from uuid import uuid4
-
-import pytest
-
-from generalresearch.managers.network.label import IPLabelManager
-from generalresearch.managers.network.tool_run import ToolRunManager
-from generalresearch.models.network.definitions import IPProtocol
-from generalresearch.models.network.mtr.parser import parse_mtr_output
-from generalresearch.models.network.nmap.parser import parse_nmap_xml
-from generalresearch.models.network.rdns.parser import parse_rdns_output
-from generalresearch.models.network.tool_run import MTRRun, NmapRun, RDNSRun, Status
-from generalresearch.models.network.tool_run_command import (
- MTRRunCommand,
- MTRRunCommandOptions,
- NmapRunCommand,
- NmapRunCommandOptions,
- RDNSRunCommand,
- RDNSRunCommandOptions,
-)
-
-
-@pytest.fixture(scope="session")
-def scan_group_id():
- return uuid4().hex
-
-
-@pytest.fixture(scope="session")
-def iplabel_manager(thl_web_rw) -> IPLabelManager:
- assert "/unittest-" in thl_web_rw.dsn.path
-
- return IPLabelManager(pg_config=thl_web_rw)
-
-
-@pytest.fixture(scope="session")
-def toolrun_manager(thl_web_rw) -> ToolRunManager:
- assert "/unittest-" in thl_web_rw.dsn.path
-
- return ToolRunManager(pg_config=thl_web_rw)
-
-
-@pytest.fixture(scope="session")
-def nmap_raw_output(request) -> str:
- fp = os.path.join(request.config.rootpath, "data/nmaprun1.xml")
- with open(fp) as f:
- data = f.read()
- return data
-
-
-@pytest.fixture(scope="session")
-def nmap_result(nmap_raw_output):
- return parse_nmap_xml(nmap_raw_output)
-
-
-@pytest.fixture(scope="session")
-def nmap_run(nmap_result, scan_group_id):
- r = nmap_result
- config = NmapRunCommand(
- command="nmap",
- options=NmapRunCommandOptions(
- ip=r.target_ip, ports="22-1000,11000,1100,3389,61232", top_ports=None
- ),
- )
- return NmapRun(
- tool_version=r.version,
- status=Status.SUCCESS,
- ip=r.target_ip,
- started_at=r.started_at,
- finished_at=r.finished_at,
- raw_command=config.to_command_str(),
- scan_group_id=scan_group_id,
- config=config,
- parsed=r,
- )
-
-
-@pytest.fixture(scope="session")
-def dig_raw_output():
- return "156.32.33.45.in-addr.arpa. 300 IN PTR scanme.nmap.org."
-
-
-@pytest.fixture(scope="session")
-def rdns_result(dig_raw_output):
- return parse_rdns_output(ip="45.33.32.156", raw=dig_raw_output)
-
-
-@pytest.fixture(scope="session")
-def rdns_run(rdns_result, scan_group_id):
- r = rdns_result
- ip = "45.33.32.156"
- utc_now = datetime.now(tz=timezone.utc)
- config = RDNSRunCommand(command="dig", options=RDNSRunCommandOptions(ip=ip))
- return RDNSRun(
- tool_version="1.2.3",
- status=Status.SUCCESS,
- ip=ip,
- started_at=utc_now,
- finished_at=utc_now + timedelta(seconds=1),
- raw_command=config.to_command_str(),
- scan_group_id=scan_group_id,
- config=config,
- parsed=r,
- )
-
-
-@pytest.fixture(scope="session")
-def mtr_raw_output(request):
- fp = os.path.join(request.config.rootpath, "data/mtr_fatbeam.json")
- with open(fp) as f:
- data = f.read()
- return data
-
-
-@pytest.fixture(scope="session")
-def mtr_result(mtr_raw_output):
- return parse_mtr_output(mtr_raw_output, port=443, protocol=IPProtocol.TCP)
-
-
-@pytest.fixture(scope="session")
-def mtr_run(mtr_result, scan_group_id):
- r = mtr_result
- utc_now = datetime.now(tz=timezone.utc)
- config = MTRRunCommand(
- command="mtr",
- options=MTRRunCommandOptions(
- ip=r.destination, protocol=IPProtocol.TCP, port=443
- ),
- )
-
- return MTRRun(
- tool_version="1.2.3",
- status=Status.SUCCESS,
- ip=r.destination,
- started_at=utc_now,
- finished_at=utc_now + timedelta(seconds=1),
- raw_command=config.to_command_str(),
- scan_group_id=scan_group_id,
- config=config,
- parsed=r,
- facility_id=1,
- source_ip="1.2.3.4",
- )
diff --git a/test_utils/managers/thl/conftest.py b/test_utils/managers/thl/conftest.py
index 76e4226..5b70961 100644
--- a/test_utils/managers/thl/conftest.py
+++ b/test_utils/managers/thl/conftest.py
@@ -1,112 +1,258 @@
from __future__ import annotations
-from decimal import Decimal
-from random import randint
from typing import Callable
-import faker
-from pydantic import PositiveInt
-
-from generalresearch.managers.thl.ipinfo import IPGeonameManager, IPInformationManager
-from generalresearch.models.custom_types import IPvAnyAddressStr
-from generalresearch.models.thl.ipinfo import IPGeoname, IPInformation, UserType
-
-fake = faker.Faker()
-
-
-def ipgeoname_factory(ipgeoname_manager: IPGeonameManager) -> Callable[..., IPGeoname]:
-
- def _inner(
- geoname_id: PositiveInt | None = None,
- continent_code: str | None = None,
- continent_name: str | None = None,
- country_iso: str | None = None,
- country_name: str | None = None,
- subdivision_1_iso: str | None = None,
- subdivision_1_name: str | None = None,
- subdivision_2_iso: str | None = None,
- subdivision_2_name: str | None = None,
- city_name: str | None = None,
- metro_code: int | None = None,
- time_zone: str | None = None,
- is_in_european_union: bool | None = None,
- ) -> IPGeoname:
-
- return ipgeoname_manager.create(
- geoname_id=geoname_id or randint(1, 999_999_999),
- continent_code=continent_code or "na",
- continent_name=continent_name or "North America",
- country_iso=country_iso or "us",
- country_name=country_name or "United States",
- subdivision_1_iso=subdivision_1_iso or "fl",
- subdivision_1_name=subdivision_1_name or "Florida",
- subdivision_2_iso=subdivision_2_iso,
- subdivision_2_name=subdivision_2_name,
- city_name=city_name,
- metro_code=metro_code,
- time_zone=time_zone,
- is_in_european_union=is_in_european_union,
- )
-
- return _inner
-
-
-def ipinformation_factory(
- ipinformation_manager: IPInformationManager,
-) -> Callable[..., IPInformation]:
-
- def _inner(
- ip: IPvAnyAddressStr | None = None,
- geoname_id: PositiveInt | None = None,
- country_iso: str | None = None,
- registered_country_iso: str | None = None,
- is_anonymous: bool | None = None,
- is_anonymous_vpn: bool | None = None,
- is_hosting_provider: bool | None = None,
- is_public_proxy: bool | None = None,
- is_tor_exit_node: bool | None = None,
- is_residential_proxy: bool | None = None,
- autonomous_system_number: PositiveInt | None = None,
- autonomous_system_organization: str | None = None,
- domain: str | None = None,
- isp: str | None = None,
- mobile_country_code: str | None = None,
- mobile_network_code: str | None = None,
- network: str | None = None,
- organization: str | None = None,
- static_ip_score: float | None = None,
- user_type: UserType | None = None,
- postal_code: str | None = None,
- latitude: Decimal | None = None,
- longitude: Decimal | None = None,
- accuracy_radius: int | None = None,
- ) -> IPInformation:
-
- return ipinformation_manager.create(
- ip=ip or fake.ipv4_public(),
- geoname_id=geoname_id,
- country_iso=country_iso or fake.country_code(),
- registered_country_iso=registered_country_iso,
- is_anonymous=is_anonymous,
- is_anonymous_vpn=is_anonymous_vpn,
- is_hosting_provider=is_hosting_provider,
- is_public_proxy=is_public_proxy,
- is_tor_exit_node=is_tor_exit_node,
- is_residential_proxy=is_residential_proxy,
- autonomous_system_number=autonomous_system_number,
- autonomous_system_organization=autonomous_system_organization,
- domain=domain,
- isp=isp,
- mobile_country_code=mobile_country_code,
- mobile_network_code=mobile_network_code,
- network=network,
- organization=organization,
- static_ip_score=static_ip_score,
- user_type=user_type,
- postal_code=postal_code,
- latitude=latitude,
- longitude=longitude,
- accuracy_radius=accuracy_radius,
- )
-
- return _inner
+import pytest
+from pydantic import PostgresDsn
+
+from generalresearch.config import GRLBaseSettings
+from generalresearch.managers.base import Permission
+from generalresearch.managers.thl.buyer import BuyerManager
+from generalresearch.managers.thl.category import CategoryManager
+from generalresearch.managers.thl.payout import (
+ BrokerageProductPayoutEventManager,
+ BusinessPayoutEventManager,
+ PayoutEventManager,
+ UserPayoutEventManager,
+)
+from generalresearch.managers.thl.product import ProductManager
+from generalresearch.managers.thl.session import SessionManager
+from generalresearch.managers.thl.task_adjustment import (
+ TaskAdjustmentManager,
+)
+from generalresearch.managers.thl.user_manager.user_manager import (
+ UserManager,
+)
+from generalresearch.managers.thl.user_manager.user_metadata_manager import (
+ UserMetadataManager,
+)
+from generalresearch.managers.thl.wall import (
+ WallCacheManager,
+ WallManager,
+)
+from generalresearch.pg_helper import PostgresConfig
+from generalresearch.redis_helper import RedisConfig
+
+
+@pytest.fixture(scope="session")
+def thl_web_rr(django_db_factory: Callable[..., PostgresDsn]) -> PostgresConfig:
+
+ return PostgresConfig(
+ dsn=django_db_factory("generalresearch.thl_django"),
+ connect_timeout=1,
+ statement_timeout=5,
+ )
+
+
+@pytest.fixture(scope="session")
+def thl_web_rw(thl_web_rr: PostgresConfig) -> PostgresConfig:
+ return thl_web_rr
+
+
+@pytest.fixture(scope="session")
+def thl_redis_config(settings: GRLBaseSettings) -> RedisConfig:
+ return RedisConfig(
+ dsn=settings.thl_redis,
+ decode_responses=True,
+ socket_timeout=settings.redis_timeout,
+ socket_connect_timeout=settings.redis_timeout,
+ )
+
+
+@pytest.fixture(scope="session")
+def payout_event_manager(
+ thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
+) -> PayoutEventManager:
+ assert thl_web_rw.dsn.path
+ assert "/unittest-" in thl_web_rw.dsn.path
+
+ from generalresearch.managers.thl.payout import PayoutEventManager
+
+ return PayoutEventManager(
+ pg_config=thl_web_rw,
+ permissions=[Permission.CREATE, Permission.READ],
+ redis_config=thl_redis_config,
+ )
+
+
+@pytest.fixture(scope="session")
+def user_payout_event_manager(
+ thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
+) -> UserPayoutEventManager:
+ assert thl_web_rw.dsn.path
+ assert "/unittest-" in thl_web_rw.dsn.path
+
+ from generalresearch.managers.thl.payout import UserPayoutEventManager
+
+ return UserPayoutEventManager(
+ pg_config=thl_web_rw,
+ permissions=[Permission.CREATE, Permission.READ],
+ redis_config=thl_redis_config,
+ )
+
+
+@pytest.fixture(scope="session")
+def brokerage_product_payout_event_manager(
+ thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
+) -> BrokerageProductPayoutEventManager:
+ assert thl_web_rw.dsn.path
+ assert "/unittest-" in thl_web_rw.dsn.path
+
+ from generalresearch.managers.thl.payout import (
+ BrokerageProductPayoutEventManager,
+ )
+
+ return BrokerageProductPayoutEventManager(
+ pg_config=thl_web_rw,
+ permissions=[Permission.CREATE, Permission.READ],
+ redis_config=thl_redis_config,
+ )
+
+
+@pytest.fixture(scope="session")
+def business_payout_event_manager(
+ thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
+) -> BusinessPayoutEventManager:
+ assert thl_web_rw.dsn.path
+ assert "/unittest-" in thl_web_rw.dsn.path
+
+ from generalresearch.managers.thl.payout import (
+ BusinessPayoutEventManager,
+ )
+
+ return BusinessPayoutEventManager(
+ pg_config=thl_web_rw,
+ permissions=[Permission.CREATE, Permission.READ],
+ redis_config=thl_redis_config,
+ )
+
+
+@pytest.fixture(scope="session")
+def product_manager(thl_web_rw: PostgresConfig) -> ProductManager:
+ assert thl_web_rw.dsn
+ assert thl_web_rw.dsn.path
+ assert "/unittest-" in thl_web_rw.dsn.path
+
+ from generalresearch.managers.thl.product import ProductManager
+
+ return ProductManager(pg_config=thl_web_rw)
+
+
+@pytest.fixture(scope="session")
+def user_manager(
+ settings: GRLBaseSettings, thl_web_rw: PostgresConfig, thl_web_rr: PostgresConfig
+) -> UserManager:
+ assert thl_web_rw.dsn
+ assert thl_web_rw.dsn.path
+ assert thl_web_rr.dsn
+ assert thl_web_rr.dsn.path
+ assert "/unittest-" in thl_web_rw.dsn.path
+ assert "/unittest-" in thl_web_rr.dsn.path
+
+ from generalresearch.managers.thl.user_manager.user_manager import (
+ UserManager,
+ )
+
+ return UserManager(
+ pg_config=thl_web_rw,
+ pg_config_rr=thl_web_rr,
+ redis=settings.redis,
+ )
+
+
+@pytest.fixture(scope="session")
+def user_metadata_manager(thl_web_rw: PostgresConfig) -> UserMetadataManager:
+ assert thl_web_rw.dsn
+ assert thl_web_rw.dsn.path
+ assert "/unittest-" in thl_web_rw.dsn.path
+
+ from generalresearch.managers.thl.user_manager.user_metadata_manager import (
+ UserMetadataManager,
+ )
+
+ return UserMetadataManager(pg_config=thl_web_rw)
+
+
+@pytest.fixture(scope="session")
+def session_manager(thl_web_rw: PostgresConfig) -> SessionManager:
+ assert thl_web_rw.dsn
+ assert thl_web_rw.dsn.path
+ assert "/unittest-" in thl_web_rw.dsn.path
+
+ from generalresearch.managers.thl.session import SessionManager
+
+ return SessionManager(pg_config=thl_web_rw)
+
+
+@pytest.fixture(scope="session")
+def wall_manager(thl_web_rw: PostgresConfig) -> WallManager:
+ assert thl_web_rw.dsn
+ assert thl_web_rw.dsn.path
+ assert "/unittest-" in thl_web_rw.dsn.path
+
+ from generalresearch.managers.thl.wall import WallManager
+
+ return WallManager(pg_config=thl_web_rw)
+
+
+@pytest.fixture(scope="session")
+def wall_cache_manager(
+ thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
+) -> WallCacheManager:
+ # assert "/unittest-" in thl_web_rw.dsn.path
+
+ from generalresearch.managers.thl.wall import WallCacheManager
+
+ return WallCacheManager(pg_config=thl_web_rw, redis_config=thl_redis_config)
+
+
+@pytest.fixture(scope="session")
+def task_adjustment_manager(thl_web_rw: PostgresConfig) -> TaskAdjustmentManager:
+ # assert "/unittest-" in thl_web_rw.dsn.path
+
+ from generalresearch.managers.thl.task_adjustment import (
+ TaskAdjustmentManager,
+ )
+
+ return TaskAdjustmentManager(pg_config=thl_web_rw)
+
+
+@pytest.fixture(scope="session")
+def category_manager(thl_web_rw: PostgresConfig) -> CategoryManager:
+ assert thl_web_rw.dsn
+ assert thl_web_rw.dsn.path
+ assert "/unittest-" in thl_web_rw.dsn.path
+ from generalresearch.managers.thl.category import CategoryManager
+
+ return CategoryManager(pg_config=thl_web_rw)
+
+
+@pytest.fixture(scope="session")
+def buyer_manager(thl_web_rw: PostgresConfig) -> BuyerManager:
+ # assert "/unittest-" in thl_web_rw.dsn.path
+ from generalresearch.managers.thl.buyer import BuyerManager
+
+ return BuyerManager(pg_config=thl_web_rw)
+
+
+@pytest.fixture(scope="session")
+def survey_manager(thl_web_rw: PostgresConfig):
+ # assert "/unittest-" in thl_web_rw.dsn.path
+ from generalresearch.managers.thl.survey import SurveyManager
+
+ return SurveyManager(pg_config=thl_web_rw)
+
+
+@pytest.fixture(scope="session")
+def surveystat_manager(thl_web_rw: PostgresConfig):
+ # assert "/unittest-" in thl_web_rw.dsn.path
+ from generalresearch.managers.thl.survey import SurveyStatManager
+
+ return SurveyStatManager(pg_config=thl_web_rw)
+
+
+@pytest.fixture(scope="session")
+def surveypenalty_manager(thl_redis_config: RedisConfig):
+ from generalresearch.managers.thl.survey_penalty import SurveyPenaltyManager
+
+ return SurveyPenaltyManager(redis_config=thl_redis_config)
diff --git a/test_utils/managers/upk/conftest.py b/test_utils/managers/upk/conftest.py
index e28d085..d8f956c 100644
--- a/test_utils/managers/upk/conftest.py
+++ b/test_utils/managers/upk/conftest.py
@@ -1,173 +1,69 @@
-import os
-import time
-from typing import TYPE_CHECKING, Optional
-from uuid import UUID
+from typing import Callable, Generator
-import pandas as pd
import pytest
+from generalresearch.managers.thl.profiling.question import (
+ QuestionManager,
+)
+from generalresearch.managers.thl.profiling.schema import (
+ UpkSchemaManager,
+)
+from generalresearch.managers.thl.profiling.uqa import UQAManager
+from generalresearch.managers.thl.profiling.user_upk import (
+ UserUpkManager,
+)
+from generalresearch.models.thl.user import User
from generalresearch.pg_helper import PostgresConfig
-
-if TYPE_CHECKING:
- from generalresearch.managers.thl.category import CategoryManager
-
-
-def insert_data_from_csv(
- thl_web_rw: PostgresConfig,
- table_name: str,
- fp: Optional[str] = None,
- disable_fk_checks: bool = False,
- df: Optional[pd.DataFrame] = None,
-):
- assert fp is not None or df is not None and not (fp is not None and df is not None)
- if fp:
- df = pd.read_csv(fp, dtype=str)
- df = df.where(pd.notnull(df), None)
- cols = list(df.columns)
- col_str = ", ".join(cols)
- values_str = ", ".join(["%s"] * len(cols))
- if "id" in df.columns and len(df["id"].iloc[0]) == 36:
- df["id"] = df["id"].map(lambda x: UUID(x).hex)
- args = df.to_dict("tight")["data"]
-
- with thl_web_rw.make_connection() as conn:
- with conn.cursor() as c:
- if disable_fk_checks:
- c.execute("SET CONSTRAINTS ALL DEFERRED")
- c.executemany(
- f"INSERT INTO {table_name} ({col_str}) VALUES ({values_str})",
- params_seq=args,
- )
- conn.commit()
+from generalresearch.redis_helper import RedisConfig
@pytest.fixture(scope="session")
-def category_data(
- thl_web_rw: PostgresConfig, category_manager: "CategoryManager"
-) -> None:
- fp = os.path.join(os.path.dirname(__file__), "marketplace_category.csv.gz")
- insert_data_from_csv(
- thl_web_rw,
- fp=fp,
- table_name="marketplace_category",
- disable_fk_checks=True,
- )
- # Don't strictly need to do this, but probably we should
- category_manager.populate_caches()
- cats = category_manager.categories.values()
- path_id = {c.path: c.id for c in cats}
- data = [
- {"id": c.id, "parent_id": path_id[c.parent_path]} for c in cats if c.parent_path
- ]
- query = """
- UPDATE marketplace_category
- SET parent_id = %(parent_id)s
- WHERE id = %(id)s;
- """
- with thl_web_rw.make_connection() as conn:
- with conn.cursor() as c:
- c.executemany(query=query, params_seq=data)
- conn.commit()
+def upk_schema_manager(thl_web_rw: PostgresConfig) -> UpkSchemaManager:
+ return UpkSchemaManager(pg_config=thl_web_rw)
@pytest.fixture(scope="session")
-def property_data(thl_web_rw: PostgresConfig) -> None:
- fp = os.path.join(os.path.dirname(__file__), "marketplace_property.csv.gz")
- insert_data_from_csv(thl_web_rw, fp=fp, table_name="marketplace_property")
-
+def user_upk_manager(
+ thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
+) -> UserUpkManager:
-@pytest.fixture(scope="session")
-def item_data(thl_web_rw: PostgresConfig) -> None:
- fp = os.path.join(os.path.dirname(__file__), "marketplace_item.csv.gz")
- insert_data_from_csv(thl_web_rw, fp=fp, table_name="marketplace_item")
+ return UserUpkManager(pg_config=thl_web_rw, redis_config=thl_redis_config)
@pytest.fixture(scope="session")
-def propertycategoryassociation_data(
+def question_manager(
thl_web_rw: PostgresConfig,
- category_data,
- property_data,
- category_manager: "CategoryManager",
-) -> None:
- table_name = "marketplace_propertycategoryassociation"
- fp = os.path.join(os.path.dirname(__file__), f"{table_name}.csv.gz")
- # Need to lookup category pk from uuid
- category_manager.populate_caches()
- df = pd.read_csv(fp, dtype=str)
- df["category_id"] = df["category_id"].map(
- lambda x: category_manager.categories[x].id
- )
- insert_data_from_csv(thl_web_rw, df=df, table_name=table_name)
+) -> QuestionManager:
+ return QuestionManager(pg_config=thl_web_rw)
@pytest.fixture(scope="session")
-def propertycountry_data(thl_web_rw: PostgresConfig, property_data) -> None:
- fp = os.path.join(os.path.dirname(__file__), "marketplace_propertycountry.csv.gz")
- insert_data_from_csv(thl_web_rw, fp=fp, table_name="marketplace_propertycountry")
+def uqa_manager(
+ thl_web_rw: PostgresConfig, thl_redis_config: RedisConfig
+) -> UQAManager:
+ return UQAManager(redis_config=thl_redis_config, pg_config=thl_web_rw)
-@pytest.fixture(scope="session")
-def propertymarketplaceassociation_data(
- thl_web_rw: PostgresConfig, property_data
-) -> None:
- table_name = "marketplace_propertymarketplaceassociation"
- fp = os.path.join(os.path.dirname(__file__), f"{table_name}.csv.gz")
- insert_data_from_csv(thl_web_rw, fp=fp, table_name=table_name)
+@pytest.fixture(scope="function")
+def uqa_manager_clear_cache_factory(
+ uqa_manager: UQAManager,
+) -> Callable[..., Generator[None]]:
-@pytest.fixture(scope="session")
-def propertyitemrange_data(
- thl_web_rw: PostgresConfig, property_data, item_data
-) -> None:
- table_name = "marketplace_propertyitemrange"
- fp = os.path.join(os.path.dirname(__file__), f"{table_name}.csv.gz")
- insert_data_from_csv(thl_web_rw, fp=fp, table_name=table_name)
+ def _inner(user: User) -> Generator[None]:
+ # On successive py-test/jenkins runs, the cache may contain
+ # the previous run's info (keyed under the same user_id)
+ uqa_manager.clear_cache(user)
+ yield
-@pytest.fixture(scope="session")
-def question_data(thl_web_rw: PostgresConfig) -> None:
- table_name = "marketplace_question"
- fp = os.path.join(os.path.dirname(__file__), f"{table_name}.csv.gz")
- insert_data_from_csv(
- thl_web_rw, fp=fp, table_name=table_name, disable_fk_checks=True
- )
+ uqa_manager.clear_cache(user)
+ return _inner
-@pytest.fixture(scope="session")
-def clear_upk_tables(thl_web_rw: PostgresConfig):
- tables = [
- "marketplace_propertyitemrange",
- "marketplace_propertymarketplaceassociation",
- "marketplace_propertycategoryassociation",
- "marketplace_category",
- "marketplace_item",
- "marketplace_property",
- "marketplace_propertycountry",
- "marketplace_question",
- ]
- table_str = ", ".join(tables)
-
- with thl_web_rw.make_connection() as conn:
- with conn.cursor() as c:
- c.execute(f"TRUNCATE {table_str} RESTART IDENTITY CASCADE;")
- conn.commit()
-
-@pytest.fixture(scope="session")
-def upk_data(
- clear_upk_tables,
- category_data,
- property_data,
- item_data,
- propertycategoryassociation_data,
- propertycountry_data,
- propertymarketplaceassociation_data,
- propertyitemrange_data,
- question_data,
-) -> None:
- # Wait a second to make sure the HarmonizerCache refresh loop pulls these in
- time.sleep(2)
-
-
-def test_fixtures(upk_data):
- pass
+@pytest.fixture(scope="function")
+def uqa_manager_clear_cache(
+ uqa_manager_clear_cache_factory: Callable[..., None], user: User
+):
+ uqa_manager_clear_cache_factory(user=user)
diff --git a/test_utils/models/conftest.py b/test_utils/models/conftest.py
index 1133d32..9925a9e 100644
--- a/test_utils/models/conftest.py
+++ b/test_utils/models/conftest.py
@@ -16,6 +16,7 @@ from generalresearch.models.thl.definitions import (
WALL_ALLOWED_STATUS_STATUS_CODE,
Status,
)
+from generalresearch.models.thl.survey.model import Buyer, Survey
from generalresearch.pg_helper import PostgresConfig
from generalresearch.redis_helper import RedisConfig
@@ -59,7 +60,6 @@ if TYPE_CHECKING:
Product,
)
from generalresearch.models.thl.session import Session, Wall
- from generalresearch.models.thl.survey.model import Buyer, Survey
from generalresearch.models.thl.user import User
from generalresearch.models.thl.user_iphistory import IPRecord
from generalresearch.models.thl.userhealth import AuditLog, AuditLogLevel
@@ -70,10 +70,10 @@ if TYPE_CHECKING:
@pytest.fixture
def user(
request,
- product_manager: "ProductManager",
- user_manager: "UserManager",
+ product_manager: ProductManager,
+ user_manager: UserManager,
thl_web_rr: PostgresConfig,
-) -> "User":
+) -> User:
product = getattr(request, "product", None)
if product is None:
@@ -172,7 +172,6 @@ def wall(session: Session, user: User, wall_manager: WallManager) -> Wall | None
@pytest.fixture
def session_factory(
- wall_factory: Callable[..., Wall],
session_manager: SessionManager,
wall_manager: WallManager,
utc_hour_ago: datetime,
@@ -190,7 +189,7 @@ def session_factory(
# Session details
final_status: Status = Status.COMPLETE,
started: datetime = utc_hour_ago,
- ) -> "Session":
+ ) -> Session:
if wall_req_cpis:
assert len(wall_req_cpis) == wall_count
if wall_statuses:
@@ -422,7 +421,7 @@ def business(request, business_manager: BusinessManager) -> Business:
@pytest.fixture
def business_address(
- request, business: "Business", business_address_manager: BusinessAddressManager
+ request, business: Business, business_address_manager: BusinessAddressManager
) -> BusinessAddress:
return business_address_manager.create_dummy(business_id=business.id)
@@ -442,77 +441,6 @@ def team(request, team_manager: TeamManager) -> Team:
@pytest.fixture
-def gr_user(gr_um: GRUserManager) -> GRUser:
- return gr_um.create_dummy()
-
-
-@pytest.fixture
-def gr_user_cache(
- gr_user: GRUser,
- gr_db: PostgresConfig,
- thl_web_rr: PostgresConfig,
- gr_redis_config: RedisConfig,
-) -> GRUser:
- gr_user.set_cache(
- pg_config=gr_db, thl_web_rr=thl_web_rr, redis_config=gr_redis_config
- )
- return gr_user
-
-
-@pytest.fixture
-def gr_user_factory(gr_um: GRUserManager) -> Callable[..., GRUser]:
-
- def _inner():
- return gr_um.create_dummy()
-
- return _inner
-
-
-@pytest.fixture()
-def gr_user_token(
- gr_user: GRUser, gr_tm: GRTokenManager, gr_db: PostgresConfig
-) -> GRToken:
- gr_tm.create(user_id=gr_user.id)
- gr_user.prefetch_token(pg_config=gr_db)
-
- res = gr_user.token
- assert res is not None, "GRToken should exist after creation and prefetching"
- return res
-
-
-@pytest.fixture()
-def gr_user_token_header(gr_user_token: GRToken) -> dict[str, str]:
- return gr_user_token.auth_header
-
-
-@pytest.fixture(scope="function")
-def membership(
- request, team: Team, gr_user: GRUser, team_manager: TeamManager
-) -> Membership:
- assert team.id, "Team must be saved"
- assert gr_user.id, "GRUser must be saved"
- return team_manager.add_user(team=team, gr_user=gr_user)
-
-
-@pytest.fixture(scope="function")
-def membership_factory(
- team: Team,
- gr_user: GRUser,
- membership_manager: MembershipManager,
- team_manager: TeamManager,
- gr_um: GRUserManager,
-) -> Callable[..., Membership]:
-
- def _inner(**kwargs) -> Membership:
- _team = kwargs.get("team", team_manager.create_dummy())
- _gr_user = kwargs.get("gr_user", gr_um.create_dummy())
-
- return membership_manager.create(team=_team, gr_user=_gr_user)
-
- return _inner
-
-
-@pytest.fixture
def audit_log(audit_log_manager: AuditLogManager, user: User) -> AuditLog:
return audit_log_manager.create_dummy(user_id=user.user_id)
@@ -613,7 +541,7 @@ def buyer_factory(buyer_manager: BuyerManager) -> Callable[..., Buyer]:
@pytest.fixture(scope="session")
-def survey(survey_manager: SurveyManager, buyer: Buyer) -> "Survey":
+def survey(survey_manager: SurveyManager, buyer: Buyer) -> Survey:
s = Survey(source=Source.TESTING, survey_id=uuid4().hex, buyer_code=buyer.code)
survey_manager.create_bulk([s])
return s
diff --git a/test_utils/grliq/managers/__init__.py b/test_utils/models/contest/__init__.py
index e69de29..e69de29 100644
--- a/test_utils/grliq/managers/__init__.py
+++ b/test_utils/models/contest/__init__.py
diff --git a/test_utils/models/contest/conftest.py b/test_utils/models/contest/conftest.py
new file mode 100644
index 0000000..e750076
--- /dev/null
+++ b/test_utils/models/contest/conftest.py
@@ -0,0 +1,292 @@
+from __future__ import annotations
+
+from datetime import datetime, timezone
+from decimal import Decimal
+from typing import Callable
+from uuid import uuid4
+
+import pytest
+from fastapi import Request
+
+from generalresearch.currency import USDCent
+from generalresearch.managers.thl.contest_manager import ContestManager
+from generalresearch.managers.thl.ledger_manager.thl_ledger import ThlLedgerManager
+from generalresearch.models.thl.contest.contest import Contest
+from generalresearch.models.thl.contest.leaderboard import (
+ LeaderboardContestCreate,
+)
+from generalresearch.models.thl.contest.milestone import (
+ MilestoneContestCreate,
+)
+from generalresearch.models.thl.contest.raffle import (
+ RaffleContestCreate,
+)
+from generalresearch.models.thl.product import Product
+from generalresearch.models.thl.user import User
+
+# === Miscellaneous ===
+
+# === Managers ===
+
+# === Models ===
+
+
+@pytest.fixture
+def raffle_contest_create() -> RaffleContestCreate:
+ from generalresearch.models.thl.contest import (
+ ContestEndCondition,
+ ContestPrize,
+ )
+ from generalresearch.models.thl.contest.definitions import (
+ ContestPrizeKind,
+ ContestType,
+ )
+ from generalresearch.models.thl.contest.raffle import (
+ ContestEntryType,
+ RaffleContestCreate,
+ )
+
+ # This is what we'll get from the fastapi endpoint
+ return RaffleContestCreate(
+ name="test",
+ contest_type=ContestType.RAFFLE,
+ entry_type=ContestEntryType.CASH,
+ prizes=[
+ ContestPrize(
+ name="iPod 64GB White",
+ kind=ContestPrizeKind.PHYSICAL,
+ estimated_cash_value=USDCent(100),
+ )
+ ],
+ end_condition=ContestEndCondition(target_entry_amount=USDCent(100)),
+ )
+
+
+@pytest.fixture
+def raffle_contest_in_db(
+ product_user_wallet_yes: Product,
+ raffle_contest_create: RaffleContestCreate,
+ contest_manager: ContestManager,
+) -> Contest:
+ return contest_manager.create(
+ product_id=product_user_wallet_yes.uuid, contest_create=raffle_contest_create
+ )
+
+
+@pytest.fixture
+def raffle_contest(
+ product_user_wallet_yes: Product, raffle_contest_create: RaffleContestCreate
+) -> Contest:
+ from generalresearch.models.thl.contest.io import contest_create_to_contest
+
+ return contest_create_to_contest(
+ product_id=product_user_wallet_yes.uuid, contest_create=raffle_contest_create
+ )
+
+
+@pytest.fixture(scope="function")
+def raffle_contest_factory(
+ product_user_wallet_yes: Product,
+ raffle_contest_create: RaffleContestCreate,
+ contest_manager: ContestManager,
+) -> Callable[..., Contest]:
+
+ def _inner(**kwargs):
+ raffle_contest_create.update(**kwargs)
+ return contest_manager.create(
+ product_id=product_user_wallet_yes.uuid,
+ contest_create=raffle_contest_create,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def milestone_contest_create() -> MilestoneContestCreate:
+ from generalresearch.models.thl.contest import (
+ ContestPrize,
+ )
+ from generalresearch.models.thl.contest.definitions import (
+ ContestPrizeKind,
+ ContestType,
+ )
+ from generalresearch.models.thl.contest.milestone import (
+ ContestEntryTrigger,
+ MilestoneContestCreate,
+ MilestoneContestEndCondition,
+ )
+
+ # This is what we'll get from the fastapi endpoint
+ return MilestoneContestCreate(
+ name="Win a 50% bonus for 7 days and a $1 bonus after your first 3 completes!",
+ description="only valid for the first 5 users",
+ contest_type=ContestType.MILESTONE,
+ prizes=[
+ ContestPrize(
+ name="50% for 7 days",
+ kind=ContestPrizeKind.PROMOTION,
+ estimated_cash_value=USDCent(0),
+ ),
+ ContestPrize(
+ name="$1 Bonus",
+ kind=ContestPrizeKind.CASH,
+ cash_amount=USDCent(1_00),
+ estimated_cash_value=USDCent(1_00),
+ ),
+ ],
+ end_condition=MilestoneContestEndCondition(
+ ends_at=datetime(year=2030, month=1, day=1, tzinfo=timezone.utc),
+ max_winners=5,
+ ),
+ entry_trigger=ContestEntryTrigger.TASK_COMPLETE,
+ target_amount=3,
+ )
+
+
+@pytest.fixture
+def milestone_contest_in_db(
+ product_user_wallet_yes: Product,
+ milestone_contest_create: MilestoneContestCreate,
+ contest_manager: ContestManager,
+) -> Contest:
+ return contest_manager.create(
+ product_id=product_user_wallet_yes.uuid, contest_create=milestone_contest_create
+ )
+
+
+@pytest.fixture
+def milestone_contest(
+ product_user_wallet_yes: Product,
+ milestone_contest_create: MilestoneContestCreate,
+) -> Contest:
+ from generalresearch.models.thl.contest.io import contest_create_to_contest
+
+ return contest_create_to_contest(
+ product_id=product_user_wallet_yes.uuid, contest_create=milestone_contest_create
+ )
+
+
+@pytest.fixture(scope="function")
+def milestone_contest_factory(
+ product_user_wallet_yes: Product,
+ milestone_contest_create: MilestoneContestCreate,
+ contest_manager: ContestManager,
+) -> Callable[..., Contest]:
+
+ def _inner(**kwargs):
+ milestone_contest_create.update(**kwargs)
+ return contest_manager.create(
+ product_id=product_user_wallet_yes.uuid,
+ contest_create=milestone_contest_create,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def leaderboard_contest_create(
+ product_user_wallet_yes: Product,
+) -> LeaderboardContestCreate:
+ from generalresearch.models.thl.contest import (
+ ContestPrize,
+ )
+ from generalresearch.models.thl.contest.definitions import (
+ ContestPrizeKind,
+ ContestType,
+ )
+ from generalresearch.models.thl.contest.leaderboard import (
+ LeaderboardContestCreate,
+ )
+
+ # This is what we'll get from the fastapi endpoint
+ return LeaderboardContestCreate(
+ name="test",
+ contest_type=ContestType.LEADERBOARD,
+ prizes=[
+ ContestPrize(
+ name="$15 Cash",
+ estimated_cash_value=USDCent(15_00),
+ cash_amount=USDCent(15_00),
+ kind=ContestPrizeKind.CASH,
+ leaderboard_rank=1,
+ ),
+ ContestPrize(
+ name="$10 Cash",
+ estimated_cash_value=USDCent(10_00),
+ cash_amount=USDCent(10_00),
+ kind=ContestPrizeKind.CASH,
+ leaderboard_rank=2,
+ ),
+ ],
+ leaderboard_key=f"leaderboard:{product_user_wallet_yes.uuid}:us:daily:2025-01-01:complete_count",
+ )
+
+
+@pytest.fixture
+def leaderboard_contest_in_db(
+ product_user_wallet_yes: Product,
+ leaderboard_contest_create: LeaderboardContestCreate,
+ contest_manager: ContestManager,
+) -> Contest:
+ return contest_manager.create(
+ product_id=product_user_wallet_yes.uuid,
+ contest_create=leaderboard_contest_create,
+ )
+
+
+@pytest.fixture
+def leaderboard_contest(
+ product_user_wallet_yes: Product,
+ leaderboard_contest_create: LeaderboardContestCreate,
+):
+ from generalresearch.models.thl.contest.io import contest_create_to_contest
+
+ return contest_create_to_contest(
+ product_id=product_user_wallet_yes.uuid,
+ contest_create=leaderboard_contest_create,
+ )
+
+
+@pytest.fixture(scope="function")
+def leaderboard_contest_factory(
+ product_user_wallet_yes: Product,
+ leaderboard_contest_create: LeaderboardContestCreate,
+ contest_manager: ContestManager,
+) -> Callable[..., Contest]:
+
+ def _inner(**kwargs):
+ leaderboard_contest_create.update(**kwargs)
+ return contest_manager.create(
+ product_id=product_user_wallet_yes.uuid,
+ contest_create=leaderboard_contest_create,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def user_with_money(
+ request: Request,
+ user_factory: Callable[..., User],
+ product_user_wallet_yes: Product,
+ thl_lm: ThlLedgerManager,
+) -> User:
+
+ params = getattr(request, "param", {}) or {}
+ min_balance = int(params.get("min_balance", USDCent(1_00)))
+
+ user: User = user_factory(product=product_user_wallet_yes)
+ wallet = thl_lm.get_account_or_create_user_wallet(user)
+ balance = thl_lm.get_account_balance(wallet)
+ todo = min_balance - balance
+ if todo > 0:
+ # # Put money in user's wallet
+ thl_lm.create_tx_user_bonus(
+ user=user,
+ ref_uuid=uuid4().hex,
+ description="bonus",
+ amount=Decimal(todo) / 100,
+ )
+ print(f"wallet balance: {thl_lm.get_user_wallet_balance(user=user)}")
+
+ return user
diff --git a/test_utils/grliq/models/__init__.py b/test_utils/models/gr/__init__.py
index e69de29..e69de29 100644
--- a/test_utils/grliq/models/__init__.py
+++ b/test_utils/models/gr/__init__.py
diff --git a/test_utils/models/gr/conftest.py b/test_utils/models/gr/conftest.py
new file mode 100644
index 0000000..df97306
--- /dev/null
+++ b/test_utils/models/gr/conftest.py
@@ -0,0 +1,213 @@
+from __future__ import annotations
+
+from typing import Callable
+from uuid import uuid4
+
+import pytest
+from pydantic import PositiveInt
+from pydantic_extra_types.phone_numbers import PhoneNumber
+
+from generalresearch.managers.gr.authentication import GRTokenManager, GRUserManager
+from generalresearch.managers.gr.business import (
+ BusinessAddressManager,
+ BusinessBankAccountManager,
+ BusinessManager,
+)
+from generalresearch.managers.gr.team import MembershipManager, TeamManager
+from generalresearch.models.custom_types import UUIDStr
+from generalresearch.models.gr.authentication import GRToken, GRUser
+from generalresearch.models.gr.business import (
+ Business,
+ BusinessAddress,
+ BusinessBankAccount,
+ BusinessType,
+ TransferMethod,
+)
+from generalresearch.models.gr.team import Membership, Team
+from generalresearch.pg_helper import PostgresConfig
+from generalresearch.redis_helper import RedisConfig
+
+# --- Static ---
+
+
+# --- Factory / Database ---
+
+
+@pytest.fixture
+def gr_user_factory(gr_user_manager: GRUserManager) -> Callable[..., GRUser]:
+
+ def _inner(
+ sub: str | None = None,
+ is_superuser: bool = False,
+ ) -> GRUser:
+ sub = sub or f"{uuid4().hex}-{uuid4().hex}"
+
+ return gr_user_manager.create(
+ sub=sub,
+ is_superuser=is_superuser,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def gr_user_cache(
+ gr_user: GRUser,
+ gr_db: PostgresConfig,
+ thl_web_rr: PostgresConfig,
+ gr_redis_config: RedisConfig,
+) -> GRUser:
+ gr_user.set_cache(
+ pg_config=gr_db, thl_web_rr=thl_web_rr, redis_config=gr_redis_config
+ )
+ return gr_user
+
+
+@pytest.fixture
+def gr_business_bank_account_factory(
+ gr_bbam: BusinessBankAccountManager,
+) -> Callable[..., BusinessBankAccount]:
+
+ def _inner(
+ business_id: PositiveInt,
+ uuid: UUIDStr | None = None,
+ transfer_method: TransferMethod | None = None,
+ account_number: str | None = None,
+ routing_number: str | None = None,
+ iban: str | None = None,
+ swift: str | None = None,
+ ):
+ from generalresearch.models.gr.business import TransferMethod
+
+ return gr_bbam.create(
+ business_id=business_id,
+ uuid=uuid or uuid4().hex,
+ transfer_method=transfer_method or TransferMethod.ACH,
+ account_number=account_number or uuid4().hex[:6],
+ routing_number=routing_number or uuid4().hex[:6],
+ iban=iban or uuid4().hex[:6],
+ swift=swift or uuid4().hex[:6],
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def gr_business_address_factory(
+ gr_bam: BusinessAddressManager,
+) -> Callable[..., BusinessAddress]:
+
+ def _inner(
+ business_id: PositiveInt,
+ uuid: UUIDStr | None = None,
+ line_1: str | None = None,
+ line_2: str | None = None,
+ city: str | None = None,
+ state: str | None = None,
+ postal_code: str | None = None,
+ phone_number: PhoneNumber | None = None,
+ country: str | None = None,
+ ):
+ uuid = uuid or uuid4().hex
+ line_1 = line_1 or "abc"
+ line_2 = line_2 or "bczx"
+ city = city or "Downingtown"
+ state = state or "CA"
+ postal_code = postal_code or "94041"
+ phone_number = None
+ country = country or "US"
+
+ return gr_bam.create(
+ business_id=business_id,
+ uuid=uuid,
+ line_1=line_1,
+ line_2=line_2,
+ city=city,
+ state=state,
+ postal_code=postal_code,
+ phone_number=phone_number,
+ country=country,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def gr_business_factory(
+ gr_bm: BusinessManager,
+) -> Callable[..., Business]:
+
+ def _inner(
+ uuid: UUIDStr | None = None,
+ name: str | None = None,
+ team: Team | None = None,
+ kind: BusinessType | None = None,
+ tax_number: str | None = None,
+ ) -> Business:
+ from random import randint
+
+ uuid = uuid or uuid4().hex
+ name = name or "< Unknown >"
+ tax_number = tax_number or str(randint(1, 999_999_999))
+
+ return gr_bm.create(
+ uuid=uuid, name=name, team=team, kind=kind, tax_number=tax_number
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def gr_team(
+ gr_tm: TeamManager,
+) -> Callable[..., Team]:
+
+ def _inner(uuid: UUIDStr | None = None, name: str | None = None) -> Team:
+ uuid = uuid or uuid4().hex
+ name = name or f"name-{uuid4().hex[:12]}"
+
+ return gr_tm.create(uuid=uuid, name=name)
+
+ return _inner
+
+
+@pytest.fixture()
+def gr_user_token(
+ gr_user: GRUser, gr_tm: GRTokenManager, gr_db: PostgresConfig
+) -> GRToken:
+ gr_tm.create(user_id=gr_user.id)
+ gr_user.prefetch_token(pg_config=gr_db)
+
+ res = gr_user.token
+ assert res is not None, "GRToken should exist after creation and prefetching"
+ return res
+
+
+@pytest.fixture()
+def gr_user_token_header(gr_user_token: GRToken) -> dict[str, str]:
+ return gr_user_token.auth_header
+
+
+@pytest.fixture(scope="function")
+def membership(team: Team, gr_user: GRUser, team_manager: TeamManager) -> Membership:
+ assert team.id, "Team must be saved"
+ assert gr_user.id, "GRUser must be saved"
+ return team_manager.add_user(team=team, gr_user=gr_user)
+
+
+@pytest.fixture(scope="function")
+def membership_factory(
+ team: Team,
+ gr_user: GRUser,
+ membership_manager: MembershipManager,
+ team_manager: TeamManager,
+ gr_um: GRUserManager,
+) -> Callable[..., Membership]:
+
+ def _inner(**kwargs) -> Membership:
+ _team = kwargs.get("team", team_manager.create_dummy())
+ _gr_user = kwargs.get("gr_user", gr_um.create_dummy())
+
+ return membership_manager.create(team=_team, gr_user=_gr_user)
+
+ return _inner
diff --git a/test_utils/managers/grliq/__init__.py b/test_utils/models/ledger/__init__.py
index e69de29..e69de29 100644
--- a/test_utils/managers/grliq/__init__.py
+++ b/test_utils/models/ledger/__init__.py
diff --git a/test_utils/models/ledger/conftest.py b/test_utils/models/ledger/conftest.py
new file mode 100644
index 0000000..5bef113
--- /dev/null
+++ b/test_utils/models/ledger/conftest.py
@@ -0,0 +1,724 @@
+from __future__ import annotations
+
+from datetime import datetime
+from decimal import Decimal
+from random import randint
+from typing import TYPE_CHECKING, Callable
+from uuid import uuid4
+
+import pytest
+from fastapi import Request
+
+from generalresearch.currency import USDCent
+from generalresearch.managers.base import PostgresManager
+from test_utils.models.conftest import (
+ payout_config,
+ product_amt_true,
+ product_user_wallet_no,
+ product_user_wallet_yes,
+ session,
+ session_factory,
+ user_factory,
+ wall,
+ wall_factory,
+)
+
+_ = (
+ user_factory,
+ product_user_wallet_no,
+ wall,
+ product_amt_true,
+ product_user_wallet_yes,
+ session_factory,
+ session,
+ wall_factory,
+ payout_config,
+)
+
+if TYPE_CHECKING:
+
+ from generalresearch.currency import LedgerCurrency
+ from generalresearch.managers.thl.ledger_manager.ledger import LedgerManager
+ from generalresearch.managers.thl.ledger_manager.thl_ledger import (
+ ThlLedgerManager,
+ )
+ from generalresearch.managers.thl.payout import (
+ BrokerageProductPayoutEventManager,
+ BusinessPayoutEventManager,
+ )
+ from generalresearch.managers.thl.session import SessionManager
+ from generalresearch.managers.thl.wall import WallManager
+ from generalresearch.models.thl.ledger import (
+ LedgerAccount,
+ LedgerTransaction,
+ )
+ from generalresearch.models.thl.payout import (
+ BrokerageProductPayoutEvent,
+ )
+ from generalresearch.models.thl.product import Product
+ from generalresearch.models.thl.session import Session
+ from generalresearch.models.thl.user import User
+
+
+@pytest.fixture
+def ledger_account(
+ request: Request, lm: LedgerManager, currency: LedgerCurrency
+) -> LedgerAccount:
+ from generalresearch.models.thl.ledger import (
+ AccountType,
+ Direction,
+ LedgerAccount,
+ )
+
+ account_type = getattr(request, "account_type", AccountType.CASH)
+ direction = getattr(request, "direction", Direction.CREDIT)
+
+ acct_uuid = uuid4().hex
+ qn = f"{currency}:{account_type}:{acct_uuid}"
+
+ acct_model = LedgerAccount(
+ uuid=acct_uuid,
+ display_name=f"test-{acct_uuid}",
+ currency=currency,
+ qualified_name=qn,
+ account_type=account_type,
+ normal_balance=direction,
+ )
+ return lm.create_account(account=acct_model)
+
+
+@pytest.fixture
+def ledger_account_factory(
+ request: Request,
+ thl_lm: ThlLedgerManager,
+ lm: LedgerManager,
+ currency: LedgerCurrency,
+) -> Callable[..., LedgerAccount]:
+
+ from generalresearch.models.thl.ledger import (
+ AccountType,
+ Direction,
+ LedgerAccount,
+ )
+
+ def _inner(
+ product: Product,
+ account_type: AccountType = AccountType.CASH,
+ direction: Direction = Direction.CREDIT,
+ ) -> LedgerAccount:
+ thl_lm.get_account_or_create_bp_wallet(product=product)
+ acct_uuid = uuid4().hex
+ qn = f"{currency}:{account_type}:{acct_uuid}"
+
+ acct_model = LedgerAccount(
+ uuid=acct_uuid,
+ display_name=f"test-{acct_uuid}",
+ currency=currency,
+ qualified_name=qn,
+ account_type=account_type,
+ normal_balance=direction,
+ )
+ return lm.create_account(account=acct_model)
+
+ return _inner
+
+
+@pytest.fixture
+def ledger_account_credit(
+ request: Request, lm: LedgerManager, currency: LedgerCurrency
+) -> LedgerAccount:
+ from generalresearch.models.thl.ledger import AccountType, Direction
+
+ account_type = AccountType.REVENUE
+ acct_uuid = uuid4().hex
+
+ qn = f"{currency}:{account_type}:{acct_uuid}"
+ from generalresearch.models.thl.ledger import LedgerAccount
+
+ acct_model = LedgerAccount(
+ uuid=acct_uuid,
+ display_name=f"test-{acct_uuid}",
+ currency=currency,
+ qualified_name=qn,
+ account_type=account_type,
+ normal_balance=Direction.CREDIT,
+ )
+ return lm.create_account(account=acct_model)
+
+
+@pytest.fixture
+def ledger_account_debit(
+ request: Request, lm: LedgerManager, currency: LedgerCurrency
+) -> LedgerAccount:
+ from generalresearch.models.thl.ledger import AccountType, Direction
+
+ account_type = AccountType.EXPENSE
+ acct_uuid = uuid4().hex
+
+ qn = f"{currency}:{account_type}:{acct_uuid}"
+ from generalresearch.models.thl.ledger import LedgerAccount
+
+ acct_model = LedgerAccount(
+ uuid=acct_uuid,
+ display_name=f"test-{acct_uuid}",
+ currency=currency,
+ qualified_name=qn,
+ account_type=account_type,
+ normal_balance=Direction.DEBIT,
+ )
+ return lm.create_account(account=acct_model)
+
+
+@pytest.fixture
+def tag(request: Request, lm: LedgerManager) -> str:
+ from generalresearch.currency import LedgerCurrency
+
+ return (
+ request.param
+ if hasattr(request, "tag")
+ else f"{LedgerCurrency.TEST}:{uuid4().hex}"
+ )
+
+
+@pytest.fixture
+def usd_cent(request: Request) -> USDCent:
+ amount = randint(99, 9_999)
+ return request.param if hasattr(request, "usd_cent") else USDCent(amount)
+
+
+@pytest.fixture
+def bp_payout_event(
+ product: Product,
+ usd_cent: USDCent,
+ business_payout_event_manager: BusinessPayoutEventManager,
+ thl_lm: ThlLedgerManager,
+) -> BrokerageProductPayoutEvent:
+
+ return business_payout_event_manager.create_bp_payout_event(
+ thl_ledger_manager=thl_lm,
+ product=product,
+ amount=usd_cent,
+ skip_wallet_balance_check=True,
+ skip_one_per_day_check=True,
+ )
+
+
+@pytest.fixture
+def bp_payout_event_factory(
+ brokerage_product_payout_event_manager: BrokerageProductPayoutEventManager,
+ thl_lm: ThlLedgerManager,
+) -> Callable[..., BrokerageProductPayoutEvent]:
+
+ def _inner(
+ product: Product, usd_cent: USDCent, ext_ref_id: str | None = None
+ ) -> BrokerageProductPayoutEvent:
+
+ return brokerage_product_payout_event_manager.create_bp_payout_event(
+ thl_ledger_manager=thl_lm,
+ product=product,
+ amount=usd_cent,
+ ext_ref_id=ext_ref_id,
+ skip_wallet_balance_check=True,
+ skip_one_per_day_check=True,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def currency(lm: LedgerManager) -> LedgerCurrency:
+ # return request.param if hasattr(request, "currency") else LedgerCurrency.TEST
+ assert lm.currency, "LedgerManager must have a currency specified for these tests"
+ return lm.currency
+
+
+@pytest.fixture
+def tx_metadata(request: Request) -> dict[str, str] | None:
+ return (
+ request.param
+ if hasattr(request, "tx_metadata")
+ else {f"key-{uuid4().hex[:10]}": uuid4().hex}
+ )
+
+
+@pytest.fixture
+def ledger_tx(
+ request: Request,
+ ledger_account_credit: LedgerAccount,
+ ledger_account_debit: LedgerAccount,
+ tag: str,
+ currency: LedgerCurrency,
+ tx_metadata: dict[str, str] | None,
+ lm: LedgerManager,
+) -> LedgerTransaction:
+ from generalresearch.models.thl.ledger import Direction, LedgerEntry
+
+ amount = int(Decimal("1.00") * 100)
+
+ entries = [
+ LedgerEntry(
+ direction=Direction.CREDIT,
+ account_uuid=ledger_account_credit.uuid,
+ amount=amount,
+ ),
+ LedgerEntry(
+ direction=Direction.DEBIT,
+ account_uuid=ledger_account_debit.uuid,
+ amount=amount,
+ ),
+ ]
+
+ return lm.create_tx(entries=entries, tag=tag, metadata=tx_metadata)
+
+
+@pytest.fixture
+def create_main_accounts(
+ lm: LedgerManager, currency: LedgerCurrency
+) -> Callable[..., None]:
+
+ def _inner() -> None:
+ from generalresearch.models.thl.ledger import (
+ AccountType,
+ Direction,
+ LedgerAccount,
+ )
+
+ account = LedgerAccount(
+ display_name="Cash flow task complete",
+ qualified_name=f"{currency.value}:revenue:task_complete",
+ normal_balance=Direction.CREDIT,
+ account_type=AccountType.REVENUE,
+ currency=lm.currency,
+ )
+ lm.get_account_or_create(account=account)
+
+ account = LedgerAccount(
+ display_name="Operating Cash Account",
+ qualified_name=f"{currency.value}:cash",
+ normal_balance=Direction.DEBIT,
+ account_type=AccountType.CASH,
+ currency=currency,
+ )
+
+ lm.get_account_or_create(account=account)
+
+ return _inner
+
+
+@pytest.fixture
+def delete_ledger_db(thl_web_rw: PostgresManager) -> Callable[..., None]:
+
+ def _inner():
+ for table in [
+ "ledger_transactionmetadata",
+ "ledger_entry",
+ "ledger_transaction",
+ "ledger_account",
+ ]:
+ thl_web_rw.execute_write(
+ query=f"DELETE FROM {table};",
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def wipe_main_accounts(
+ thl_web_rw: PostgresManager, lm: LedgerManager, currency: LedgerCurrency
+) -> Callable[..., None]:
+
+ def _inner() -> None:
+ db_table = thl_web_rw.db_name
+ qual_names = [
+ f"{currency.value}:revenue:task_complete",
+ f"{currency.value}:cash",
+ ]
+
+ res = thl_web_rw.execute_sql_query(
+ query=f"""
+ SELECT lt.id as ltid, le.id as leid, tmd.id as tmdid, la.uuid as lauuid
+ FROM `{db_table}`.`ledger_transaction` AS lt
+ LEFT JOIN `{db_table}`.ledger_entry le
+ ON lt.id = le.transaction_id
+ LEFT JOIN `{db_table}`.ledger_account la
+ ON la.uuid = le.account_id
+ LEFT JOIN `{db_table}`.ledger_transactionmetadata tmd
+ ON lt.id = tmd.transaction_id
+ WHERE la.qualified_name IN %s
+ """,
+ params=[qual_names],
+ )
+
+ lt = {x["ltid"] for x in res if x["ltid"]}
+ le = {x["leid"] for x in res if x["leid"]}
+ tmd = {x["tmdid"] for x in res if x["tmdid"]}
+ la = {x["lauuid"] for x in res if x["lauuid"]}
+
+ thl_web_rw.execute_sql_query(
+ query=f"""
+ DELETE FROM `{db_table}`.`ledger_transactionmetadata`
+ WHERE id IN %s
+ """,
+ params=[tmd],
+ commit=True,
+ )
+
+ thl_web_rw.execute_sql_query(
+ query=f"""
+ DELETE FROM `{db_table}`.`ledger_entry`
+ WHERE id IN %s
+ """,
+ params=[le],
+ commit=True,
+ )
+
+ thl_web_rw.execute_sql_query(
+ query=f"""
+ DELETE FROM `{db_table}`.`ledger_transaction`
+ WHERE id IN %s
+ """,
+ params=[lt],
+ commit=True,
+ )
+
+ thl_web_rw.execute_sql_query(
+ query=f"""
+ DELETE FROM `{db_table}`.`ledger_account`
+ WHERE uuid IN %s
+ """,
+ params=[la],
+ commit=True,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def account_cash(lm: LedgerManager, currency: LedgerCurrency) -> LedgerAccount:
+ from generalresearch.models.thl.ledger import (
+ AccountType,
+ Direction,
+ LedgerAccount,
+ )
+
+ account = LedgerAccount(
+ display_name="Operating Cash Account",
+ qualified_name=f"{currency.value}:cash",
+ normal_balance=Direction.DEBIT,
+ account_type=AccountType.CASH,
+ currency=currency,
+ )
+ return lm.get_account_or_create(account=account)
+
+
+@pytest.fixture
+def account_revenue_task_complete(
+ lm: LedgerManager, currency: LedgerCurrency
+) -> LedgerAccount:
+ from generalresearch.models.thl.ledger import (
+ AccountType,
+ Direction,
+ LedgerAccount,
+ )
+
+ account = LedgerAccount(
+ display_name="Cash flow task complete",
+ qualified_name=f"{currency.value}:revenue:task_complete",
+ normal_balance=Direction.CREDIT,
+ account_type=AccountType.REVENUE,
+ currency=currency,
+ )
+ return lm.get_account_or_create(account=account)
+
+
+@pytest.fixture
+def account_expense_tango(lm: LedgerManager, currency: LedgerCurrency) -> LedgerAccount:
+ from generalresearch.models.thl.ledger import (
+ AccountType,
+ Direction,
+ LedgerAccount,
+ )
+
+ account = LedgerAccount(
+ display_name="Tango Fee",
+ qualified_name=f"{currency.value}:expense:tango_fee",
+ normal_balance=Direction.DEBIT,
+ account_type=AccountType.EXPENSE,
+ currency=currency,
+ )
+ return lm.get_account_or_create(account=account)
+
+
+@pytest.fixture
+def user_account_user_wallet(
+ lm: LedgerManager, user: User, currency: LedgerCurrency
+) -> LedgerAccount:
+ from generalresearch.models.thl.ledger import (
+ AccountType,
+ Direction,
+ LedgerAccount,
+ )
+
+ account = LedgerAccount(
+ display_name=f"{user.uuid} Wallet",
+ qualified_name=f"{currency.value}:user_wallet:{user.uuid}",
+ normal_balance=Direction.CREDIT,
+ account_type=AccountType.USER_WALLET,
+ reference_type="user",
+ reference_uuid=user.uuid,
+ currency=currency,
+ )
+ return lm.get_account_or_create(account=account)
+
+
+@pytest.fixture
+def product_account_bp_wallet(
+ lm: LedgerManager, product: Product, currency: LedgerCurrency
+) -> LedgerAccount:
+ from generalresearch.models.thl.ledger import (
+ AccountType,
+ Direction,
+ LedgerAccount,
+ )
+
+ account = LedgerAccount.model_validate(
+ {
+ "display_name": f"{product.name} Wallet",
+ "qualified_name": f"{currency.value}:bp_wallet:{product.uuid}",
+ "normal_balance": Direction.CREDIT,
+ "account_type": AccountType.BP_WALLET,
+ "reference_type": "bp",
+ "reference_uuid": product.uuid,
+ "currency": currency,
+ }
+ )
+ return lm.get_account_or_create(account=account)
+
+
+@pytest.fixture
+def setup_accounts(
+ product_factory: Callable[..., Product],
+ lm: LedgerManager,
+ user: User,
+ currency: LedgerCurrency,
+) -> None:
+ from generalresearch.models.thl.ledger import (
+ AccountType,
+ Direction,
+ LedgerAccount,
+ )
+
+ # BP's wallet and a revenue from their commissions account.
+ p1 = product_factory()
+
+ account = LedgerAccount(
+ display_name=f"Revenue from {p1.name} commission",
+ qualified_name=f"{currency.value}:revenue:bp_commission:{p1.uuid}",
+ normal_balance=Direction.CREDIT,
+ account_type=AccountType.REVENUE,
+ reference_type="bp",
+ reference_uuid=p1.uuid,
+ currency=currency,
+ )
+ lm.get_account_or_create(account=account)
+
+ account = LedgerAccount.model_validate(
+ {
+ "display_name": f"{p1.name} Wallet",
+ "qualified_name": f"{currency.value}:bp_wallet:{p1.uuid}",
+ "normal_balance": Direction.CREDIT,
+ "account_type": AccountType.BP_WALLET,
+ "reference_type": "bp",
+ "reference_uuid": p1.uuid,
+ "currency": currency,
+ }
+ )
+ lm.get_account_or_create(account=account)
+
+ # BP's wallet, user's wallet, and a revenue from their commissions account.
+ p2 = product_factory()
+ account = LedgerAccount(
+ display_name=f"Revenue from {p2.name} commission",
+ qualified_name=f"{currency.value}:revenue:bp_commission:{p2.uuid}",
+ normal_balance=Direction.CREDIT,
+ account_type=AccountType.REVENUE,
+ reference_type="bp",
+ reference_uuid=p2.uuid,
+ currency=currency,
+ )
+ lm.get_account_or_create(account)
+
+ account = LedgerAccount(
+ display_name=f"{p2.name} Wallet",
+ qualified_name=f"{currency.value}:bp_wallet:{p2.uuid}",
+ normal_balance=Direction.CREDIT,
+ account_type=AccountType.BP_WALLET,
+ reference_type="bp",
+ reference_uuid=p2.uuid,
+ currency=currency,
+ )
+ lm.get_account_or_create(account)
+
+ account = LedgerAccount(
+ display_name=f"{user.uuid} Wallet",
+ qualified_name=f"{currency.value}:user_wallet:{user.uuid}",
+ normal_balance=Direction.CREDIT,
+ account_type=AccountType.USER_WALLET,
+ reference_type="user",
+ reference_uuid=user.uuid,
+ currency="test",
+ )
+ lm.get_account_or_create(account=account)
+
+
+@pytest.fixture
+def session_with_tx_factory(
+ session_factory: Callable[..., Session],
+ session_manager: SessionManager,
+ wall_manager: WallManager,
+ utc_hour_ago: datetime,
+ thl_lm: ThlLedgerManager,
+) -> Callable[..., Session]:
+
+ from generalresearch.models.thl.session import (
+ Status,
+ StatusCode1,
+ )
+
+ def _inner(
+ user: User,
+ final_status: Status = Status.COMPLETE,
+ wall_req_cpi: Decimal = Decimal(".50"),
+ started: datetime = utc_hour_ago,
+ ) -> Session:
+ s: Session = session_factory(
+ user=user,
+ wall_count=2,
+ final_status=final_status,
+ wall_req_cpi=wall_req_cpi,
+ started=started,
+ )
+ last_wall = s.wall_events[-1]
+
+ wall_manager.finish(
+ wall=last_wall,
+ status=Status.COMPLETE,
+ status_code_1=StatusCode1.COMPLETE,
+ finished=last_wall.finished,
+ )
+
+ status, status_code_1 = s.determine_session_status()
+ _, _, bp_pay, user_pay = s.determine_payments()
+ session_manager.finish_with_status(
+ session=s,
+ finished=last_wall.finished,
+ payout=bp_pay,
+ user_payout=user_pay,
+ status=status,
+ status_code_1=status_code_1,
+ )
+
+ thl_lm.create_tx_task_complete(
+ wall=last_wall,
+ user=user,
+ created=last_wall.finished,
+ force=True,
+ )
+
+ thl_lm.create_tx_bp_payment(session=s, created=last_wall.finished, force=True)
+
+ return s
+
+ return _inner
+
+
+@pytest.fixture
+def adj_to_fail_with_tx_factory(
+ session_manager: SessionManager,
+ wall_manager: WallManager,
+ thl_lm: ThlLedgerManager,
+) -> Callable[..., None]:
+ from datetime import timedelta
+
+ from generalresearch.models.thl.definitions import WallAdjustedStatus
+
+ def _inner(
+ session: Session,
+ created: datetime,
+ ) -> None:
+ w1 = wall_manager.get_wall_events(session_id=session.id)[-1]
+
+ # This is defined in `thl-grpc/thl/user_quality_history/recons.py:150`
+ # so we can't use it as part of this test anyway to add rows to the
+ # thl_taskadjustment table anyway.. until we created a
+ # TaskAdjustment Manager to put into generalresearch!
+
+ # create_task_adjustment_event(
+ # wall,
+ # user,
+ # adjusted_status,
+ # amount_usd=amount_usd,
+ # alert_time=alert_time,
+ # ext_status_code=ext_status_code,
+ # )
+
+ wall_manager.adjust_status(
+ wall=w1,
+ adjusted_status=WallAdjustedStatus.ADJUSTED_TO_FAIL,
+ adjusted_cpi=Decimal("0.00"),
+ adjusted_timestamp=created,
+ )
+
+ thl_lm.create_tx_task_adjustment(
+ wall=w1,
+ user=session.user,
+ created=created + timedelta(milliseconds=1),
+ )
+
+ session.wall_events = wall_manager.get_wall_events(session_id=session.id)
+ session_manager.adjust_status(session=session)
+
+ thl_lm.create_tx_bp_adjustment(
+ session=session, created=created + timedelta(milliseconds=2)
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def adj_to_complete_with_tx_factory(
+ session_manager: SessionManager,
+ wall_manager: WallManager,
+ thl_lm: ThlLedgerManager,
+) -> Callable[..., None]:
+ from datetime import timedelta
+
+ from generalresearch.models.thl.definitions import WallAdjustedStatus
+
+ def _inner(
+ session: Session,
+ created: datetime,
+ ) -> None:
+ w1 = wall_manager.get_wall_events(session_id=session.id)[-1]
+
+ wall_manager.adjust_status(
+ wall=w1,
+ adjusted_status=WallAdjustedStatus.ADJUSTED_TO_COMPLETE,
+ adjusted_cpi=w1.req_cpi,
+ adjusted_timestamp=created,
+ )
+
+ thl_lm.create_tx_task_adjustment(
+ wall=w1,
+ user=session.user,
+ created=created + timedelta(milliseconds=1),
+ )
+
+ session.wall_events = wall_manager.get_wall_events(session_id=session.id)
+ session_manager.adjust_status(session=session)
+
+ thl_lm.create_tx_bp_adjustment(
+ session=session, created=created + timedelta(milliseconds=2)
+ )
+
+ return _inner
diff --git a/test_utils/grliq/managers/conftest.py b/test_utils/models/network/__init__.py
index e69de29..e69de29 100644
--- a/test_utils/grliq/managers/conftest.py
+++ b/test_utils/models/network/__init__.py
diff --git a/test_utils/models/network/conftest.py b/test_utils/models/network/conftest.py
new file mode 100644
index 0000000..abfbc18
--- /dev/null
+++ b/test_utils/models/network/conftest.py
@@ -0,0 +1,144 @@
+import os
+from datetime import datetime, timedelta, timezone
+from uuid import uuid4
+
+import pytest
+from fastapi import Request
+
+from generalresearch.managers.network.label import IPLabelManager
+from generalresearch.managers.network.tool_run import ToolRunManager
+from generalresearch.models.network.definitions import IPProtocol
+from generalresearch.models.network.mtr.parser import parse_mtr_output
+from generalresearch.models.network.mtr.result import MTRResult
+from generalresearch.models.network.nmap.parser import parse_nmap_xml
+from generalresearch.models.network.nmap.result import NmapResult
+from generalresearch.models.network.rdns.parser import parse_rdns_output
+from generalresearch.models.network.rdns.result import RDNSResult
+from generalresearch.models.network.tool_run import MTRRun, NmapRun, RDNSRun, Status
+from generalresearch.models.network.tool_run_command import (
+ MTRRunCommand,
+ MTRRunCommandOptions,
+ NmapRunCommand,
+ NmapRunCommandOptions,
+ RDNSRunCommand,
+ RDNSRunCommandOptions,
+)
+from generalresearch.pg_helper import PostgresConfig
+
+
+@pytest.fixture(scope="session")
+def scan_group_id() -> str:
+ return uuid4().hex
+
+
+@pytest.fixture(scope="session")
+def iplabel_manager(thl_web_rw: PostgresConfig) -> IPLabelManager:
+ return IPLabelManager(pg_config=thl_web_rw)
+
+
+@pytest.fixture(scope="session")
+def toolrun_manager(thl_web_rw: PostgresConfig) -> ToolRunManager:
+ return ToolRunManager(pg_config=thl_web_rw)
+
+
+@pytest.fixture(scope="session")
+def nmap_raw_output(request: Request) -> str:
+ fp = os.path.join(request.config.rootpath, "data/nmaprun1.xml")
+ with open(fp) as f:
+ data = f.read()
+ return data
+
+
+@pytest.fixture(scope="session")
+def nmap_result(nmap_raw_output: str) -> NmapResult:
+ return parse_nmap_xml(nmap_raw_output)
+
+
+@pytest.fixture(scope="session")
+def nmap_run(nmap_result: NmapResult, scan_group_id: str):
+ r = nmap_result
+ config = NmapRunCommand(
+ command="nmap",
+ options=NmapRunCommandOptions(
+ ip=r.target_ip, ports="22-1000,11000,1100,3389,61232", top_ports=None
+ ),
+ )
+ return NmapRun(
+ tool_version=r.version,
+ status=Status.SUCCESS,
+ ip=r.target_ip,
+ started_at=r.started_at,
+ finished_at=r.finished_at,
+ raw_command=config.to_command_str(),
+ scan_group_id=scan_group_id,
+ config=config,
+ parsed=r,
+ )
+
+
+@pytest.fixture(scope="session")
+def dig_raw_output() -> str:
+ return "156.32.33.45.in-addr.arpa. 300 IN PTR scanme.nmap.org."
+
+
+@pytest.fixture(scope="session")
+def rdns_result(dig_raw_output: str) -> RDNSResult:
+ return parse_rdns_output(ip="45.33.32.156", raw=dig_raw_output)
+
+
+@pytest.fixture(scope="session")
+def rdns_run(rdns_result: RDNSResult, scan_group_id: str):
+ r = rdns_result
+ ip = "45.33.32.156"
+ utc_now = datetime.now(tz=timezone.utc)
+ config = RDNSRunCommand(command="dig", options=RDNSRunCommandOptions(ip=ip))
+ return RDNSRun(
+ tool_version="1.2.3",
+ status=Status.SUCCESS,
+ ip=ip,
+ started_at=utc_now,
+ finished_at=utc_now + timedelta(seconds=1),
+ raw_command=config.to_command_str(),
+ scan_group_id=scan_group_id,
+ config=config,
+ parsed=r,
+ )
+
+
+@pytest.fixture(scope="session")
+def mtr_raw_output(request: Request) -> str:
+ fp = os.path.join(request.config.rootpath, "data/mtr_fatbeam.json")
+ with open(fp) as f:
+ data = f.read()
+ return data
+
+
+@pytest.fixture(scope="session")
+def mtr_result(mtr_raw_output: str) -> MTRResult:
+ return parse_mtr_output(mtr_raw_output, port=443, protocol=IPProtocol.TCP)
+
+
+@pytest.fixture(scope="session")
+def mtr_run(mtr_result: MTRResult, scan_group_id: str):
+ r = mtr_result
+ utc_now = datetime.now(tz=timezone.utc)
+ config = MTRRunCommand(
+ command="mtr",
+ options=MTRRunCommandOptions(
+ ip=r.destination, protocol=IPProtocol.TCP, port=443
+ ),
+ )
+
+ return MTRRun(
+ tool_version="1.2.3",
+ status=Status.SUCCESS,
+ ip=r.destination,
+ started_at=utc_now,
+ finished_at=utc_now + timedelta(seconds=1),
+ raw_command=config.to_command_str(),
+ scan_group_id=scan_group_id,
+ config=config,
+ parsed=r,
+ facility_id=1,
+ source_ip="1.2.3.4",
+ )
diff --git a/test_utils/grliq/models/conftest.py b/test_utils/models/thl/__init__.py
index e69de29..e69de29 100644
--- a/test_utils/grliq/models/conftest.py
+++ b/test_utils/models/thl/__init__.py
diff --git a/test_utils/models/thl/conftest.py b/test_utils/models/thl/conftest.py
new file mode 100644
index 0000000..cf8d2fa
--- /dev/null
+++ b/test_utils/models/thl/conftest.py
@@ -0,0 +1,434 @@
+from __future__ import annotations
+
+from datetime import datetime, timezone
+from decimal import ROUND_DOWN, Decimal
+from random import choice as rand_choice
+from random import choice as rchoice
+from random import randint, random
+from typing import Any, Callable
+from uuid import uuid4
+
+import faker
+import pytest
+from pydantic import PositiveInt
+
+from generalresearch.managers.thl.ipinfo import IPGeonameManager, IPInformationManager
+from generalresearch.managers.thl.payout import UserPayoutEventManager
+from generalresearch.managers.thl.product import ProductManager
+from generalresearch.managers.thl.session import SessionManager
+from generalresearch.managers.thl.user_manager.user_manager import UserManager
+from generalresearch.managers.thl.userhealth import AuditLogManager, IPRecordManager
+from generalresearch.managers.thl.wall import WallManager
+from generalresearch.models import DeviceType
+from generalresearch.models.custom_types import (
+ AwareDatetimeISO,
+ IPvAnyAddressStr,
+ UUIDStr,
+)
+from generalresearch.models.legacy.bucket import Bucket
+from generalresearch.models.thl.definitions import (
+ PayoutStatus,
+)
+from generalresearch.models.thl.ipinfo import IPGeoname, IPInformation, UserType
+from generalresearch.models.thl.payout import UserPayoutEvent
+from generalresearch.models.thl.product import (
+ PayoutConfig,
+ Product,
+ ProfilingConfig,
+ SessionConfig,
+ SourcesConfig,
+ SupplyConfig,
+ UserCreateConfig,
+ UserHealthConfig,
+ UserWalletConfig,
+)
+from generalresearch.models.thl.session import (
+ Session,
+ Source,
+ Status,
+ Wall,
+)
+from generalresearch.models.thl.user import User
+from generalresearch.models.thl.user_iphistory import IPRecord
+from generalresearch.models.thl.userhealth import AuditLog, AuditLogLevel
+from generalresearch.models.thl.wallet import PayoutType
+from generalresearch.models.thl.wallet.cashout_method import CashMailOrderData
+
+fake = faker.Faker()
+
+
+@pytest.fixture
+def wall_status() -> Status:
+ return Status.COMPLETE
+
+
+@pytest.fixture
+def user_factory(user_manager: UserManager) -> Callable[..., User]:
+
+ def _inner(
+ # --- Create dummy "optional" --- #
+ product_user_id: str | None = None,
+ # --- Optional --- #
+ product_id: UUIDStr | None = None,
+ product: Product | None = None,
+ created: datetime | None = None,
+ ) -> User:
+
+ product_user_id = product_user_id or uuid4().hex
+
+ return user_manager.create_user(
+ product_user_id=product_user_id,
+ product_id=product_id,
+ product=product,
+ created=created,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def wall_factory(
+ wall_manager: WallManager, session_factory: Session
+) -> Callable[..., Wall]:
+
+ def _inner(
+ session_id: int | None = None,
+ user_id: int | None = None,
+ started: datetime | None = None,
+ source: Source | None = None,
+ req_survey_id: str | None = None,
+ req_cpi: Decimal | None = None,
+ buyer_id: str | None = None,
+ uuid_id: str | None = None,
+ ):
+ """To be used in tests, where we don't care about certain fields"""
+
+ user_id = user_id or fake.random_int(min=1, max=2_147_483_648)
+ started = started or fake.date_time_between(
+ start_date=datetime(year=1900, month=1, day=1, tzinfo=timezone.utc),
+ end_date=datetime.now(tz=timezone.utc),
+ tzinfo=timezone.utc,
+ )
+
+ if session_id is None:
+ # session = SessionManager(pg_config=self.pg_config).create_dummy(
+ # started=started
+ # )
+ session = session_factory()
+ session_id = session.id
+
+ source = source or rchoice(list(Source))
+ req_survey_id = req_survey_id or uuid4().hex
+ req_cpi = req_cpi or Decimal(fake.random_int(min=1, max=150) / 100).quantize(
+ Decimal(".01"), rounding=ROUND_DOWN
+ )
+
+ return wall_manager.create(
+ session_id=session_id,
+ user_id=user_id,
+ started=started,
+ source=source,
+ req_survey_id=req_survey_id,
+ req_cpi=req_cpi,
+ buyer_id=buyer_id,
+ uuid_id=uuid_id,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def product_factory(product_manager: ProductManager) -> Callable[..., Product]:
+
+ def _inner(
+ product_id: UUIDStr | None = None,
+ team_id: UUIDStr | None = None,
+ business_id: UUIDStr | None = None,
+ name: str | None = None,
+ redirect_url: str | None = None,
+ harmonizer_domain: str | None = None,
+ commission_pct: Decimal = Decimal("0.05000"),
+ sources_config: SourcesConfig | SupplyConfig | None = None,
+ payout_config: PayoutConfig | None = None,
+ session_config: SessionConfig | None = None,
+ profiling_config: ProfilingConfig | None = None,
+ user_wallet_config: UserWalletConfig | None = None,
+ user_create_config: UserCreateConfig | None = None,
+ user_health_config: UserHealthConfig | None = None,
+ ) -> 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
+ 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,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def session_factory(session_manager: SessionManager):
+
+ def _inner(
+ # -- Create Dummy "optional" -- #
+ started: datetime | None = None,
+ user: User | None = None,
+ # -- Optional -- #
+ country_iso: str | None = None,
+ device_type: DeviceType | None = None,
+ ip: str | None = None,
+ bucket: Bucket | None = None,
+ url_metadata: dict[str, str] | None = None,
+ uuid_id: str | None = None,
+ ) -> Session:
+ """To be used in tests, where we don't care about certain fields"""
+ started = started or fake.date_time_between(
+ start_date=datetime(year=1900, month=1, day=1, tzinfo=timezone.utc),
+ end_date=datetime(year=2000, month=1, day=1, tzinfo=timezone.utc),
+ tzinfo=timezone.utc,
+ )
+ user = user or User(
+ user_id=fake.random_int(min=1, max=2_147_483_648), uuid=uuid4().hex
+ )
+
+ return session_manager.create(
+ started=started,
+ user=user,
+ country_iso=country_iso,
+ device_type=device_type,
+ ip=ip,
+ bucket=bucket,
+ url_metadata=url_metadata,
+ uuid_id=uuid_id,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def ipgeoname_factory(ipgeoname_manager: IPGeonameManager) -> Callable[..., IPGeoname]:
+
+ def _inner(
+ geoname_id: PositiveInt | None = None,
+ continent_code: str | None = None,
+ continent_name: str | None = None,
+ country_iso: str | None = None,
+ country_name: str | None = None,
+ subdivision_1_iso: str | None = None,
+ subdivision_1_name: str | None = None,
+ subdivision_2_iso: str | None = None,
+ subdivision_2_name: str | None = None,
+ city_name: str | None = None,
+ metro_code: int | None = None,
+ time_zone: str | None = None,
+ is_in_european_union: bool | None = None,
+ ) -> IPGeoname:
+
+ return ipgeoname_manager.create(
+ geoname_id=geoname_id or randint(1, 999_999_999),
+ continent_code=continent_code or "na",
+ continent_name=continent_name or "North America",
+ country_iso=country_iso or "us",
+ country_name=country_name or "United States",
+ subdivision_1_iso=subdivision_1_iso or "fl",
+ subdivision_1_name=subdivision_1_name or "Florida",
+ subdivision_2_iso=subdivision_2_iso,
+ subdivision_2_name=subdivision_2_name,
+ city_name=city_name,
+ metro_code=metro_code,
+ time_zone=time_zone,
+ is_in_european_union=is_in_european_union,
+ )
+
+ return _inner
+
+
+def ipinformation_factory(
+ ipinformation_manager: IPInformationManager,
+) -> Callable[..., IPInformation]:
+
+ def _inner(
+ ip: IPvAnyAddressStr | None = None,
+ geoname_id: PositiveInt | None = None,
+ country_iso: str | None = None,
+ registered_country_iso: str | None = None,
+ is_anonymous: bool | None = None,
+ is_anonymous_vpn: bool | None = None,
+ is_hosting_provider: bool | None = None,
+ is_public_proxy: bool | None = None,
+ is_tor_exit_node: bool | None = None,
+ is_residential_proxy: bool | None = None,
+ autonomous_system_number: PositiveInt | None = None,
+ autonomous_system_organization: str | None = None,
+ domain: str | None = None,
+ isp: str | None = None,
+ mobile_country_code: str | None = None,
+ mobile_network_code: str | None = None,
+ network: str | None = None,
+ organization: str | None = None,
+ static_ip_score: float | None = None,
+ user_type: UserType | None = None,
+ postal_code: str | None = None,
+ latitude: Decimal | None = None,
+ longitude: Decimal | None = None,
+ accuracy_radius: int | None = None,
+ ) -> IPInformation:
+
+ return ipinformation_manager.create(
+ ip=ip or fake.ipv4_public(),
+ geoname_id=geoname_id,
+ country_iso=country_iso or fake.country_code(),
+ registered_country_iso=registered_country_iso,
+ is_anonymous=is_anonymous,
+ is_anonymous_vpn=is_anonymous_vpn,
+ is_hosting_provider=is_hosting_provider,
+ is_public_proxy=is_public_proxy,
+ is_tor_exit_node=is_tor_exit_node,
+ is_residential_proxy=is_residential_proxy,
+ autonomous_system_number=autonomous_system_number,
+ autonomous_system_organization=autonomous_system_organization,
+ domain=domain,
+ isp=isp,
+ mobile_country_code=mobile_country_code,
+ mobile_network_code=mobile_network_code,
+ network=network,
+ organization=organization,
+ static_ip_score=static_ip_score,
+ user_type=user_type,
+ postal_code=postal_code,
+ latitude=latitude,
+ longitude=longitude,
+ accuracy_radius=accuracy_radius,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def user_payout_event_factory(
+ user_payout_event_manager: UserPayoutEventManager,
+) -> Callable[..., UserPayoutEvent]:
+
+ def _inner(
+ uuid: UUIDStr | None = None,
+ debit_account_uuid: UUIDStr | None = None,
+ account_reference_type: str | None = None,
+ account_reference_uuid: UUIDStr | None = None,
+ cashout_method_uuid: UUIDStr | None = None,
+ description: str | None = None,
+ created: AwareDatetimeISO | None = None,
+ amount: PositiveInt | None = None,
+ status: PayoutStatus | None = None,
+ ext_ref_id: str | None = None,
+ payout_type: PayoutType | None = None,
+ request_data: dict[str, Any] | None = None,
+ order_data: dict[str, Any] | CashMailOrderData | None = None,
+ ) -> UserPayoutEvent:
+
+ debit_account_uuid = debit_account_uuid or uuid4().hex
+ cashout_method_uuid = cashout_method_uuid or uuid4().hex
+ # account_reference_type = account_reference_type or f"acct-ref-{uuid4().hex}"
+ # account_reference_uuid = account_reference_uuid or uuid4().hex
+ # cashout_method_uuid = cashout_method_uuid or uuid4().hex
+ amount = amount or randint(a=99, b=9_999)
+ status = status or rand_choice(list(PayoutStatus))
+
+ description = description or f"desc-{uuid4().hex[:12]}"
+ # ext_ref_id = ext_ref_id or f"ext-ref-{uuid4().hex[:8]}"
+ payout_type = payout_type or rand_choice(list(PayoutType))
+ request_data = request_data or {}
+ # order_data = order_data or None
+
+ return user_payout_event_manager.create(
+ uuid=uuid,
+ debit_account_uuid=debit_account_uuid,
+ account_reference_type=account_reference_type,
+ account_reference_uuid=account_reference_uuid,
+ cashout_method_uuid=cashout_method_uuid,
+ description=description,
+ created=created,
+ amount=amount,
+ status=status,
+ ext_ref_id=ext_ref_id,
+ payout_type=payout_type,
+ request_data=request_data,
+ order_data=order_data,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def iprecord_factory(iprecord_manager: IPRecordManager) -> Callable[..., IPRecord]:
+
+ def _inner(
+ user_id: PositiveInt,
+ ip: IPvAnyAddressStr | None = None,
+ forwarded_ip1: IPvAnyAddressStr | None = None,
+ forwarded_ip2: IPvAnyAddressStr | None = None,
+ forwarded_ip3: IPvAnyAddressStr | None = None,
+ forwarded_ip4: IPvAnyAddressStr | None = None,
+ forwarded_ip5: IPvAnyAddressStr | None = None,
+ forwarded_ip6: IPvAnyAddressStr | None = None,
+ ) -> IPRecord:
+ return iprecord_manager.create(
+ user_id=user_id,
+ ip=ip or fake.ipv4_public(),
+ forwarded_ip1=(forwarded_ip1 or fake.ipv4_public()),
+ forwarded_ip2=(forwarded_ip2 or fake.ipv6() if random() < 0.5 else None),
+ forwarded_ip3=(
+ forwarded_ip3 or fake.ipv4_public() if random() < 0.25 else None
+ ),
+ forwarded_ip4=forwarded_ip4,
+ forwarded_ip5=forwarded_ip5,
+ forwarded_ip6=forwarded_ip6,
+ )
+
+ return _inner
+
+
+# class AuditLogManager(PostgresManager):
+
+
+@pytest.fixture
+def auditlog_factory(audit_log_manager: AuditLogManager):
+
+ def _inner(
+ user_id: PositiveInt,
+ level: AuditLogLevel | None = None,
+ event_type: str | None = None,
+ event_msg: str | None = None,
+ event_value: float | None = None,
+ ) -> AuditLog:
+
+ event_types = {
+ "offerwall-enter.blocked",
+ "offerwall-enter.rate-limited",
+ "offerwall-enter.url-modified",
+ }
+
+ return audit_log_manager.create(
+ user_id=user_id,
+ level=level or rchoice(list(AuditLogLevel)),
+ event_type=event_type or rchoice(list(event_types)),
+ event_msg=event_msg,
+ event_value=event_value,
+ )
+
+ return _inner
diff --git a/test_utils/models/upk/__init__.py b/test_utils/models/upk/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test_utils/models/upk/__init__.py
diff --git a/test_utils/models/upk/conftest.py b/test_utils/models/upk/conftest.py
new file mode 100644
index 0000000..c8855da
--- /dev/null
+++ b/test_utils/models/upk/conftest.py
@@ -0,0 +1,178 @@
+from __future__ import annotations
+
+import os
+import time
+from typing import TYPE_CHECKING
+from uuid import UUID
+
+import pandas as pd
+import pytest
+
+from generalresearch.pg_helper import PostgresConfig
+
+if TYPE_CHECKING:
+ from generalresearch.managers.thl.category import CategoryManager
+
+
+def insert_data_from_csv(
+ thl_web_rw: PostgresConfig,
+ table_name: str,
+ fp: str | None = None,
+ disable_fk_checks: bool = False,
+ df: pd.DataFrame | None = None,
+):
+ assert fp is not None or df is not None and not (fp is not None and df is not None)
+ if fp:
+ df = pd.read_csv(fp, dtype=str)
+
+ assert isinstance(df, pd.DataFrame)
+
+ df = df.where(pd.notnull(df), None)
+ cols = list(df.columns)
+ col_str = ", ".join(cols)
+ values_str = ", ".join(["%s"] * len(cols))
+ if "id" in df.columns and len(df["id"].iloc[0]) == 36:
+ df["id"] = df["id"].map(lambda x: UUID(x).hex)
+ args = df.to_dict("tight")["data"]
+
+ with thl_web_rw.make_connection() as conn:
+ with conn.cursor() as c:
+ if disable_fk_checks:
+ c.execute("SET CONSTRAINTS ALL DEFERRED")
+ c.executemany(
+ f"INSERT INTO {table_name} ({col_str}) VALUES ({values_str})",
+ params_seq=args,
+ )
+ conn.commit()
+
+
+@pytest.fixture(scope="session")
+def category_data(
+ thl_web_rw: PostgresConfig, category_manager: CategoryManager
+) -> None:
+ fp = os.path.join(os.path.dirname(__file__), "marketplace_category.csv.gz")
+ insert_data_from_csv(
+ thl_web_rw,
+ fp=fp,
+ table_name="marketplace_category",
+ disable_fk_checks=True,
+ )
+ # Don't strictly need to do this, but probably we should
+ category_manager.populate_caches()
+ cats = category_manager.categories.values()
+ path_id = {c.path: c.id for c in cats}
+ data = [
+ {"id": c.id, "parent_id": path_id[c.parent_path]} for c in cats if c.parent_path
+ ]
+ query = """
+ UPDATE marketplace_category
+ SET parent_id = %(parent_id)s
+ WHERE id = %(id)s;
+ """
+ with thl_web_rw.make_connection() as conn:
+ with conn.cursor() as c:
+ c.executemany(query=query, params_seq=data)
+ conn.commit()
+
+
+@pytest.fixture(scope="session")
+def property_data(thl_web_rw: PostgresConfig) -> None:
+ fp = os.path.join(os.path.dirname(__file__), "marketplace_property.csv.gz")
+ insert_data_from_csv(thl_web_rw, fp=fp, table_name="marketplace_property")
+
+
+@pytest.fixture(scope="session")
+def item_data(thl_web_rw: PostgresConfig) -> None:
+ fp = os.path.join(os.path.dirname(__file__), "marketplace_item.csv.gz")
+ insert_data_from_csv(thl_web_rw, fp=fp, table_name="marketplace_item")
+
+
+@pytest.fixture(scope="session")
+def propertycategoryassociation_data(
+ thl_web_rw: PostgresConfig,
+ category_data,
+ property_data,
+ category_manager: CategoryManager,
+) -> None:
+ table_name = "marketplace_propertycategoryassociation"
+ fp = os.path.join(os.path.dirname(__file__), f"{table_name}.csv.gz")
+ # Need to lookup category pk from uuid
+ category_manager.populate_caches()
+ df = pd.read_csv(fp, dtype=str)
+ df["category_id"] = df["category_id"].map(
+ lambda x: category_manager.categories[x].id
+ )
+ insert_data_from_csv(thl_web_rw, df=df, table_name=table_name)
+
+
+@pytest.fixture(scope="session")
+def propertycountry_data(thl_web_rw: PostgresConfig, property_data) -> None:
+ fp = os.path.join(os.path.dirname(__file__), "marketplace_propertycountry.csv.gz")
+ insert_data_from_csv(thl_web_rw, fp=fp, table_name="marketplace_propertycountry")
+
+
+@pytest.fixture(scope="session")
+def propertymarketplaceassociation_data(
+ thl_web_rw: PostgresConfig, property_data
+) -> None:
+ table_name = "marketplace_propertymarketplaceassociation"
+ fp = os.path.join(os.path.dirname(__file__), f"{table_name}.csv.gz")
+ insert_data_from_csv(thl_web_rw, fp=fp, table_name=table_name)
+
+
+@pytest.fixture(scope="session")
+def propertyitemrange_data(
+ thl_web_rw: PostgresConfig, property_data, item_data
+) -> None:
+ table_name = "marketplace_propertyitemrange"
+ fp = os.path.join(os.path.dirname(__file__), f"{table_name}.csv.gz")
+ insert_data_from_csv(thl_web_rw, fp=fp, table_name=table_name)
+
+
+@pytest.fixture(scope="session")
+def question_data(thl_web_rw: PostgresConfig) -> None:
+ table_name = "marketplace_question"
+ fp = os.path.join(os.path.dirname(__file__), f"{table_name}.csv.gz")
+ insert_data_from_csv(
+ thl_web_rw, fp=fp, table_name=table_name, disable_fk_checks=True
+ )
+
+
+@pytest.fixture(scope="session")
+def clear_upk_tables(thl_web_rw: PostgresConfig):
+ tables = [
+ "marketplace_propertyitemrange",
+ "marketplace_propertymarketplaceassociation",
+ "marketplace_propertycategoryassociation",
+ "marketplace_category",
+ "marketplace_item",
+ "marketplace_property",
+ "marketplace_propertycountry",
+ "marketplace_question",
+ ]
+ table_str = ", ".join(tables)
+
+ with thl_web_rw.make_connection() as conn:
+ with conn.cursor() as c:
+ c.execute(f"TRUNCATE {table_str} RESTART IDENTITY CASCADE;")
+ conn.commit()
+
+
+@pytest.fixture(scope="session")
+def upk_data(
+ clear_upk_tables,
+ category_data,
+ property_data,
+ item_data,
+ propertycategoryassociation_data,
+ propertycountry_data,
+ propertymarketplaceassociation_data,
+ propertyitemrange_data,
+ question_data,
+) -> None:
+ # Wait a second to make sure the HarmonizerCache refresh loop pulls these in
+ time.sleep(2)
+
+
+def test_fixtures(upk_data):
+ pass
diff --git a/test_utils/managers/upk/marketplace_category.csv.gz b/test_utils/models/upk/marketplace_category.csv.gz
index 0f8ec1c..0f8ec1c 100644
--- a/test_utils/managers/upk/marketplace_category.csv.gz
+++ b/test_utils/models/upk/marketplace_category.csv.gz
Binary files differ
diff --git a/test_utils/managers/upk/marketplace_item.csv.gz b/test_utils/models/upk/marketplace_item.csv.gz
index c12c5d8..c12c5d8 100644
--- a/test_utils/managers/upk/marketplace_item.csv.gz
+++ b/test_utils/models/upk/marketplace_item.csv.gz
Binary files differ
diff --git a/test_utils/managers/upk/marketplace_property.csv.gz b/test_utils/models/upk/marketplace_property.csv.gz
index a781d1d..a781d1d 100644
--- a/test_utils/managers/upk/marketplace_property.csv.gz
+++ b/test_utils/models/upk/marketplace_property.csv.gz
Binary files differ
diff --git a/test_utils/managers/upk/marketplace_propertycategoryassociation.csv.gz b/test_utils/models/upk/marketplace_propertycategoryassociation.csv.gz
index 5b4ea19..5b4ea19 100644
--- a/test_utils/managers/upk/marketplace_propertycategoryassociation.csv.gz
+++ b/test_utils/models/upk/marketplace_propertycategoryassociation.csv.gz
Binary files differ
diff --git a/test_utils/managers/upk/marketplace_propertycountry.csv.gz b/test_utils/models/upk/marketplace_propertycountry.csv.gz
index 5d2a637..5d2a637 100644
--- a/test_utils/managers/upk/marketplace_propertycountry.csv.gz
+++ b/test_utils/models/upk/marketplace_propertycountry.csv.gz
Binary files differ
diff --git a/test_utils/managers/upk/marketplace_propertyitemrange.csv.gz b/test_utils/models/upk/marketplace_propertyitemrange.csv.gz
index 84f4f0e..84f4f0e 100644
--- a/test_utils/managers/upk/marketplace_propertyitemrange.csv.gz
+++ b/test_utils/models/upk/marketplace_propertyitemrange.csv.gz
Binary files differ
diff --git a/test_utils/managers/upk/marketplace_propertymarketplaceassociation.csv.gz b/test_utils/models/upk/marketplace_propertymarketplaceassociation.csv.gz
index 6b9fd1c..6b9fd1c 100644
--- a/test_utils/managers/upk/marketplace_propertymarketplaceassociation.csv.gz
+++ b/test_utils/models/upk/marketplace_propertymarketplaceassociation.csv.gz
Binary files differ
diff --git a/test_utils/managers/upk/marketplace_question.csv.gz b/test_utils/models/upk/marketplace_question.csv.gz
index bcfc3ad..bcfc3ad 100644
--- a/test_utils/managers/upk/marketplace_question.csv.gz
+++ b/test_utils/models/upk/marketplace_question.csv.gz
Binary files differ