from __future__ import annotations from collections.abc import Callable from datetime import UTC, datetime from decimal import ROUND_DOWN, Decimal from random import choice as rand_choice from random import choice as rchoice from random import randint, random from typing import Any from uuid import uuid4 import faker import pytest from pydantic import PositiveInt from generalresearch.managers.thl.ipinfo import IPGeonameManager, IPInformationManager from generalresearch.managers.thl.payout import UserPayoutEventManager from generalresearch.managers.thl.product import ProductManager from generalresearch.managers.thl.session import SessionManager from generalresearch.managers.thl.user_manager.user_manager import UserManager from generalresearch.managers.thl.userhealth import AuditLogManager, IPRecordManager from generalresearch.managers.thl.wall import WallManager from generalresearch.models import DeviceType from generalresearch.models.custom_types import ( AwareDatetimeISO, IPvAnyAddressStr, UUIDStr, ) from generalresearch.models.legacy.bucket import Bucket from generalresearch.models.thl.definitions import ( PayoutStatus, ) from generalresearch.models.thl.ipinfo import IPGeoname, IPInformation, UserType from generalresearch.models.thl.payout import UserPayoutEvent from generalresearch.models.thl.product import ( PayoutConfig, Product, ProfilingConfig, SessionConfig, SourcesConfig, SupplyConfig, UserCreateConfig, UserHealthConfig, UserWalletConfig, ) from generalresearch.models.thl.session import ( Session, Source, Status, Wall, ) from generalresearch.models.thl.user import User from generalresearch.models.thl.user_iphistory import IPRecord from generalresearch.models.thl.userhealth import AuditLog, AuditLogLevel from generalresearch.models.thl.wallet import PayoutType from generalresearch.models.thl.wallet.cashout_method import CashMailOrderData fake = faker.Faker() @pytest.fixture def wall_status() -> Status: return Status.COMPLETE @pytest.fixture def user_factory(user_manager: UserManager) -> Callable[..., User]: def _inner( # --- Create dummy "optional" --- # product_user_id: str | None = None, # --- Optional --- # product_id: UUIDStr | None = None, product: Product | None = None, created: datetime | None = None, ) -> User: product_user_id = product_user_id or uuid4().hex return user_manager.create_user( product_user_id=product_user_id, product_id=product_id, product=product, created=created, ) return _inner @pytest.fixture def wall_factory( wall_manager: WallManager, session_factory: Session ) -> Callable[..., Wall]: def _inner( session_id: int | None = None, user_id: int | None = None, started: datetime | None = None, source: Source | None = None, req_survey_id: str | None = None, req_cpi: Decimal | None = None, buyer_id: str | None = None, uuid_id: str | None = None, ): """To be used in tests, where we don't care about certain fields""" user_id = user_id or fake.random_int(min=1, max=2_147_483_648) started = started or fake.date_time_between( start_date=datetime(year=1900, month=1, day=1, tzinfo=UTC), end_date=datetime.now(tz=UTC), tzinfo=UTC, ) if session_id is None: # session = SessionManager(pg_config=self.pg_config).create_dummy( # started=started # ) session = session_factory() session_id = session.id source = source or rchoice(list(Source)) req_survey_id = req_survey_id or uuid4().hex req_cpi = req_cpi or Decimal(fake.random_int(min=1, max=150) / 100).quantize( Decimal(".01"), rounding=ROUND_DOWN ) return wall_manager.create( session_id=session_id, user_id=user_id, started=started, source=source, req_survey_id=req_survey_id, req_cpi=req_cpi, buyer_id=buyer_id, uuid_id=uuid_id, ) return _inner @pytest.fixture def product_factory(product_manager: ProductManager) -> Callable[..., Product]: def _inner( product_id: UUIDStr | None = None, team_id: UUIDStr | None = None, business_id: UUIDStr | None = None, name: str | None = None, redirect_url: str | None = None, harmonizer_domain: str | None = None, commission_pct: Decimal = Decimal("0.05000"), sources_config: SourcesConfig | SupplyConfig | None = None, payout_config: PayoutConfig | None = None, session_config: SessionConfig | None = None, profiling_config: ProfilingConfig | None = None, user_wallet_config: UserWalletConfig | None = None, user_create_config: UserCreateConfig | None = None, user_health_config: UserHealthConfig | None = None, ) -> Product: """To be used in tests, where we don't care about certain fields""" product_id = product_id if product_id else uuid4().hex team_id = team_id if team_id else uuid4().hex name = name if name else f"name-{product_id[:12]}" redirect_url = redirect_url if redirect_url else "https://www.example.com/" return product_manager.create( product_id=product_id, team_id=team_id, business_id=business_id, name=name, redirect_url=redirect_url, harmonizer_domain=harmonizer_domain, commission_pct=commission_pct, sources_config=sources_config, payout_config=payout_config, session_config=session_config, profiling_config=profiling_config, user_wallet_config=user_wallet_config, user_create_config=user_create_config, user_health_config=user_health_config, ) return _inner @pytest.fixture def session_factory(session_manager: SessionManager): def _inner( # -- Create Dummy "optional" -- # started: datetime | None = None, user: User | None = None, # -- Optional -- # country_iso: str | None = None, device_type: DeviceType | None = None, ip: str | None = None, bucket: Bucket | None = None, url_metadata: dict[str, str] | None = None, uuid_id: str | None = None, ) -> Session: """To be used in tests, where we don't care about certain fields""" started = started or fake.date_time_between( start_date=datetime(year=1900, month=1, day=1, tzinfo=UTC), end_date=datetime(year=2000, month=1, day=1, tzinfo=UTC), tzinfo=UTC, ) user = user or User( user_id=fake.random_int(min=1, max=2_147_483_648), uuid=uuid4().hex ) return session_manager.create( started=started, user=user, country_iso=country_iso, device_type=device_type, ip=ip, bucket=bucket, url_metadata=url_metadata, uuid_id=uuid_id, ) return _inner @pytest.fixture def ipgeoname_factory(ipgeoname_manager: IPGeonameManager) -> Callable[..., IPGeoname]: def _inner( geoname_id: PositiveInt | None = None, continent_code: str | None = None, continent_name: str | None = None, country_iso: str | None = None, country_name: str | None = None, subdivision_1_iso: str | None = None, subdivision_1_name: str | None = None, subdivision_2_iso: str | None = None, subdivision_2_name: str | None = None, city_name: str | None = None, metro_code: int | None = None, time_zone: str | None = None, is_in_european_union: bool | None = None, ) -> IPGeoname: return ipgeoname_manager.create( geoname_id=geoname_id or randint(1, 999_999_999), continent_code=continent_code or "na", continent_name=continent_name or "North America", country_iso=country_iso or "us", country_name=country_name or "United States", subdivision_1_iso=subdivision_1_iso or "fl", subdivision_1_name=subdivision_1_name or "Florida", subdivision_2_iso=subdivision_2_iso, subdivision_2_name=subdivision_2_name, city_name=city_name, metro_code=metro_code, time_zone=time_zone, is_in_european_union=is_in_european_union, ) return _inner def ipinformation_factory( ipinformation_manager: IPInformationManager, ) -> Callable[..., IPInformation]: def _inner( ip: IPvAnyAddressStr | None = None, geoname_id: PositiveInt | None = None, country_iso: str | None = None, registered_country_iso: str | None = None, is_anonymous: bool | None = None, is_anonymous_vpn: bool | None = None, is_hosting_provider: bool | None = None, is_public_proxy: bool | None = None, is_tor_exit_node: bool | None = None, is_residential_proxy: bool | None = None, autonomous_system_number: PositiveInt | None = None, autonomous_system_organization: str | None = None, domain: str | None = None, isp: str | None = None, mobile_country_code: str | None = None, mobile_network_code: str | None = None, network: str | None = None, organization: str | None = None, static_ip_score: float | None = None, user_type: UserType | None = None, postal_code: str | None = None, latitude: Decimal | None = None, longitude: Decimal | None = None, accuracy_radius: int | None = None, ) -> IPInformation: return ipinformation_manager.create( ip=ip or fake.ipv4_public(), geoname_id=geoname_id, country_iso=country_iso or fake.country_code(), registered_country_iso=registered_country_iso, is_anonymous=is_anonymous, is_anonymous_vpn=is_anonymous_vpn, is_hosting_provider=is_hosting_provider, is_public_proxy=is_public_proxy, is_tor_exit_node=is_tor_exit_node, is_residential_proxy=is_residential_proxy, autonomous_system_number=autonomous_system_number, autonomous_system_organization=autonomous_system_organization, domain=domain, isp=isp, mobile_country_code=mobile_country_code, mobile_network_code=mobile_network_code, network=network, organization=organization, static_ip_score=static_ip_score, user_type=user_type, postal_code=postal_code, latitude=latitude, longitude=longitude, accuracy_radius=accuracy_radius, ) return _inner @pytest.fixture def user_payout_event_factory( user_payout_event_manager: UserPayoutEventManager, ) -> Callable[..., UserPayoutEvent]: def _inner( uuid: UUIDStr | None = None, debit_account_uuid: UUIDStr | None = None, account_reference_type: str | None = None, account_reference_uuid: UUIDStr | None = None, cashout_method_uuid: UUIDStr | None = None, description: str | None = None, created: AwareDatetimeISO | None = None, amount: PositiveInt | None = None, status: PayoutStatus | None = None, ext_ref_id: str | None = None, payout_type: PayoutType | None = None, request_data: dict[str, Any] | None = None, order_data: dict[str, Any] | CashMailOrderData | None = None, ) -> UserPayoutEvent: debit_account_uuid = debit_account_uuid or uuid4().hex cashout_method_uuid = cashout_method_uuid or uuid4().hex # account_reference_type = account_reference_type or f"acct-ref-{uuid4().hex}" # account_reference_uuid = account_reference_uuid or uuid4().hex # cashout_method_uuid = cashout_method_uuid or uuid4().hex amount = amount or randint(a=99, b=9_999) status = status or rand_choice(list(PayoutStatus)) description = description or f"desc-{uuid4().hex[:12]}" # ext_ref_id = ext_ref_id or f"ext-ref-{uuid4().hex[:8]}" payout_type = payout_type or rand_choice(list(PayoutType)) request_data = request_data or {} # order_data = order_data or None return user_payout_event_manager.create( uuid=uuid, debit_account_uuid=debit_account_uuid, account_reference_type=account_reference_type, account_reference_uuid=account_reference_uuid, cashout_method_uuid=cashout_method_uuid, description=description, created=created, amount=amount, status=status, ext_ref_id=ext_ref_id, payout_type=payout_type, request_data=request_data, order_data=order_data, ) return _inner @pytest.fixture def iprecord_factory(iprecord_manager: IPRecordManager) -> Callable[..., IPRecord]: def _inner( user_id: PositiveInt, ip: IPvAnyAddressStr | None = None, forwarded_ip1: IPvAnyAddressStr | None = None, forwarded_ip2: IPvAnyAddressStr | None = None, forwarded_ip3: IPvAnyAddressStr | None = None, forwarded_ip4: IPvAnyAddressStr | None = None, forwarded_ip5: IPvAnyAddressStr | None = None, forwarded_ip6: IPvAnyAddressStr | None = None, ) -> IPRecord: return iprecord_manager.create( user_id=user_id, ip=ip or fake.ipv4_public(), forwarded_ip1=(forwarded_ip1 or fake.ipv4_public()), forwarded_ip2=(forwarded_ip2 or fake.ipv6() if random() < 0.5 else None), forwarded_ip3=( forwarded_ip3 or fake.ipv4_public() if random() < 0.25 else None ), forwarded_ip4=forwarded_ip4, forwarded_ip5=forwarded_ip5, forwarded_ip6=forwarded_ip6, ) return _inner # class AuditLogManager(PostgresManager): @pytest.fixture def auditlog_factory(audit_log_manager: AuditLogManager): def _inner( user_id: PositiveInt, level: AuditLogLevel | None = None, event_type: str | None = None, event_msg: str | None = None, event_value: float | None = None, ) -> AuditLog: event_types = { "offerwall-enter.blocked", "offerwall-enter.rate-limited", "offerwall-enter.url-modified", } return audit_log_manager.create( user_id=user_id, level=level or rchoice(list(AuditLogLevel)), event_type=event_type or rchoice(list(event_types)), event_msg=event_msg, event_value=event_value, ) return _inner @pytest.fixture(scope="session") def profiling_info_json() -> str: return ( '[{"property_label": "hispanic", "cardinality": "*", "prop_type": "i", "country_iso": "us", ' '"property_id": "05170ae296ab49178a075cab2a2073a6", "item_id": "7911ec1468b146ee870951f8ae9cbac1", ' '"item_label": "panamanian", "gold_standard": 1, "options": [{"id": "c358c11e72c74fa2880358f1d4be85ab", ' '"label": "not_hispanic"}, {"id": "b1d6c475770849bc8e0200054975dc9c", "label": "yes_hispanic"}, ' '{"id": "bd1eb44495d84b029e107c188003c2bd", "label": "other_hispanic"}, ' '{"id": "f290ad5e75bf4f4ea94dc847f57c1bd3", "label": "mexican"}, ' '{"id": "49f50f2801bd415ea353063bfc02d252", "label": "puerto_rican"}, ' '{"id": "dcbe005e522f4b10928773926601f8bf", "label": "cuban"}, ' '{"id": "467ef8ddb7ac4edb88ba9ef817cbb7e9", "label": "salvadoran"}, ' '{"id": "3c98e7250707403cba2f4dc7b877c963", "label": "dominican"}, ' '{"id": "981ee77f6d6742609825ef54fea824a8", "label": "guatemalan"}, ' '{"id": "81c8057b809245a7ae1b8a867ea6c91e", "label": "colombian"}, ' '{"id": "513656d5f9e249fa955c3b527d483b93", "label": "honduran"}, ' '{"id": "afc8cddd0c7b4581bea24ccd64db3446", "label": "ecuadorian"}, ' '{"id": "61f34b36e80747a89d85e1eb17536f84", "label": "argentinian"}, ' '{"id": "5330cfa681d44aa8ade3a6d0ea198e44", "label": "peruvian"}, ' '{"id": "e7bceaffd76e486596205d8545019448", "label": "nicaraguan"}, ' '{"id": "b7bbb2ebf8424714962e6c4f43275985", "label": "spanish"}, ' '{"id": "8bf539785e7a487892a2f97e52b1932d", "label": "venezuelan"}, ' '{"id": "7911ec1468b146ee870951f8ae9cbac1", "label": "panamanian"}], "category": [{"id": ' '"4fd8381d5a1c4409ab007ca254ced084", "label": "Demographic", "path": "/Demographic", ' '"adwords_vertical_id": null}]}, {"property_label": "ethnic_group", "cardinality": "*", "prop_type": ' '"i", "country_iso": "us", "property_id": "15070958225d4132b7f6674fcfc979f6", "item_id": ' '"64b7114cf08143949e3bcc3d00a5d8a0", "item_label": "other_ethnicity", "gold_standard": 1, "options": [{' '"id": "a72e97f4055e4014a22bee4632cbf573", "label": "caucasians"}, ' '{"id": "4760353bc0654e46a928ba697b102735", "label": "black_or_african_american"}, ' '{"id": "20ff0a2969fa4656bbda5c3e0874e63b", "label": "asian"}, ' '{"id": "107e0a79e6b94b74926c44e70faf3793", "label": "native_hawaiian_or_other_pacific_islander"}, ' '{"id": "900fa12691d5458c8665bf468f1c98c1", "label": "native_americans"}, ' '{"id": "64b7114cf08143949e3bcc3d00a5d8a0", "label": "other_ethnicity"}], "category": [{"id": ' '"4fd8381d5a1c4409ab007ca254ced084", "label": "Demographic", "path": "/Demographic", ' '"adwords_vertical_id": null}]}, {"property_label": "educational_attainment", "cardinality": "?", ' '"prop_type": "i", "country_iso": "us", "property_id": "2637783d4b2b4075b93e2a156e16e1d8", "item_id": ' '"934e7b81d6744a1baa31bbc51f0965d5", "item_label": "other_education", "gold_standard": 1, "options": [{' '"id": "df35ef9e474b4bf9af520aa86630202d", "label": "3rd_grade_completion"}, ' '{"id": "83763370a1064bd5ba76d1b68c4b8a23", "label": "8th_grade_completion"}, ' '{"id": "f0c25a0670c340bc9250099dcce50957", "label": "not_high_school_graduate"}, ' '{"id": "02ff74c872bd458983a83847e1a9f8fd", "label": "high_school_completion"}, ' '{"id": "ba8beb807d56441f8fea9b490ed7561c", "label": "vocational_program_completion"}, ' '{"id": "65373a5f348a410c923e079ddbb58e9b", "label": "some_college_completion"}, ' '{"id": "2d15d96df85d4cc7b6f58911fdc8d5e2", "label": "associate_academic_degree_completion"}, ' '{"id": "497b1fedec464151b063cd5367643ffa", "label": "bachelors_degree_completion"}, ' '{"id": "295133068ac84424ae75e973dc9f2a78", "label": "some_graduate_completion"}, ' '{"id": "e64f874faeff4062a5aa72ac483b4b9f", "label": "masters_degree_completion"}, ' '{"id": "cbaec19a636d476385fb8e7842b044f5", "label": "doctorate_degree_completion"}, ' '{"id": "934e7b81d6744a1baa31bbc51f0965d5", "label": "other_education"}], "category": [{"id": ' '"4fd8381d5a1c4409ab007ca254ced084", "label": "Demographic", "path": "/Demographic", ' '"adwords_vertical_id": null}]}, {"property_label": "household_spoken_language", "cardinality": "*", ' '"prop_type": "i", "country_iso": "us", "property_id": "5a844571073d482a96853a0594859a51", "item_id": ' '"62b39c1de141422896ad4ab3c4318209", "item_label": "dut", "gold_standard": 1, "options": [{"id": ' '"f65cd57b79d14f0f8460761ce41ec173", "label": "ara"}, {"id": "6d49de1f8f394216821310abd29392d9", ' '"label": "zho"}, {"id": "be6dc23c2bf34c3f81e96ddace22800d", "label": "eng"}, ' '{"id": "ddc81f28752d47a3b1c1f3b8b01a9b07", "label": "fre"}, {"id": "2dbb67b29bd34e0eb630b1b8385542ca", ' '"label": "ger"}, {"id": "a747f96952fc4b9d97edeeee5120091b", "label": "hat"}, ' '{"id": "7144b04a3219433baac86273677551fa", "label": "hin"}, {"id": "e07ff3e82c7149eaab7ea2b39ee6a6dc", ' '"label": "ita"}, {"id": "b681eff81975432ebfb9f5cc22dedaa3", "label": "jpn"}, ' '{"id": "5cb20440a8f64c9ca62fb49c1e80cdef", "label": "kor"}, {"id": "171c4b77d4204bc6ac0c2b81e38a10ff", ' '"label": "pan"}, {"id": "8c3ec18e6b6c4a55a00dd6052e8e84fb", "label": "pol"}, ' '{"id": "3ce074d81d384dd5b96f1fb48f87bf01", "label": "por"}, {"id": "6138dc951990458fa88a666f6ddd907b", ' '"label": "rus"}, {"id": "e66e5ecc07df4ebaa546e0b436f034bd", "label": "spa"}, ' '{"id": "5a981b3d2f0d402a96dd2d0392ec2fcb", "label": "tgl"}, {"id": "b446251bd211403487806c4d0a904981", ' '"label": "vie"}, {"id": "92fb3ee337374e2db875fb23f52eed46", "label": "xxx"}, ' '{"id": "8b1f590f12f24cc1924d7bdcbe82081e", "label": "ind"}, {"id": "bf3f4be556a34ff4b836420149fd2037", ' '"label": "tur"}, {"id": "87ca815c43ba4e7f98cbca98821aa508", "label": "zul"}, ' '{"id": "0adbf915a7a64d67a87bb3ce5d39ca54", "label": "may"}, {"id": "62b39c1de141422896ad4ab3c4318209", ' '"label": "dut"}], "category": [{"id": "4fd8381d5a1c4409ab007ca254ced084", "label": "Demographic", ' '"path": "/Demographic", "adwords_vertical_id": null}]}, {"property_label": "gender", "cardinality": ' '"?", "prop_type": "i", "country_iso": "us", "property_id": "73175402104741549f21de2071556cd7", ' '"item_id": "093593e316344cd3a0ac73669fca8048", "item_label": "other_gender", "gold_standard": 1, ' '"options": [{"id": "b9fc5ea07f3a4252a792fd4a49e7b52b", "label": "male"}, ' '{"id": "9fdb8e5e18474a0b84a0262c21e17b56", "label": "female"}, ' '{"id": "093593e316344cd3a0ac73669fca8048", "label": "other_gender"}], "category": [{"id": ' '"4fd8381d5a1c4409ab007ca254ced084", "label": "Demographic", "path": "/Demographic", ' '"adwords_vertical_id": null}]}, {"property_label": "age_in_years", "cardinality": "?", "prop_type": ' '"n", "country_iso": "us", "property_id": "94f7379437874076b345d76642d4ce6d", "item_id": null, ' '"item_label": null, "gold_standard": 1, "category": [{"id": "4fd8381d5a1c4409ab007ca254ced084", ' '"label": "Demographic", "path": "/Demographic", "adwords_vertical_id": null}]}, {"property_label": ' '"children_age_gender", "cardinality": "*", "prop_type": "i", "country_iso": "us", "property_id": ' '"e926142fcea94b9cbbe13dc7891e1e7f", "item_id": "b7b8074e95334b008e8958ccb0a204f1", "item_label": ' '"female_18", "gold_standard": 1, "options": [{"id": "16a6448ec24c48d4993d78ebee33f9b4", ' '"label": "male_under_1"}, {"id": "809c04cb2e3b4a3bbd8077ab62cdc220", "label": "female_under_1"}, ' '{"id": "295e05bb6a0843bc998890b24c99841e", "label": "no_children"}, ' '{"id": "142cb948d98c4ae8b0ef2ef10978e023", "label": "male_0"}, ' '{"id": "5a5c1b0e9abc48a98b3bc5f817d6e9d0", "label": "male_1"}, ' '{"id": "286b1a9afb884bdfb676dbb855479d1e", "label": "male_2"}, ' '{"id": "942ca3cda699453093df8cbabb890607", "label": "male_3"}, ' '{"id": "995818d432f643ec8dd17e0809b24b56", "label": "male_4"}, ' '{"id": "f38f8b57f25f4cdea0f270297a1e7a5c", "label": "male_5"}, ' '{"id": "975df709e6d140d1a470db35023c432d", "label": "male_6"}, ' '{"id": "f60bd89bbe0f4e92b90bccbc500467c2", "label": "male_7"}, ' '{"id": "6714ceb3ed5042c0b605f00b06814207", "label": "male_8"}, ' '{"id": "c03c2f8271d443cf9df380e84b4dea4c", "label": "male_9"}, ' '{"id": "11690ee0f5a54cb794f7ddd010d74fa2", "label": "male_10"}, ' '{"id": "17bef9a9d14b4197b2c5609fa94b0642", "label": "male_11"}, ' '{"id": "e79c8338fe28454f89ccc78daf6f409a", "label": "male_12"}, ' '{"id": "3a4f87acb3fa41f4ae08dfe2858238c1", "label": "male_13"}, ' '{"id": "36ffb79d8b7840a7a8cb8d63bbc8df59", "label": "male_14"}, ' '{"id": "1401a508f9664347aee927f6ec5b0a40", "label": "male_15"}, ' '{"id": "6e0943c5ec4a4f75869eb195e3eafa50", "label": "male_16"}, ' '{"id": "47d4b27b7b5242758a9fff13d3d324cf", "label": "male_17"}, ' '{"id": "9ce886459dd44c9395eb77e1386ab181", "label": "female_0"}, ' '{"id": "6499ccbf990d4be5b686aec1c7353fd8", "label": "female_1"}, ' '{"id": "d85ceaa39f6d492abfc8da49acfd14f2", "label": "female_2"}, ' '{"id": "18edb45c138e451d8cb428aefbb80f9c", "label": "female_3"}, ' '{"id": "bac6f006ed9f4ccf85f48e91e99fdfd1", "label": "female_4"}, ' '{"id": "5a6a1a8ad00c4ce8be52dcb267b034ff", "label": "female_5"}, ' '{"id": "6bff0acbf6364c94ad89507bcd5f4f45", "label": "female_6"}, ' '{"id": "d0d56a0a6b6f4516a366a2ce139b4411", "label": "female_7"}, ' '{"id": "bda6028468044b659843e2bef4db2175", "label": "female_8"}, ' '{"id": "dbb6d50325464032b456357b1a6e5e9c", "label": "female_9"}, ' '{"id": "b87a93d7dc1348edac5e771684d63fb8", "label": "female_10"}, ' '{"id": "11449d0d98f14e27ba47de40b18921d7", "label": "female_11"}, ' '{"id": "16156501e97b4263962cbbb743840292", "label": "female_12"}, ' '{"id": "04ee971c89a345cc8141a45bce96050c", "label": "female_13"}, ' '{"id": "e818d310bfbc4faba4355e5d2ed49d4f", "label": "female_14"}, ' '{"id": "440d25e078924ba0973163153c417ed6", "label": "female_15"}, ' '{"id": "78ff804cc9b441c5a524bd91e3d1f8bf", "label": "female_16"}, ' '{"id": "4b04d804d7d84786b2b1c22e4ed440f5", "label": "female_17"}, ' '{"id": "28bc848cd3ff44c3893c76bfc9bc0c4e", "label": "male_18"}, ' '{"id": "b7b8074e95334b008e8958ccb0a204f1", "label": "female_18"}], "category": [{"id": ' '"e18ba6e9d51e482cbb19acf2e6f505ce", "label": "Parenting", "path": "/People & Society/Family & ' 'Relationships/Family/Parenting", "adwords_vertical_id": "58"}]}, {"property_label": "home_postal_code", ' '"cardinality": "?", "prop_type": "x", "country_iso": "us", "property_id": ' '"f3b32ebe78014fbeb1ed6ff77d6338bf", "item_id": null, "item_label": null, "gold_standard": 1, ' '"category": [{"id": "4fd8381d5a1c4409ab007ca254ced084", "label": "Demographic", "path": "/Demographic", ' '"adwords_vertical_id": null}]}, {"property_label": "household_income", "cardinality": "?", "prop_type": ' '"n", "country_iso": "us", "property_id": "ff5b1d4501d5478f98de8c90ef996ac1", "item_id": null, ' '"item_label": null, "gold_standard": 1, "category": [{"id": "4fd8381d5a1c4409ab007ca254ced084", ' '"label": "Demographic", "path": "/Demographic", "adwords_vertical_id": null}]}]' ) @pytest.fixture(scope="session") def profiling_user_info_json() -> str: return ( '{"user_profile_knowledge": [], "marketplace_profile_knowledge": [{"source": "d", "question_id": ' '"1", "answer": ["1"], "created": "2023-11-07T16:41:05.234096Z"}, {"source": "pr", ' '"question_id": "3", "answer": ["1"], "created": "2023-11-07T16:41:05.234096Z"}, {"source": ' '"h", "question_id": "60", "answer": ["58"], "created": "2023-11-07T16:41:05.234096Z"}, ' '{"source": "c", "question_id": "43", "answer": ["1"], "created": "2023-11-07T16:41:05.234096Z"}, ' '{"source": "s", "question_id": "211", "answer": ["111"], "created": ' '"2023-11-07T16:41:05.234096Z"}, {"source": "s", "question_id": "1843", "answer": ["111"], ' '"created": "2023-11-07T16:41:05.234096Z"}, {"source": "h", "question_id": "13959", "answer": [' '"244155"], "created": "2023-11-07T16:41:05.234096Z"}, {"source": "c", "question_id": "33092", ' '"answer": ["1"], "created": "2023-11-07T16:41:05.234096Z"}, {"source": "c", "question_id": "gender", ' '"answer": ["10682"], "created": "2023-11-07T16:41:05.234096Z"}, {"source": "e", "question_id": ' '"gender", "answer": ["male"], "created": "2023-11-07T16:41:05.234096Z"}, {"source": "f", ' '"question_id": "gender", "answer": ["male"], "created": "2023-11-07T16:41:05.234096Z"}, {"source": ' '"i", "question_id": "gender", "answer": ["1"], "created": "2023-11-07T16:41:05.234096Z"}, ' '{"source": "c", "question_id": "137510", "answer": ["1"], "created": "2023-11-07T16:41:05.234096Z"}, ' '{"source": "m", "question_id": "gender", "answer": ["1"], "created": ' '"2023-11-07T16:41:05.234096Z"}, {"source": "o", "question_id": "gender", "answer": ["male"], ' '"created": "2023-11-07T16:41:05.234096Z"}, {"source": "c", "question_id": "gender_plus", "answer": [' '"7657644"], "created": "2023-11-07T16:41:05.234096Z"}, {"source": "i", "question_id": ' '"gender_plus", "answer": ["1"], "created": "2023-11-07T16:41:05.234096Z"}, {"source": "c", ' '"question_id": "income_level", "answer": ["9071"], "created": "2023-11-07T16:41:05.234096Z"}]}' )