From 203066cb5228ce3bcadb940b9aca1b6a36dceb4e Mon Sep 17 00:00:00 2001 From: stuppie Date: Fri, 18 Sep 2026 11:16:22 -0600 Subject: user ip history and geo ip information fixes, fixtures, and tests --- tests/managers/thl/test_ipinfo.py | 201 +++++++++----------------------------- 1 file changed, 44 insertions(+), 157 deletions(-) (limited to 'tests/managers/thl/test_ipinfo.py') diff --git a/tests/managers/thl/test_ipinfo.py b/tests/managers/thl/test_ipinfo.py index c021eb9..f39d50e 100644 --- a/tests/managers/thl/test_ipinfo.py +++ b/tests/managers/thl/test_ipinfo.py @@ -1,160 +1,47 @@ -from collections.abc import Callable -from typing import TYPE_CHECKING - -import faker - -from generalresearch.managers.thl.ipinfo import ( - GeoIpInfoManager, - IPGeonameManager, - IPInformationManager, -) -from generalresearch.models.thl.ipinfo import ( - GeoIPInformation, - IPGeoname, - IPInformation, -) - -if TYPE_CHECKING: - from generalresearch.pg_helper import PostgresConfig - from generalresearch.redis_helper import RedisConfig - -fake = faker.Faker() - - -class TestIPGeonameManager: - - def test_init( - self, thl_web_rr: PostgresConfig, ip_geoname_manager: IPGeonameManager - ): - - instance = IPGeonameManager(pg_config=thl_web_rr) - assert isinstance(instance, IPGeonameManager) - assert isinstance(ip_geoname_manager, IPGeonameManager) - - def test_create( - self, - ip_geoname_factory: Callable[..., IPGeoname], - ip_geoname_manager: IPGeonameManager, - ): - - instance = ip_geoname_factory() - assert isinstance(instance, IPGeoname) - - res = ip_geoname_manager.fetch_geoname_ids(filter_ids=[instance.geoname_id]) - assert res[0].model_dump_json() == instance.model_dump_json() - - -class TestIPInformationManager: - - def test_init( - self, thl_web_rr: PostgresConfig, ip_information_manager: IPInformationManager - ): - instance = IPInformationManager(pg_config=thl_web_rr) - assert isinstance(instance, IPInformationManager) - assert isinstance(ip_information_manager, IPInformationManager) - - def test_create( - self, - ip_information_factory: Callable[..., IPInformation], - ip_information_manager: IPInformationManager, - ): - instance = ip_information_factory() - assert isinstance(instance, IPInformation) - - res = ip_information_manager.fetch_ip_information(filter_ips=[instance.ip]) - assert res[0].model_dump_json() == instance.model_dump_json() - - def test_prefetch_geoname( - self, - ip_information: IPInformation, - ip_geoname: IPGeoname, - thl_web_rr: PostgresConfig, - ): - assert isinstance(ip_information, IPInformation) - - assert ip_information.geoname_id == ip_geoname.geoname_id - assert ip_information.geoname is None - - ip_information.prefetch_geoname(pg_config=thl_web_rr) - assert isinstance(ip_information.geoname, IPGeoname) +from generalresearch.managers.thl.ipinfo import GeoIpInfoManager +from generalresearch.models.thl.ipinfo import GeoIPInformation class TestGeoIpInfoManager: - def test_init( - self, - thl_web_rr: PostgresConfig, - thl_redis_config: RedisConfig, - geoipinfo_manager: GeoIpInfoManager, - ): - instance = GeoIpInfoManager(pg_config=thl_web_rr, redis_config=thl_redis_config) - assert isinstance(instance, GeoIpInfoManager) - assert isinstance(geoipinfo_manager, GeoIpInfoManager) - - def test_multi( - self, - ip_information_factory: Callable[..., IPInformation], - ip_geoname: IPGeoname, - geoipinfo_manager: GeoIpInfoManager, - ): - ip = fake.ipv4_public() - ip_information_factory(ip=ip, geoname=ip_geoname) - ips = [ip] - - # This only looks up in redis. They don't exist yet - res = geoipinfo_manager.get_cache_multi(ip_addresses=ips) - assert res == {ip: None} - - # Looks up in redis, if not exists, looks in mysql, then sets - # the caches that didn't exist. - res = geoipinfo_manager.get_multi(ip_addresses=ips) - assert res[ip] is not None - - ip2 = fake.ipv4_public() - ip_information_factory(ip=ip2, geoname=ip_geoname) - ips = [ip, ip2] - res = geoipinfo_manager.get_cache_multi(ip_addresses=ips) - assert res[ip] is not None - assert res[ip2] is None - res = geoipinfo_manager.get_multi(ip_addresses=ips) - assert res[ip] is not None - assert res[ip2] is not None - res = geoipinfo_manager.get_cache_multi(ip_addresses=ips) - assert res[ip] is not None - assert res[ip2] is not None - - def test_multi_ipv6( - self, - ip_information_factory: Callable[..., IPInformation], - ip_geoname: IPGeoname, - geoipinfo_manager: GeoIpInfoManager, - ): - ip = fake.ipv6() - # Make another IP that will be in the same /64 block. - ip2 = ip[:-1] + "a" if ip[-1] != "a" else ip[:-1] + "b" - ip_information_factory(ip=ip, geoname=ip_geoname) - ips = [ip, ip2] - print(f"{ips=}") - - # This only looks up in redis. They don't exist yet - res = geoipinfo_manager.get_cache_multi(ip_addresses=ips) - assert res == {ip: None, ip2: None} - - # Looks up in redis, if not exists, looks in mysql, then sets - # the caches that didn't exist. - res = geoipinfo_manager.get_multi(ip_addresses=ips) - - res1 = res[ip] - assert isinstance(res1, GeoIPInformation) - assert res1.ip == ip - assert res1.lookup_prefix == "/64" - - res2 = res[ip2] - assert isinstance(res2, GeoIPInformation) - assert res2.ip == ip2 - assert res2.lookup_prefix == "/64" - # they should be the same basically, except for the ip - - def test_doesnt_exist(self, geoipinfo_manager: GeoIpInfoManager): - ip = fake.ipv4_public() - res = geoipinfo_manager.get_multi(ip_addresses=[ip]) - assert res == {ip: None} + def test_get(self, geoipinfo_manager: GeoIpInfoManager): + result = geoip_info_manager.get("8.8.8.8") + + assert result == GeoIPInformation( + ip="8.8.8.8", + country_iso="us", + is_anonymous=False, + autonomous_system_number=15169, + autonomous_system_organization="Google", + access_type=None, + ) + geoip_info_manager.grip_mmdb.lookup.assert_called_once_with("8.8.8.8") + + def test_get_multi(self, geoipinfo_manager: GeoIpInfoManager): + result = geoip_info_manager.get_multi(["8.8.8.8", "1.1.1.1", "8.8.8.8"]) + + assert result == { + "8.8.8.8": GeoIPInformation( + ip="8.8.8.8", + country_iso="us", + is_anonymous=False, + autonomous_system_number=15169, + autonomous_system_organization="Google", + access_type=None, + ), + "1.1.1.1": GeoIPInformation( + ip="1.1.1.1", + country_iso="au", + is_anonymous=True, + autonomous_system_number=13335, + autonomous_system_organization="Cloudflare", + access_type=None, + ), + } + assert geoip_info_manager.grip_mmdb.lookup.call_count == 2 + assert { + call.args[0] for call in geoip_info_manager.grip_mmdb.lookup.call_args_list + } == {"8.8.8.8", "1.1.1.1"} + + def test_get_multi_empty(self, geoipinfo_manager: GeoIpInfoManager): + assert geoip_info_manager.get_multi([]) == {} + geoip_info_manager.grip_mmdb.lookup.assert_not_called() -- cgit v1.2.3 From 1a98418317c115b92739639cf0b837bd974fc5d6 Mon Sep 17 00:00:00 2001 From: stuppie Date: Fri, 18 Sep 2026 11:34:27 -0600 Subject: fix more tests --- generalresearch/managers/thl/payout.py | 2 +- .../managers/thl/wallet/cashout_tasks.py | 3 --- generalresearch/managers/thl/wallet/user_payout.py | 4 ++- test_utils/managers/thl/conftest.py | 31 ++-------------------- test_utils/models/ledger/conftest.py | 16 +++++------ tests/managers/thl/test_cashout_method.py | 4 --- tests/managers/thl/test_ipinfo.py | 6 ++--- tests/managers/thl/test_ledger/test_thl_lm_tx.py | 27 +++++++++++++++++++ tests/managers/thl/test_ledger/test_thl_pem.py | 5 ++-- tests/managers/thl/test_payout.py | 19 +++++++------ 10 files changed, 56 insertions(+), 61 deletions(-) delete mode 100644 generalresearch/managers/thl/wallet/cashout_tasks.py (limited to 'tests/managers/thl/test_ipinfo.py') diff --git a/generalresearch/managers/thl/payout.py b/generalresearch/managers/thl/payout.py index 4014cf8..3968ea7 100644 --- a/generalresearch/managers/thl/payout.py +++ b/generalresearch/managers/thl/payout.py @@ -879,7 +879,7 @@ class BusinessPayoutEventManager(PostgresManagerWithRedis): amount: USDCent, ext_ref_id: str, created: datetime | None = None, - ): + ) -> BusinessPayoutEvent: """ This should NOT be called directly normally. It is just a shortcut for tests. However, instead of just making a naked BP payout, diff --git a/generalresearch/managers/thl/wallet/cashout_tasks.py b/generalresearch/managers/thl/wallet/cashout_tasks.py deleted file mode 100644 index b28b04f..0000000 --- a/generalresearch/managers/thl/wallet/cashout_tasks.py +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/generalresearch/managers/thl/wallet/user_payout.py b/generalresearch/managers/thl/wallet/user_payout.py index ca47611..a1c628b 100644 --- a/generalresearch/managers/thl/wallet/user_payout.py +++ b/generalresearch/managers/thl/wallet/user_payout.py @@ -11,7 +11,9 @@ from redis import Redis from generalresearch.currency import USDCent from generalresearch.managers.thl.cashout_method import CashoutMethodManager from generalresearch.managers.thl.ipinfo import GeoIpInfoManager -from generalresearch.managers.thl.ledger_manager.exceptions import LedgerTransactionCreateError +from generalresearch.managers.thl.ledger_manager.exceptions import ( + LedgerTransactionCreateError, +) from generalresearch.managers.thl.ledger_manager.thl_ledger import ThlLedgerManager from generalresearch.managers.thl.payout import PayoutEventManager from generalresearch.managers.thl.userhealth import UserIpHistoryManager diff --git a/test_utils/managers/thl/conftest.py b/test_utils/managers/thl/conftest.py index 3392559..5b96680 100644 --- a/test_utils/managers/thl/conftest.py +++ b/test_utils/managers/thl/conftest.py @@ -23,15 +23,10 @@ if TYPE_CHECKING: from generalresearch.config import GRLBaseSettings from generalresearch.managers.thl.buyer import BuyerManager from generalresearch.managers.thl.category import CategoryManager - from generalresearch.managers.thl.ipinfo import ( - IPGeonameManager, - IPInformationManager, - ) from generalresearch.managers.thl.payout import ( BrokerageProductPayoutEventManager, BusinessPayoutEventManager, PayoutEventManager, - UserPayoutEventManager, ) from generalresearch.managers.thl.product import ProductManager from generalresearch.managers.thl.session import SessionManager @@ -52,6 +47,7 @@ if TYPE_CHECKING: WallCacheManager, WallManager, ) + from generalresearch.managers.thl.wallet.user_payout import UserPayoutEventManager # === Msc === @@ -139,7 +135,7 @@ def user_payout_event_manager( assert thl_web_rw.dsn.path assert "/unittest-" in thl_web_rw.dsn.path - from generalresearch.managers.thl.payout import UserPayoutEventManager + from generalresearch.managers.thl.wallet.user_payout import UserPayoutEventManager return UserPayoutEventManager( pg_config=thl_web_rw, @@ -342,29 +338,6 @@ def surveypenalty_manager(thl_redis_config: RedisConfig): return SurveyPenaltyManager(redis_config=thl_redis_config) -# --- IP Geolocation --- - - -@pytest.fixture -def ip_geoname_manager(thl_web_rw: PostgresConfig) -> IPGeonameManager: - from generalresearch.managers.thl.ipinfo import IPGeonameManager - - return IPGeonameManager(pg_config=thl_web_rw) - - -# --- IP Information --- - - -@pytest.fixture(scope="session") -def ip_information_manager(thl_web_rw: PostgresConfig) -> IPInformationManager: - assert thl_web_rw.dsn.path - assert "/unittest-" in thl_web_rw.dsn.path - - from generalresearch.managers.thl.ipinfo import IPInformationManager - - return IPInformationManager(pg_config=thl_web_rw) - - # --- IP Record --- diff --git a/test_utils/models/ledger/conftest.py b/test_utils/models/ledger/conftest.py index 9ee0df2..e9ddbc9 100644 --- a/test_utils/models/ledger/conftest.py +++ b/test_utils/models/ledger/conftest.py @@ -39,7 +39,6 @@ if TYPE_CHECKING: ThlLedgerManager, ) from generalresearch.managers.thl.payout import ( - BrokerageProductPayoutEventManager, BusinessPayoutEventManager, ) from generalresearch.managers.thl.session import SessionManager @@ -202,7 +201,7 @@ def bp_payout_event( @pytest.fixture def bp_payout_event_factory( - brokerage_product_payout_event_manager: BrokerageProductPayoutEventManager, + business_payout_event_manager: BusinessPayoutEventManager, thl_ledger_manager: ThlLedgerManager, ) -> Callable[..., BrokerageProductPayoutEvent]: @@ -210,14 +209,13 @@ def bp_payout_event_factory( product: Product, usd_cent: USDCent, ext_ref_id: str | None = None ) -> BrokerageProductPayoutEvent: - return brokerage_product_payout_event_manager.create_bp_payout_event( + bus_pe = business_payout_event_manager.create_bp_payout_event( thl_ledger_manager=thl_ledger_manager, product=product, amount=usd_cent, - ext_ref_id=ext_ref_id, - skip_wallet_balance_check=True, - skip_one_per_day_check=True, + ext_ref_id=ext_ref_id or uuid4().hex, ) + return bus_pe.bp_payouts[0] return _inner @@ -225,9 +223,9 @@ def bp_payout_event_factory( @pytest.fixture def currency(ledger_manager: LedgerManager) -> LedgerCurrency: # return request.param if hasattr(request, "currency") else LedgerCurrency.TEST - assert ( - ledger_manager.currency - ), "LedgerManager must have a currency specified for these tests" + assert ledger_manager.currency, ( + "LedgerManager must have a currency specified for these tests" + ) return ledger_manager.currency diff --git a/tests/managers/thl/test_cashout_method.py b/tests/managers/thl/test_cashout_method.py index fc364f2..bb978f8 100644 --- a/tests/managers/thl/test_cashout_method.py +++ b/tests/managers/thl/test_cashout_method.py @@ -13,7 +13,6 @@ from generalresearch.models.thl.wallet.cashout_method import ( from generalresearch.models.thl.wallet.definitions import PayoutType if TYPE_CHECKING: - from generalresearch.config import GRLBaseSettings from generalresearch.managers.thl.cashout_method import ( CashoutMethodManager, ) @@ -24,7 +23,6 @@ if TYPE_CHECKING: class TestTangoCashoutMethods: - def test_create_and_get( self, cashout_method_manager: CashoutMethodManager, @@ -51,9 +49,7 @@ class TestTangoCashoutMethods: assert len(res) == 2 - class TestUserCashoutMethods: - def test( self, cashout_method_manager: CashoutMethodManager, diff --git a/tests/managers/thl/test_ipinfo.py b/tests/managers/thl/test_ipinfo.py index f39d50e..d84cbf7 100644 --- a/tests/managers/thl/test_ipinfo.py +++ b/tests/managers/thl/test_ipinfo.py @@ -3,7 +3,7 @@ from generalresearch.models.thl.ipinfo import GeoIPInformation class TestGeoIpInfoManager: - def test_get(self, geoipinfo_manager: GeoIpInfoManager): + def test_get(self, geoip_info_manager: GeoIpInfoManager): result = geoip_info_manager.get("8.8.8.8") assert result == GeoIPInformation( @@ -16,7 +16,7 @@ class TestGeoIpInfoManager: ) geoip_info_manager.grip_mmdb.lookup.assert_called_once_with("8.8.8.8") - def test_get_multi(self, geoipinfo_manager: GeoIpInfoManager): + def test_get_multi(self, geoip_info_manager: GeoIpInfoManager): result = geoip_info_manager.get_multi(["8.8.8.8", "1.1.1.1", "8.8.8.8"]) assert result == { @@ -42,6 +42,6 @@ class TestGeoIpInfoManager: call.args[0] for call in geoip_info_manager.grip_mmdb.lookup.call_args_list } == {"8.8.8.8", "1.1.1.1"} - def test_get_multi_empty(self, geoipinfo_manager: GeoIpInfoManager): + def test_get_multi_empty(self, geoip_info_manager: GeoIpInfoManager): assert geoip_info_manager.get_multi([]) == {} geoip_info_manager.grip_mmdb.lookup.assert_not_called() diff --git a/tests/managers/thl/test_ledger/test_thl_lm_tx.py b/tests/managers/thl/test_ledger/test_thl_lm_tx.py index 96ea0d6..22a7b73 100644 --- a/tests/managers/thl/test_ledger/test_thl_lm_tx.py +++ b/tests/managers/thl/test_ledger/test_thl_lm_tx.py @@ -806,6 +806,24 @@ class TestThlLedgerTxManager: assert thl_ledger_manager.get_session_attempt_credit(session.uuid) == 5 assert thl_ledger_manager.get_user_attempt_credit_balance(user) == 5 + attempt_credit_account = ( + thl_ledger_manager.get_account_or_create_user_attempt_credit(user) + ) + user_txs = thl_ledger_manager.get_user_txs( + user, account_uuid=attempt_credit_account.uuid + ) + assert user_txs.total == 1 + assert user_txs.transactions[0].tx_type == TransactionType.USER_ATTEMPT_CREDIT + assert user_txs.transactions[0].amount == 5 + assert user_txs.transactions[0].balance_after == 5 + assert user_txs.summary.user_attempt_credit.entry_count == 1 + assert user_txs.summary.user_attempt_credit.total_amount == 5 + + user_txs_by_name = thl_ledger_manager.get_user_txs( + user, qualified_name=attempt_credit_account.qualified_name + ) + assert user_txs_by_name == user_txs + with pytest.raises( LedgerTransactionConditionFailedError, match=r"^duplicate tag$" ): @@ -887,6 +905,15 @@ class TestThlLedgerTxManager: assert thl_ledger_manager.get_user_wallet_balance(user) == round(user_pay * 100) assert thl_ledger_manager.check_ledger_balanced() + attempt_credit_account = ( + thl_ledger_manager.get_account_or_create_user_attempt_credit(user) + ) + user_txs = thl_ledger_manager.get_user_txs( + user, account_uuid=attempt_credit_account.uuid + ) + assert [tx.amount for tx in user_txs.transactions] == [5, -5] + assert [tx.balance_after for tx in user_txs.transactions] == [5, 0] + def test_bp_payment_with_zero_attempt_credit_balance( self, session_factory: Callable[..., Session], diff --git a/tests/managers/thl/test_ledger/test_thl_pem.py b/tests/managers/thl/test_ledger/test_thl_pem.py index fb35aa4..4761438 100644 --- a/tests/managers/thl/test_ledger/test_thl_pem.py +++ b/tests/managers/thl/test_ledger/test_thl_pem.py @@ -30,7 +30,6 @@ if TYPE_CHECKING: class TestThlPayoutEventManager: - def test_get_by_uuid( self, brokerage_product_payout_event_manager: BrokerageProductPayoutEventManager ): @@ -50,8 +49,9 @@ class TestThlPayoutEventManager: bp_payout_event_factory: Callable[..., BrokerageProductPayoutEvent], thl_ledger_manager: ThlLedgerManager, brokerage_product_payout_event_manager: BrokerageProductPayoutEventManager, + create_main_accounts, ): - + create_main_accounts() N_PRODUCTS = randint(3, 10) N_PAYOUT_EVENTS = randint(3, 10) amounts = [] @@ -223,7 +223,6 @@ class TestThlPayoutEventManager: class TestBPPayoutEvent: - def test_get_bp_bp_payout_events_for_products( self, product_factory: Callable[..., Product], diff --git a/tests/managers/thl/test_payout.py b/tests/managers/thl/test_payout.py index 52bbbec..69b9737 100644 --- a/tests/managers/thl/test_payout.py +++ b/tests/managers/thl/test_payout.py @@ -163,7 +163,9 @@ class TestPayout: thl_ledger_manager: ThlLedgerManager, utc_now: datetime, pending_bp_pe: BrokerageProductPayoutEvent, + create_main_accounts, ): + create_main_accounts() thl_ledger_manager.get_account_or_create_bp_wallet(product=product) brokerage_product_payout_event_manager.create_tx_bp_payout_from_payout_event( @@ -871,6 +873,7 @@ class TestBusinessPayoutEventManager: bp1 = business_payout_event_manager.create_from_ach_or_wire( business=gr_business, amount=USDCent(bb1.available_balance), + transaction_id=ach_id1, pm=product_manager, thl_lm=thl_ledger_manager, created=start + timedelta(days=1, hours=5), @@ -901,22 +904,22 @@ class TestBusinessPayoutEventManager: ledger_collection.initial_load(client=None, sync=True) pop_ledger_merge.build(client=client_no_amm, ledger_coll=ledger_collection) - business.prebuild_balance( - thl_pg_config=thl_web_rr, + gr_business.prebuild_balance( + product_manager=product_manager, lm=ledger_manager, ds=mnt_filepath, client=client_no_amm, pop_ledger=pop_ledger_merge, ) - business.prebuild_payouts( + gr_business.prebuild_payouts( bpem=business_payout_event_manager, ) - assert isinstance(business.payouts, list) - assert len(business.payouts) == 2 - assert len(business.payouts[0].bp_payouts) == 2 - assert len(business.payouts[1].bp_payouts) == 1 + assert isinstance(gr_business.payouts, list) + assert len(gr_business.payouts) == 2 + assert len(gr_business.payouts[0].bp_payouts) == 2 + assert len(gr_business.payouts[1].bp_payouts) == 1 - bb2 = business.balance + bb2 = gr_business.balance # Okay os we have the balance before, and after the Business Payout # of bb1.available_balance worth.. -- cgit v1.2.3