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 randint, random from typing import TYPE_CHECKING, Any from uuid import uuid4 import faker import pytest from grip_client.enums import AccessType from pydantic import PositiveInt from generalresearch.models.custom_types import ( AwareDatetimeISO, IPvAnyAddressStr, UUIDStr, ) from generalresearch.models.thl.definitions import PayoutStatus from generalresearch.models.thl.session import ( Source, Status, ) from generalresearch.models.thl.user import User from generalresearch.models.thl.userhealth import AuditLogLevel from generalresearch.models.thl.wallet.definitions import PayoutType if TYPE_CHECKING: 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.definitions import DeviceType from generalresearch.models.gr.business import Business from generalresearch.models.gr.team import Team from generalresearch.models.legacy.bucket import Bucket from generalresearch.models.thl.ipinfo import IPGeoname, IPInformation 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, Wall, ) from generalresearch.models.thl.user_iphistory import IPRecord from generalresearch.models.thl.userhealth import AuditLog 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 rand_choice(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 # --- Product --- @pytest.fixture() def product_factory(product_manager: ProductManager) -> Callable[..., Product]: def _inner( save: bool = True, team: Team | None = None, business: Business | None = None, product_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.uuid if team else uuid4().hex business_id = business.uuid if business 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/" if save: 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, ) else: raise ValueError("Unsaved Product not yet supported") return _inner @pytest.fixture() def product(product_factory: Callable[..., Product]) -> Product: return product_factory(save=True) @pytest.fixture() def unsaved_product(product_factory: Callable[..., Product]) -> Product: return product_factory(save=False) # --- Session --- @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: AccessType | 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 rand_choice(list(AuditLogLevel)), event_type=event_type or rand_choice(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"}]}' )