aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorMax Nanis2026-08-21 11:31:13 -0700
committerMax Nanis2026-08-21 11:31:13 -0700
commitff538deb290c851364df85aa6ccc64bc3719ef64 (patch)
treec04c3573ab6adab70971fef00d3420a5da5f9619 /tests
parent4fe0f6b5e0f0c744902e4c3ab8940e23a6f8a2e1 (diff)
parentc4a44873540ca4c0a3ab19b9beef4cfc6e0252a7 (diff)
downloadgeneralresearch-ff538deb290c851364df85aa6ccc64bc3719ef64.tar.gz
generalresearch-ff538deb290c851364df85aa6ccc64bc3719ef64.zip
Merge branch 'master' into dev
Diffstat (limited to 'tests')
-rw-r--r--tests/conftest.py10
-rw-r--r--tests/grliq/managers/test_forensic_data.py35
-rw-r--r--tests/grliq/managers/test_forensic_results.py4
-rw-r--r--tests/incite/collections/test_df_collection_item_thl_web.py26
-rw-r--r--tests/incite/collections/test_df_collection_thl_marketplaces.py2
-rw-r--r--tests/incite/collections/test_df_collection_thl_web.py27
-rw-r--r--tests/incite/test_collection_base.py6
-rw-r--r--tests/models/admin/test_report_request.py23
-rw-r--r--tests/models/custom_types/test_aware_datetime.py7
-rw-r--r--tests/models/custom_types/test_dsn.py9
-rw-r--r--tests/models/custom_types/test_uuid_str.py7
-rw-r--r--tests/models/dynata/test_eligbility.py10
-rw-r--r--tests/models/gr/test_authentication.py36
-rw-r--r--tests/models/gr/test_base.py46
-rw-r--r--tests/models/gr/test_business.py75
-rw-r--r--tests/models/thl/test_product.py53
-rw-r--r--tests/pytest.ini3
-rw-r--r--tests/test_postgres.py68
18 files changed, 298 insertions, 149 deletions
diff --git a/tests/conftest.py b/tests/conftest.py
index 2482269..6748592 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -3,8 +3,6 @@ pytest_plugins = [
"test_utils.conftest",
# -- GRL IQ
"test_utils.grliq.conftest",
- "test_utils.grliq.managers.conftest",
- "test_utils.grliq.models.conftest",
# -- Incite
"test_utils.incite.conftest",
"test_utils.incite.collections.conftest",
@@ -12,9 +10,17 @@ pytest_plugins = [
# -- Managers
"test_utils.managers.conftest",
"test_utils.managers.contest.conftest",
+ "test_utils.managers.gr.conftest",
"test_utils.managers.ledger.conftest",
"test_utils.managers.network.conftest",
+ "test_utils.managers.thl.conftest",
"test_utils.managers.upk.conftest",
# -- Models
"test_utils.models.conftest",
+ "test_utils.models.contest.conftest",
+ "test_utils.models.gr.conftest",
+ "test_utils.models.ledger.conftest",
+ "test_utils.models.network.conftest",
+ "test_utils.models.thl.conftest",
+ "test_utils.models.upk.conftest",
]
diff --git a/tests/grliq/managers/test_forensic_data.py b/tests/grliq/managers/test_forensic_data.py
index ac2792a..e4854e8 100644
--- a/tests/grliq/managers/test_forensic_data.py
+++ b/tests/grliq/managers/test_forensic_data.py
@@ -1,20 +1,23 @@
+from __future__ import annotations
+
from datetime import timedelta
from typing import TYPE_CHECKING
from uuid import uuid4
import pytest
+from generalresearch.grliq.models.events import MouseEvent, TimingData
+from generalresearch.grliq.models.forensic_data import GrlIqData
+from generalresearch.grliq.models.forensic_result import (
+ GrlIqCheckerResults,
+ GrlIqForensicCategoryResult,
+)
+
if TYPE_CHECKING:
from generalresearch.grliq.managers.forensic_data import (
GrlIqDataManager,
GrlIqEventManager,
)
- from generalresearch.grliq.models.events import MouseEvent, TimingData
- from generalresearch.grliq.models.forensic_data import GrlIqData
- from generalresearch.grliq.models.forensic_result import (
- GrlIqCheckerResults,
- GrlIqForensicCategoryResult,
- )
from generalresearch.models.thl.product import Product
try:
@@ -25,7 +28,7 @@ except ImportError:
class TestGrlIqDataManager:
- def test_create_dummy(self, grliq_dm: "GrlIqDataManager"):
+ def test_create_dummy(self, grliq_dm: GrlIqDataManager):
from generalresearch.grliq.models.forensic_data import GrlIqData
gd1: GrlIqData = grliq_dm.create_dummy(is_attempt_allowed=True)
@@ -34,7 +37,7 @@ class TestGrlIqDataManager:
assert isinstance(gd1.results, GrlIqCheckerResults)
assert isinstance(gd1.category_result, GrlIqForensicCategoryResult)
- def test_create(self, grliq_data: "GrlIqData", grliq_dm: "GrlIqDataManager"):
+ def test_create(self, grliq_data: GrlIqData, grliq_dm: GrlIqDataManager):
grliq_dm.create(grliq_data)
assert grliq_data.id is not None
@@ -53,13 +56,13 @@ class TestGrlIqDataManager:
def test_update_data(self):
pass
- def test_get_id(self, grliq_data: "GrlIqData", grliq_dm: "GrlIqDataManager"):
+ def test_get_id(self, grliq_data: GrlIqData, grliq_dm: GrlIqDataManager):
grliq_dm.create(grliq_data)
res = grliq_dm.get_data(forensic_id=grliq_data.id)
assert res == grliq_data
- def test_get_uuid(self, grliq_data: "GrlIqData", grliq_dm: "GrlIqDataManager"):
+ def test_get_uuid(self, grliq_data: GrlIqData, grliq_dm: GrlIqDataManager):
grliq_dm.create(grliq_data)
res = grliq_dm.get_data(forensic_uuid=grliq_data.uuid)
@@ -73,7 +76,7 @@ class TestGrlIqDataManager:
def test_get_unique_user_count_by_fingerprint(self):
pass
- def test_filter_data(self, grliq_data: "GrlIqData", grliq_dm: "GrlIqDataManager"):
+ def test_filter_data(self, grliq_data: GrlIqData, grliq_dm: GrlIqDataManager):
grliq_dm.create(grliq_data)
res = grliq_dm.filter_data(uuids=[grliq_data.uuid])[0]
assert res == grliq_data
@@ -100,7 +103,7 @@ class TestGrlIqDataManager:
def test_make_filter_str(self):
pass
- def test_filter_count(self, grliq_dm: "GrlIqDataManager", product: "Product"):
+ def test_filter_count(self, grliq_dm: GrlIqDataManager, product: Product):
res = grliq_dm.filter_count(product_id=product.uuid)
assert isinstance(res, int)
@@ -116,7 +119,7 @@ class TestGrlIqDataManager:
class TestForensicDataGetAndFilter:
- def test_events(self, grliq_dm: "GrlIqDataManager"):
+ def test_events(self, grliq_dm: GrlIqDataManager):
"""If load_events=True, the events and mouse_events attributes should
be an array no matter what. An empty array means that the events were
loaded, but there were no events available.
@@ -141,7 +144,7 @@ class TestForensicDataGetAndFilter:
assert len(instance.events) == 0
assert len(instance.mouse_events) == 0
- def test_timing(self, grliq_dm: "GrlIqDataManager", grliq_em: "GrlIqEventManager"):
+ def test_timing(self, grliq_dm: GrlIqDataManager, grliq_em: GrlIqEventManager):
forensic_uuid = uuid4().hex
grliq_dm.create_dummy(is_attempt_allowed=True, uuid=forensic_uuid)
@@ -161,7 +164,7 @@ class TestForensicDataGetAndFilter:
assert isinstance(instance.timing_data, TimingData)
def test_events_events(
- self, grliq_dm: "GrlIqDataManager", grliq_em: "GrlIqEventManager"
+ self, grliq_dm: GrlIqDataManager, grliq_em: GrlIqEventManager
):
forensic_uuid = uuid4().hex
grliq_dm.create_dummy(is_attempt_allowed=True, uuid=forensic_uuid)
@@ -186,7 +189,7 @@ class TestForensicDataGetAndFilter:
assert len(instance.keyboard_events) == 0
def test_events_click(
- self, grliq_dm: "GrlIqDataManager", grliq_em: "GrlIqEventManager"
+ self, grliq_dm: GrlIqDataManager, grliq_em: GrlIqEventManager
):
forensic_uuid = uuid4().hex
grliq_dm.create_dummy(is_attempt_allowed=True, uuid=forensic_uuid)
diff --git a/tests/grliq/managers/test_forensic_results.py b/tests/grliq/managers/test_forensic_results.py
index 68db732..a030451 100644
--- a/tests/grliq/managers/test_forensic_results.py
+++ b/tests/grliq/managers/test_forensic_results.py
@@ -1,3 +1,5 @@
+from __future__ import annotations
+
from typing import TYPE_CHECKING
if TYPE_CHECKING:
@@ -10,7 +12,7 @@ if TYPE_CHECKING:
class TestGrlIqCategoryResultsReader:
def test_filter_category_results(
- self, grliq_dm: "GrlIqDataManager", grliq_crr: "GrlIqCategoryResultsReader"
+ self, grliq_dm: GrlIqDataManager, grliq_crr: GrlIqCategoryResultsReader
):
from generalresearch.grliq.models.forensic_result import (
GrlIqForensicCategoryResult,
diff --git a/tests/incite/collections/test_df_collection_item_thl_web.py b/tests/incite/collections/test_df_collection_item_thl_web.py
index a858fbe..8b8bcbe 100644
--- a/tests/incite/collections/test_df_collection_item_thl_web.py
+++ b/tests/incite/collections/test_df_collection_item_thl_web.py
@@ -1,3 +1,6 @@
+from __future__ import annotations
+
+from collections.abc import Generator
from datetime import datetime, timedelta, timezone
from itertools import product as iter_product
from os.path import join as pjoin
@@ -12,13 +15,7 @@ from distributed import Client, Scheduler, Worker
# noinspection PyUnresolvedReferences
from distributed.utils_test import (
- cleanup,
- client,
- client_no_amm,
- cluster_fixture,
gen_cluster,
- loop,
- loop_in_thread,
)
from faker import Faker
from pandera.pandas import DataFrameSchema
@@ -34,7 +31,6 @@ from generalresearch.models.thl.product import Product
from generalresearch.models.thl.user import User
from generalresearch.pg_helper import PostgresConfig
from generalresearch.sql_helper import PostgresDsn
-from test_utils.incite.conftest import incite_item_factory, mnt_filepath
if TYPE_CHECKING:
from generalresearch.incite.base import GRLDatasets
@@ -56,12 +52,12 @@ unsupported_mock_types = {
}
-def combo_object():
+def combo_object() -> Generator[str, None, None]:
for x in iter_product(
df_collections,
["15min", "45min", "1H"],
):
- yield x
+ yield from x
class TestDFCollectionItemBase:
@@ -199,7 +195,7 @@ class TestDFCollectionItemMethod:
client_no_amm,
incite_item_factory,
delete_df_collection,
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
):
assert 1 + 1 == 2
@@ -768,7 +764,7 @@ class TestDFCollectionItemFunctionalTest:
product: Product,
incite_item_factory,
delete_df_collection,
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
):
from generalresearch.models.thl.user import User
@@ -818,7 +814,7 @@ class TestDFCollectionItemFunctionalTest:
df_collection_data_type,
incite_item_factory,
delete_df_collection,
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
):
"""A functional test to write some Parquet files for the
DFCollection and then confirm that the files get written
@@ -866,7 +862,7 @@ class TestDFCollectionItemFunctionalTest:
df_collection_data_type,
incite_item_factory,
delete_df_collection,
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
):
from generalresearch.models.thl.user import User
@@ -919,7 +915,7 @@ class TestDFCollectionItemFunctionalTest:
product: Product,
offset: str,
duration: timedelta,
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
):
"""Don't allow creating an archive for data that will likely be
overwritten or updated
@@ -960,7 +956,7 @@ class TestDFCollectionItemFunctionalTest:
user: User,
offset: str,
duration: timedelta,
- mnt_filepath: "GRLDatasets",
+ mnt_filepath: GRLDatasets,
):
delete_df_collection(coll=df_collection)
diff --git a/tests/incite/collections/test_df_collection_thl_marketplaces.py b/tests/incite/collections/test_df_collection_thl_marketplaces.py
index 8ce8acc..981f62e 100644
--- a/tests/incite/collections/test_df_collection_thl_marketplaces.py
+++ b/tests/incite/collections/test_df_collection_thl_marketplaces.py
@@ -28,7 +28,7 @@ def combo_object():
],
["5min", "6H", "30D"],
):
- yield x
+ yield from x
@pytest.mark.parametrize("df_coll, offset", combo_object())
diff --git a/tests/incite/collections/test_df_collection_thl_web.py b/tests/incite/collections/test_df_collection_thl_web.py
index c64dac8..b09d44c 100644
--- a/tests/incite/collections/test_df_collection_thl_web.py
+++ b/tests/incite/collections/test_df_collection_thl_web.py
@@ -1,3 +1,6 @@
+from __future__ import annotations
+
+from collections.abc import Generator
from datetime import datetime
from itertools import product
from typing import TYPE_CHECKING
@@ -11,9 +14,13 @@ from generalresearch.incite.collections import DFCollection, DFCollectionType
if TYPE_CHECKING:
from generalresearch.incite.base import GRLDatasets
+ from generalresearch.incite.collections import (
+ DFCollectionItem,
+ DFCollectionType,
+ )
-def combo_object():
+def combo_object() -> Generator[tuple, None, None]:
for x in product(
[
DFCollectionType.USER,
@@ -25,7 +32,7 @@ def combo_object():
],
["30min", "1H"],
):
- yield x
+ yield from x
@pytest.mark.parametrize(
@@ -33,7 +40,9 @@ def combo_object():
)
class TestDFCollection_thl_web:
- def test_init(self, df_collection_data_type, offset: str, df_collection):
+ def test_init(
+ self, df_collection_data_type: DFCollectionType, offset: str, df_collection
+ ):
assert isinstance(df_collection_data_type, DFCollectionType)
assert isinstance(df_collection, DFCollection)
@@ -43,12 +52,12 @@ class TestDFCollection_thl_web:
)
class TestDFCollection_thl_web_Properties:
- def test_items(self, df_collection_data_type, offset: str, df_collection):
+ def test_items(self, df_collection):
assert isinstance(df_collection.items, list)
for i in df_collection.items:
assert i._collection == df_collection
- def test__schema(self, df_collection_data_type, offset: str, df_collection):
+ def test__schema(self, df_collection):
assert isinstance(df_collection._schema, DataFrameSchema)
@@ -58,16 +67,16 @@ class TestDFCollection_thl_web_Properties:
class TestDFCollection_thl_web_BaseProperties:
@pytest.mark.skip
- def test__interval_range(self, df_collection_data_type, offset: str, df_collection):
+ def test__interval_range(self, df_collection):
pass
- def test_interval_start(self, df_collection_data_type, offset: str, df_collection):
+ def test_interval_start(self, df_collection):
assert isinstance(df_collection.interval_start, datetime)
- def test_interval_range(self, df_collection_data_type, offset: str, df_collection):
+ def test_interval_range(self, df_collection):
assert isinstance(df_collection.interval_range, list)
- def test_progress(self, df_collection_data_type, offset: str, df_collection):
+ def test_progress(self, df_collection):
assert isinstance(df_collection.progress, pd.DataFrame)
diff --git a/tests/incite/test_collection_base.py b/tests/incite/test_collection_base.py
index 497e5ab..7e6605f 100644
--- a/tests/incite/test_collection_base.py
+++ b/tests/incite/test_collection_base.py
@@ -1,5 +1,6 @@
-from datetime import datetime, timezone, timedelta
-from os.path import exists as pexists, join as pjoin
+from datetime import datetime, timedelta, timezone
+from os.path import exists as pexists
+from os.path import join as pjoin
from pathlib import Path
from uuid import uuid4
@@ -244,6 +245,7 @@ class TestCollectionBaseMethodsCleanup:
class TestCollectionBaseMethodsCleanup:
+
@pytest.mark.skip
def test_cleanup_partials(self, mnt_filepath):
instance = CollectionBase(archive_path=mnt_filepath.data_src)
diff --git a/tests/models/admin/test_report_request.py b/tests/models/admin/test_report_request.py
index cf4c405..a80afbe 100644
--- a/tests/models/admin/test_report_request.py
+++ b/tests/models/admin/test_report_request.py
@@ -1,4 +1,4 @@
-from datetime import timezone, datetime
+from datetime import datetime, timezone
import pandas as pd
import pytest
@@ -6,7 +6,7 @@ from pydantic import ValidationError
class TestReportRequest:
- def test_base(self, utc_60days_ago):
+ def test_base(self):
from generalresearch.models.admin.request import (
ReportRequest,
ReportType,
@@ -24,7 +24,7 @@ class TestReportRequest:
rr1 = ReportRequest.model_validate(
{
"start": datetime(
- year=datetime.now().year,
+ year=datetime.now(tz=timezone.utc).year,
month=1,
day=1,
hour=0,
@@ -43,7 +43,7 @@ class TestReportRequest:
rr2 = ReportRequest.model_validate(
{
"start": datetime(
- year=datetime.now().year,
+ year=datetime.now(tz=timezone.utc).year,
month=1,
day=1,
hour=6,
@@ -81,29 +81,30 @@ class TestReportRequest:
# interval='1d', include_open_bucket=True,
# start_floor=datetime.datetime(2025, 7, 9, 0, 0, tzinfo=datetime.timezone.utc)).start_floor
- def test_start_end_range(self, utc_90days_ago, utc_30days_ago):
+ def test_start_end_range(self, utc_90days_ago: datetime, utc_30days_ago: datetime):
from generalresearch.models.admin.request import ReportRequest
- with pytest.raises(expected_exception=ValidationError) as cm:
+ with pytest.raises(expected_exception=ValidationError):
ReportRequest.model_validate(
{"start": utc_30days_ago, "end": utc_90days_ago}
)
- with pytest.raises(expected_exception=ValidationError) as cm:
+ with pytest.raises(expected_exception=ValidationError):
ReportRequest.model_validate(
{
- "start": datetime(year=1990, month=1, day=1),
- "end": datetime(year=1950, month=1, day=1),
+ "start": datetime(year=1990, month=1, day=1, tzinfo=timezone.utc),
+ "end": datetime(year=1950, month=1, day=1, tzinfo=timezone.utc),
}
)
def test_start_end_range_tz(self):
- from generalresearch.models.admin.request import ReportRequest
from zoneinfo import ZoneInfo
+ from generalresearch.models.admin.request import ReportRequest
+
pacific_tz = ZoneInfo("America/Los_Angeles")
- with pytest.raises(expected_exception=ValidationError) as cm:
+ with pytest.raises(expected_exception=ValidationError):
ReportRequest.model_validate(
{
"start": datetime(year=2000, month=1, day=1, tzinfo=pacific_tz),
diff --git a/tests/models/custom_types/test_aware_datetime.py b/tests/models/custom_types/test_aware_datetime.py
index a23413c..530142e 100644
--- a/tests/models/custom_types/test_aware_datetime.py
+++ b/tests/models/custom_types/test_aware_datetime.py
@@ -1,10 +1,11 @@
+from __future__ import annotations
+
import logging
from datetime import datetime, timezone
-from typing import Optional
import pytest
import pytz
-from pydantic import BaseModel, ValidationError, Field
+from pydantic import BaseModel, Field, ValidationError
from generalresearch.models.custom_types import AwareDatetimeISO
@@ -12,7 +13,7 @@ logger = logging.getLogger()
class AwareDatetimeISOModel(BaseModel):
- dt_optional: Optional[AwareDatetimeISO] = Field(default=None)
+ dt_optional: AwareDatetimeISO | None = Field(default=None)
dt: AwareDatetimeISO
diff --git a/tests/models/custom_types/test_dsn.py b/tests/models/custom_types/test_dsn.py
index b37f2c4..16e1f83 100644
--- a/tests/models/custom_types/test_dsn.py
+++ b/tests/models/custom_types/test_dsn.py
@@ -2,13 +2,11 @@ from typing import Optional
from uuid import uuid4
import pytest
-from pydantic import BaseModel, ValidationError, Field
-from pydantic import MySQLDsn
+from pydantic import BaseModel, Field, MySQLDsn, ValidationError
from pydantic_core import Url
from generalresearch.models.custom_types import DaskDsn, SentryDsn
-
# --- Test Pydantic Models ---
@@ -27,7 +25,7 @@ class TestDaskDsn:
from dask.distributed import Client
m = SettingsModel(dask="tcp://dask-scheduler.internal")
-
+ assert isinstance(m.dask, Url)
assert m.dask.scheme == "tcp"
assert m.dask.host == "dask-scheduler.internal"
assert m.dask.port == 8786
@@ -72,6 +70,7 @@ class TestDaskDsn:
def test_port(self):
m = SettingsModel(dask="tcp://dask-scheduler.internal")
+ assert isinstance(m.dask, Url)
assert m.dask.port == 8786
@@ -81,6 +80,7 @@ class TestSentryDsn:
sentry=f"https://{uuid4().hex}@12345.ingest.us.sentry.io/9876543"
)
+ assert isinstance(m.sentry, Url)
assert m.sentry.scheme == "https"
assert m.sentry.host == "12345.ingest.us.sentry.io"
assert m.sentry.port == 443
@@ -109,4 +109,5 @@ class TestSentryDsn:
def test_port(self):
test_url: str = f"https://{uuid4().hex}@12345.ingest.us.sentry.io/9876543"
m = SettingsModel(sentry=test_url)
+ assert isinstance(m.sentry, Url)
assert m.sentry.port == 443
diff --git a/tests/models/custom_types/test_uuid_str.py b/tests/models/custom_types/test_uuid_str.py
index 91af9ae..02e6a8b 100644
--- a/tests/models/custom_types/test_uuid_str.py
+++ b/tests/models/custom_types/test_uuid_str.py
@@ -1,14 +1,15 @@
-from typing import Optional
+from __future__ import annotations
+
from uuid import uuid4
import pytest
-from pydantic import BaseModel, ValidationError, Field
+from pydantic import BaseModel, Field, ValidationError
from generalresearch.models.custom_types import UUIDStr
class UUIDStrModel(BaseModel):
- uuid_optional: Optional[UUIDStr] = Field(default_factory=lambda: uuid4().hex)
+ uuid_optional: UUIDStr | None = Field(default_factory=lambda: uuid4().hex)
uuid: UUIDStr
diff --git a/tests/models/dynata/test_eligbility.py b/tests/models/dynata/test_eligbility.py
index 23437f5..736c971 100644
--- a/tests/models/dynata/test_eligbility.py
+++ b/tests/models/dynata/test_eligbility.py
@@ -5,10 +5,10 @@ class TestEligibility:
def test_evaluate_task_criteria(self):
from generalresearch.models.dynata.survey import (
- DynataQuotaGroup,
DynataFilterGroup,
- DynataSurvey,
+ DynataQuotaGroup,
DynataRequirements,
+ DynataSurvey,
)
filters = [[["a", "b"], ["c", "d"]], [["e"], ["f"]]]
@@ -137,10 +137,10 @@ class TestEligibility:
def test_soft_pair(self):
from generalresearch.models.dynata.survey import (
- DynataQuotaGroup,
DynataFilterGroup,
- DynataSurvey,
+ DynataQuotaGroup,
DynataRequirements,
+ DynataSurvey,
)
filters = [[["a", "b"], ["c", "d"]], [["e"], ["f"]]]
@@ -186,7 +186,7 @@ class TestEligibility:
}
)
assert task.passes_filters(criteria_evaluation)
- passes, condition_hashes = task.passes_filters_soft(criteria_evaluation)
+ passes, _ = task.passes_filters_soft(criteria_evaluation)
assert passes
# make 'e' & 'f' None, we don't pass the 2nd filtergroup
diff --git a/tests/models/gr/test_authentication.py b/tests/models/gr/test_authentication.py
index e906d8c..6c84a5d 100644
--- a/tests/models/gr/test_authentication.py
+++ b/tests/models/gr/test_authentication.py
@@ -3,17 +3,20 @@ import json
import os
from datetime import datetime, timezone
from random import randint
+from typing import Callable
from uuid import uuid4
import pytest
+from generalresearch.models.gr.authentication import GRUser
+from generalresearch.models.gr.team import Membership, Team
+
SSO_ISSUER = ""
class TestGRUser:
- def test_init(self, gr_user):
- from generalresearch.models.gr.authentication import GRUser
+ def test_init(self, gr_user: GRUser):
assert isinstance(gr_user, GRUser)
assert not gr_user.is_superuser
@@ -26,8 +29,7 @@ class TestGRUser:
def test_businesses(self):
pass
- def test_teams(self, gr_user, membership, gr_db, gr_redis_config):
- from generalresearch.models.gr.team import Team
+ def test_teams(self, gr_user: GRUser, membership, gr_db, gr_redis_config):
assert gr_user.teams is None
@@ -40,11 +42,11 @@ class TestGRUser:
def test_prefetch_team_duplicates(
self,
gr_user_token,
- gr_user,
- membership,
+ gr_user: GRUser,
+ membership: Membership,
product_factory,
membership_factory,
- team,
+ team: Team,
thl_web_rr,
gr_redis_config,
gr_db,
@@ -61,10 +63,10 @@ class TestGRUser:
def test_products(
self,
- gr_user,
+ gr_user: GRUser,
product_factory,
- team,
- membership,
+ team: Team,
+ membership: Membership,
gr_db,
thl_web_rr,
gr_redis_config,
@@ -102,12 +104,12 @@ class TestGRUserMethods:
def test_to_redis(
self,
- gr_user,
+ gr_user: GRUser,
gr_redis,
- team,
+ team: Team,
business,
product_factory,
- membership_factory,
+ membership_factory: Callable[Membership],
):
product_factory(team=team, business=business)
membership_factory(team=team, gr_user=gr_user)
@@ -122,7 +124,7 @@ class TestGRUserMethods:
def test_set_cache(
self,
- gr_user,
+ gr_user: GRUser,
gr_user_token,
gr_redis,
gr_db,
@@ -145,7 +147,7 @@ class TestGRUserMethods:
def test_set_cache_gr_user(
self,
- gr_user,
+ gr_user: GRUser,
gr_user_token,
gr_redis,
gr_redis_config,
@@ -203,9 +205,7 @@ class TestGRUserMethods:
@pytest.mark.skip
def test_set_cache_business_uuids(
self,
- gr_user,
- membership,
- gr_user_token,
+ gr_user: GRUser,
gr_redis,
gr_db,
thl_web_rr,
diff --git a/tests/models/gr/test_base.py b/tests/models/gr/test_base.py
new file mode 100644
index 0000000..a9f01a8
--- /dev/null
+++ b/tests/models/gr/test_base.py
@@ -0,0 +1,46 @@
+import subprocess
+from pathlib import Path
+from typing import Callable
+
+import pytest
+from pydantic import PostgresDsn
+
+from generalresearch.pg_helper import PostgresConfig
+
+
+class TestGRPostgresDjangoCreation:
+
+ def test_git(self, git_key_path: Path, gr_repo: Callable[..., Path]):
+ repo_path = gr_repo()
+
+ try:
+ # Run the git command inside the target directory
+ result = subprocess.run(
+ ["git", "rev-parse", "--is-inside-work-tree"],
+ cwd=repo_path,
+ capture_output=True,
+ text=True,
+ check=True,
+ )
+ # Check if the output string is exactly "true"
+ assert result.stdout.strip() == "true"
+
+ except (subprocess.CalledProcessError, FileNotFoundError) as e:
+ pytest.fail(f"Directory is not a Git repo or Git is not installed: {e}")
+
+ def test_django_creation(
+ self,
+ django_db_factory: Callable[..., None],
+ ):
+
+ dsn = django_db_factory("gr")
+ assert isinstance(dsn, PostgresDsn)
+
+ # def test_django_tables(self, thl_web_rw: PostgresConfig):
+ # res = thl_web_rw.execute_sql_query(query="""
+ # SELECT COUNT(*)
+ # FROM information_schema.tables
+ # WHERE table_schema = 'public';
+ # """)
+ # assert len(res) == 1
+ # assert res[0]["count"] == 56
diff --git a/tests/models/gr/test_business.py b/tests/models/gr/test_business.py
index e8bd06a..7a84f23 100644
--- a/tests/models/gr/test_business.py
+++ b/tests/models/gr/test_business.py
@@ -6,6 +6,7 @@ from uuid import uuid4
import pandas as pd
import pytest
+from dask.distributed import Client as DaskClient
# noinspection PyUnresolvedReferences
from distributed.utils_test import (
@@ -14,22 +15,27 @@ from distributed.utils_test import (
from pytest import approx
from generalresearch.currency import USDCent
+from generalresearch.managers.gr.business import BusinessBankAccountManager
+from generalresearch.models.gr.business import (
+ Business,
+ BusinessAddress,
+ BusinessBankAccount,
+ BusinessContact,
+)
from generalresearch.models.thl.finance import (
BusinessBalances,
ProductBalances,
)
-
-# from test_utils.incite.conftest import mnt_filepath
-from test_utils.managers.conftest import (
- business_bank_account_manager,
- lm,
- thl_lm,
-)
+from generalresearch.pg_helper import PostgresConfig
class TestBusinessBankAccount:
- def test_init(self, business, business_bank_account_manager):
+ def test_init(
+ self,
+ business: Business,
+ business_bank_account_manager: BusinessBankAccountManager,
+ ):
from generalresearch.models.gr.business import (
BusinessBankAccount,
TransferMethod,
@@ -42,7 +48,13 @@ class TestBusinessBankAccount:
)
assert isinstance(instance, BusinessBankAccount)
- def test_business(self, business_bank_account, business, gr_db, gr_redis_config):
+ def test_business(
+ self,
+ business_bank_account: BusinessBankAccount,
+ business: Business,
+ gr_db,
+ gr_redis_config,
+ ):
from generalresearch.models.gr.business import Business
assert business_bank_account.business is None
@@ -56,16 +68,13 @@ class TestBusinessBankAccount:
class TestBusinessAddress:
- def test_init(self, business_address):
- from generalresearch.models.gr.business import BusinessAddress
-
+ def test_init(self, business_address: BusinessAddress):
assert isinstance(business_address, BusinessAddress)
class TestBusinessContact:
def test_init(self):
- from generalresearch.models.gr.business import BusinessContact
bc = BusinessContact(name="abc", email="test@abc.com")
assert isinstance(bc, BusinessContact)
@@ -104,7 +113,7 @@ class TestBusiness:
user_factory,
session_with_tx_factory,
pop_ledger_merge,
- client_no_amm,
+ client_no_amm: DaskClient,
ledger_collection,
mnt_filepath,
create_main_accounts,
@@ -220,11 +229,11 @@ class TestBusiness:
def test_balance(
self,
- business,
+ business: Business,
mnt_filepath,
- client_no_amm,
- thl_web_rr,
- lm,
+ client_no_amm: DaskClient,
+ thl_web_rr: PostgresConfig,
+ ledger_manager,
pop_ledger_merge,
):
assert business.balance is None
@@ -232,7 +241,7 @@ class TestBusiness:
with pytest.raises(expected_exception=AssertionError) as cm:
business.prebuild_balance(
thl_pg_config=thl_web_rr,
- lm=lm,
+ lm=ledger_manager,
ds=mnt_filepath,
client=client_no_amm,
pop_ledger=pop_ledger_merge,
@@ -248,7 +257,7 @@ class TestBusiness:
business,
product_factory,
thl_web_rr,
- thl_lm,
+ thl_ledger_manager,
business_payout_event_manager,
):
assert business.payouts is None
@@ -256,17 +265,17 @@ class TestBusiness:
with pytest.raises(expected_exception=AssertionError) as cm:
business.prebuild_payouts(
thl_pg_config=thl_web_rr,
- thl_lm=thl_lm,
+ thl_lm=thl_ledger_manager,
bpem=business_payout_event_manager,
)
assert "Must provide product_uuids" in str(cm.value)
p = product_factory(business=business)
- thl_lm.get_account_or_create_bp_wallet(product=p)
+ thl_ledger_manager.get_account_or_create_bp_wallet(product=p)
business.prebuild_payouts(
thl_pg_config=thl_web_rr,
- thl_lm=thl_lm,
+ thl_lm=thl_ledger_manager,
bpem=business_payout_event_manager,
)
assert isinstance(business.payouts, list)
@@ -274,17 +283,17 @@ class TestBusiness:
def test_payouts(
self,
- business,
- product_factory,
+ business: Business,
+ product_factory: Callable[Product],
bp_payout_factory,
- thl_lm,
+ thl_ledger_manager,
thl_web_rr,
business_payout_event_manager,
create_main_accounts,
):
create_main_accounts()
p = product_factory(business=business)
- thl_lm.get_account_or_create_bp_wallet(product=p)
+ thl_ledger_manager.get_account_or_create_bp_wallet(product=p)
business_payout_event_manager.set_account_lookup_table(thl_lm=thl_lm)
bp_payout_factory(
@@ -293,7 +302,7 @@ class TestBusiness:
business.prebuild_payouts(
thl_pg_config=thl_web_rr,
- thl_lm=thl_lm,
+ thl_lm=thl_ledger_manager,
bpem=business_payout_event_manager,
)
assert len(business.payouts) == 1
@@ -306,10 +315,12 @@ class TestBusiness:
skip_wallet_balance_check=True,
skip_one_per_day_check=True,
)
- business_payout_event_manager.set_account_lookup_table(thl_lm=thl_lm)
+ business_payout_event_manager.set_account_lookup_table(
+ thl_lm=thl_ledger_manager
+ )
business.prebuild_payouts(
thl_pg_config=thl_web_rr,
- thl_lm=thl_lm,
+ thl_lm=thl_ledger_manager,
bpem=business_payout_event_manager,
)
assert len(business.payouts) == 1
@@ -370,7 +381,7 @@ class TestBusiness:
self,
business,
thl_web_rr,
- thl_lm,
+ thl_ledger_manager,
mnt_filepath,
client_no_amm,
pop_ledger_merge,
@@ -496,7 +507,7 @@ class TestBusinessBalance:
mnt_filepath,
bp_payout_factory,
thl_lm,
- lm,
+ ledger_manager,
duration,
offset,
start,
diff --git a/tests/models/thl/test_product.py b/tests/models/thl/test_product.py
index 5e9b249..39469dc 100644
--- a/tests/models/thl/test_product.py
+++ b/tests/models/thl/test_product.py
@@ -1,8 +1,10 @@
+from __future__ import annotations
+
import os
import shutil
from datetime import datetime, timedelta, timezone
from decimal import Decimal
-from typing import Callable, Optional
+from typing import Callable
from uuid import uuid4
import pytest
@@ -10,7 +12,7 @@ from dask.distributed import Client as DaskClient
from pydantic import ValidationError
from generalresearch.currency import USDCent
-from generalresearch.incite import GRLDatasets
+from generalresearch.incite.base import GRLDatasets
from generalresearch.incite.mergers.pop_ledger import PopLedgerMerge
from generalresearch.managers.thl.ledger_manager.thl_ledger import (
ThlLedgerManager,
@@ -25,6 +27,7 @@ from generalresearch.models.thl.product import (
IntegrationMode,
PayoutConfig,
PayoutTransformation,
+ PayoutTransformationPercentArgs,
Product,
ProfilingConfig,
SourceConfig,
@@ -137,6 +140,12 @@ class TestProduct:
redirect_url="https://www.google.com/hey",
)
+ assert isinstance(p.payout_config.payout_transformation, PayoutTransformation)
+ assert isinstance(
+ p.payout_config.payout_transformation.kwargs,
+ PayoutTransformationPercentArgs,
+ )
+
p.payout_config.payout_transformation = PayoutTransformation.model_validate(
{
"f": "payout_transformation_percent",
@@ -576,7 +585,7 @@ class TestGlobalProductConfigFor:
class TestProductFinancials:
@pytest.fixture
- def start(self) -> "datetime":
+ def start(self) -> datetime:
return datetime(year=2018, month=3, day=14, hour=0, tzinfo=timezone.utc)
@pytest.fixture
@@ -584,7 +593,7 @@ class TestProductFinancials:
return "30d"
@pytest.fixture
- def duration(self) -> Optional["timedelta"]:
+ def duration(self) -> timedelta | None:
return None
def test_balance(
@@ -759,7 +768,7 @@ class TestProductFinancials:
class TestProductBalance:
@pytest.fixture
- def start(self) -> "datetime":
+ def start(self) -> datetime:
return datetime(year=2018, month=3, day=14, hour=0, tzinfo=timezone.utc)
@pytest.fixture
@@ -767,7 +776,7 @@ class TestProductBalance:
return "30d"
@pytest.fixture
- def duration(self) -> Optional["timedelta"]:
+ def duration(self) -> timedelta | None:
return None
def test_inconsistent(
@@ -783,7 +792,7 @@ class TestProductBalance:
user_factory: Callable[..., User],
session_with_tx_factory: Callable[..., Session],
pop_ledger_merge,
- start,
+ start: datetime,
bp_payout_factory,
payout_event_manager,
):
@@ -792,8 +801,6 @@ class TestProductBalance:
create_main_accounts()
delete_df_collection(coll=ledger_collection)
- from generalresearch.models.thl.user import User
-
u1: User = user_factory(product=product)
# 1. Complete and Build Parquets 1st time
@@ -827,7 +834,7 @@ class TestProductBalance:
def test_not_inconsistent(
self,
product: Product,
- mnt_filepath,
+ mnt_filepath: GRLDatasets,
thl_lm: ThlLedgerManager,
client_no_amm: DaskClient,
delete_ledger_db,
@@ -852,8 +859,6 @@ class TestProductBalance:
create_main_accounts()
delete_df_collection(coll=ledger_collection)
- from generalresearch.models.thl.user import User
-
u1: User = user_factory(product=product)
# 1. Complete and Build Parquets 1st time
@@ -886,7 +891,7 @@ class TestProductBalance:
class TestProductPOPFinancial:
@pytest.fixture
- def start(self) -> "datetime":
+ def start(self) -> datetime:
return datetime(year=2018, month=3, day=14, hour=0, tzinfo=timezone.utc)
@pytest.fixture
@@ -894,15 +899,15 @@ class TestProductPOPFinancial:
return "30d"
@pytest.fixture
- def duration(self) -> Optional["timedelta"]:
+ def duration(self) -> timedelta | None:
return None
def test_base(
self,
- product,
- mnt_filepath,
+ product: Product,
+ mnt_filepath: GRLDatasets,
thl_lm: ThlLedgerManager,
- client_no_amm,
+ client_no_amm: DaskClient,
delete_ledger_db,
create_main_accounts,
delete_df_collection,
@@ -923,8 +928,6 @@ class TestProductPOPFinancial:
create_main_accounts()
delete_df_collection(coll=ledger_collection)
- from generalresearch.models.thl.user import User
-
u1: User = user_factory(product=product)
# 1. Complete and Build Parquets 1st time
@@ -961,7 +964,7 @@ class TestProductPOPFinancial:
class TestProductCache:
@pytest.fixture
- def start(self) -> "datetime":
+ def start(self) -> datetime:
return datetime(year=2018, month=3, day=14, hour=0, tzinfo=timezone.utc)
@pytest.fixture
@@ -969,7 +972,7 @@ class TestProductCache:
return "30d"
@pytest.fixture
- def duration(self) -> Optional["timedelta"]:
+ def duration(self) -> timedelta | None:
return None
def test_basic(
@@ -1008,7 +1011,6 @@ class TestProductCache:
)
from generalresearch.models.thl.product import Product
- from generalresearch.models.thl.user import User
u1: User = user_factory(product=product)
@@ -1047,7 +1049,7 @@ class TestProductCache:
def test_neg_balance_cache(
self,
product: Product,
- mnt_filepath,
+ mnt_filepath: GRLDatasets,
thl_lm,
client_no_amm: DaskClient,
thl_redis_config,
@@ -1070,7 +1072,6 @@ class TestProductCache:
delete_df_collection(coll=ledger_collection)
from generalresearch.models.thl.product import Product
- from generalresearch.models.thl.user import User
u1: User = user_factory(product=product)
@@ -1112,10 +1113,12 @@ class TestProductCache:
# Fetch from cache and assert the instance loaded from redis
rc = thl_redis_config.create_redis_client()
- res: Optional[str] = rc.get(product.cache_key)
+ res: str | None = rc.get(product.cache_key)
assert isinstance(res, str)
p1: Product = Product.model_validate_json(res)
+ assert p1.balance
+
assert p1.balance.product_id == product.uuid
assert p1.balance.payout_usd_str == "$0.71"
assert p1.balance.adjustment == -71
diff --git a/tests/pytest.ini b/tests/pytest.ini
index d280de0..1a5c089 100644
--- a/tests/pytest.ini
+++ b/tests/pytest.ini
@@ -1,2 +1 @@
-[pytest]
-asyncio_mode = auto \ No newline at end of file
+[pytest] \ No newline at end of file
diff --git a/tests/test_postgres.py b/tests/test_postgres.py
new file mode 100644
index 0000000..3b3ddd0
--- /dev/null
+++ b/tests/test_postgres.py
@@ -0,0 +1,68 @@
+import socket
+import subprocess
+from typing import Callable
+
+from pydantic import PostgresDsn
+
+from generalresearch.models.custom_types import InternalHostname, PostgresDict
+from generalresearch.pg_helper import PostgresConfig
+
+
+def is_port_open(host: InternalHostname, port: int = 5432, timeout: int = 3):
+ try:
+ with socket.create_connection((host, port), timeout=timeout):
+ return True
+ except (socket.timeout, ConnectionRefusedError, OSError):
+ return False
+
+
+def can_ping(host: InternalHostname):
+ return (
+ subprocess.call(
+ ["ping", "-c", "1", str(host)],
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ )
+ == 0
+ )
+
+
+class TestPostgresDSN:
+
+ def test_ping(self, postgres_instance_host: InternalHostname):
+ assert can_ping(host=postgres_instance_host)
+
+ def test_port(self, postgres_instance_host: InternalHostname):
+ assert is_port_open(host=postgres_instance_host)
+
+ def test_conn(self, postgres_instance: PostgresDsn):
+ config = PostgresConfig(
+ dsn=postgres_instance,
+ connect_timeout=1,
+ statement_timeout=1,
+ )
+ res = config.execute_sql_query(query="SELECT 1;")
+ assert len(res) == 1
+
+
+class TestPostgresDjangoCreation:
+
+ def test_ping(self, postgres_instance_dict: PostgresDict):
+ assert can_ping(host=postgres_instance_dict["host"])
+
+ def test_django_creation(
+ self,
+ django_db_factory: Callable[..., None],
+ ):
+
+ dsn = django_db_factory()
+ assert isinstance(dsn, PostgresDsn)
+
+ def test_django_tables(self, thl_web_rw: PostgresConfig):
+ res = thl_web_rw.execute_sql_query(query="""
+ SELECT COUNT(*)
+ FROM information_schema.tables
+ WHERE table_schema = 'public';
+ """)
+ assert len(res) == 1
+ assert res[0]["count"] == 56