diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/conftest.py | 10 | ||||
| -rw-r--r-- | tests/grliq/managers/test_forensic_data.py | 35 | ||||
| -rw-r--r-- | tests/grliq/managers/test_forensic_results.py | 4 | ||||
| -rw-r--r-- | tests/incite/collections/test_df_collection_item_thl_web.py | 26 | ||||
| -rw-r--r-- | tests/incite/collections/test_df_collection_thl_marketplaces.py | 2 | ||||
| -rw-r--r-- | tests/incite/collections/test_df_collection_thl_web.py | 27 | ||||
| -rw-r--r-- | tests/incite/test_collection_base.py | 6 | ||||
| -rw-r--r-- | tests/models/admin/test_report_request.py | 23 | ||||
| -rw-r--r-- | tests/models/custom_types/test_aware_datetime.py | 7 | ||||
| -rw-r--r-- | tests/models/custom_types/test_dsn.py | 9 | ||||
| -rw-r--r-- | tests/models/custom_types/test_uuid_str.py | 7 | ||||
| -rw-r--r-- | tests/models/dynata/test_eligbility.py | 10 | ||||
| -rw-r--r-- | tests/models/gr/test_authentication.py | 36 | ||||
| -rw-r--r-- | tests/models/gr/test_base.py | 46 | ||||
| -rw-r--r-- | tests/models/gr/test_business.py | 75 | ||||
| -rw-r--r-- | tests/models/thl/test_product.py | 53 | ||||
| -rw-r--r-- | tests/pytest.ini | 3 | ||||
| -rw-r--r-- | tests/test_postgres.py | 68 |
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 |
