aboutsummaryrefslogtreecommitdiff
path: root/test_utils/models/contest
diff options
context:
space:
mode:
authorMax Nanis2026-08-21 11:31:13 -0700
committerMax Nanis2026-08-21 11:31:13 -0700
commitff538deb290c851364df85aa6ccc64bc3719ef64 (patch)
treec04c3573ab6adab70971fef00d3420a5da5f9619 /test_utils/models/contest
parent4fe0f6b5e0f0c744902e4c3ab8940e23a6f8a2e1 (diff)
parentc4a44873540ca4c0a3ab19b9beef4cfc6e0252a7 (diff)
downloadgeneralresearch-ff538deb290c851364df85aa6ccc64bc3719ef64.tar.gz
generalresearch-ff538deb290c851364df85aa6ccc64bc3719ef64.zip
Merge branch 'master' into dev
Diffstat (limited to 'test_utils/models/contest')
-rw-r--r--test_utils/models/contest/__init__.py0
-rw-r--r--test_utils/models/contest/conftest.py292
2 files changed, 292 insertions, 0 deletions
diff --git a/test_utils/models/contest/__init__.py b/test_utils/models/contest/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test_utils/models/contest/__init__.py
diff --git a/test_utils/models/contest/conftest.py b/test_utils/models/contest/conftest.py
new file mode 100644
index 0000000..e750076
--- /dev/null
+++ b/test_utils/models/contest/conftest.py
@@ -0,0 +1,292 @@
+from __future__ import annotations
+
+from datetime import datetime, timezone
+from decimal import Decimal
+from typing import Callable
+from uuid import uuid4
+
+import pytest
+from fastapi import Request
+
+from generalresearch.currency import USDCent
+from generalresearch.managers.thl.contest_manager import ContestManager
+from generalresearch.managers.thl.ledger_manager.thl_ledger import ThlLedgerManager
+from generalresearch.models.thl.contest.contest import Contest
+from generalresearch.models.thl.contest.leaderboard import (
+ LeaderboardContestCreate,
+)
+from generalresearch.models.thl.contest.milestone import (
+ MilestoneContestCreate,
+)
+from generalresearch.models.thl.contest.raffle import (
+ RaffleContestCreate,
+)
+from generalresearch.models.thl.product import Product
+from generalresearch.models.thl.user import User
+
+# === Miscellaneous ===
+
+# === Managers ===
+
+# === Models ===
+
+
+@pytest.fixture
+def raffle_contest_create() -> RaffleContestCreate:
+ from generalresearch.models.thl.contest import (
+ ContestEndCondition,
+ ContestPrize,
+ )
+ from generalresearch.models.thl.contest.definitions import (
+ ContestPrizeKind,
+ ContestType,
+ )
+ from generalresearch.models.thl.contest.raffle import (
+ ContestEntryType,
+ RaffleContestCreate,
+ )
+
+ # This is what we'll get from the fastapi endpoint
+ return RaffleContestCreate(
+ name="test",
+ contest_type=ContestType.RAFFLE,
+ entry_type=ContestEntryType.CASH,
+ prizes=[
+ ContestPrize(
+ name="iPod 64GB White",
+ kind=ContestPrizeKind.PHYSICAL,
+ estimated_cash_value=USDCent(100),
+ )
+ ],
+ end_condition=ContestEndCondition(target_entry_amount=USDCent(100)),
+ )
+
+
+@pytest.fixture
+def raffle_contest_in_db(
+ product_user_wallet_yes: Product,
+ raffle_contest_create: RaffleContestCreate,
+ contest_manager: ContestManager,
+) -> Contest:
+ return contest_manager.create(
+ product_id=product_user_wallet_yes.uuid, contest_create=raffle_contest_create
+ )
+
+
+@pytest.fixture
+def raffle_contest(
+ product_user_wallet_yes: Product, raffle_contest_create: RaffleContestCreate
+) -> Contest:
+ from generalresearch.models.thl.contest.io import contest_create_to_contest
+
+ return contest_create_to_contest(
+ product_id=product_user_wallet_yes.uuid, contest_create=raffle_contest_create
+ )
+
+
+@pytest.fixture(scope="function")
+def raffle_contest_factory(
+ product_user_wallet_yes: Product,
+ raffle_contest_create: RaffleContestCreate,
+ contest_manager: ContestManager,
+) -> Callable[..., Contest]:
+
+ def _inner(**kwargs):
+ raffle_contest_create.update(**kwargs)
+ return contest_manager.create(
+ product_id=product_user_wallet_yes.uuid,
+ contest_create=raffle_contest_create,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def milestone_contest_create() -> MilestoneContestCreate:
+ from generalresearch.models.thl.contest import (
+ ContestPrize,
+ )
+ from generalresearch.models.thl.contest.definitions import (
+ ContestPrizeKind,
+ ContestType,
+ )
+ from generalresearch.models.thl.contest.milestone import (
+ ContestEntryTrigger,
+ MilestoneContestCreate,
+ MilestoneContestEndCondition,
+ )
+
+ # This is what we'll get from the fastapi endpoint
+ return MilestoneContestCreate(
+ name="Win a 50% bonus for 7 days and a $1 bonus after your first 3 completes!",
+ description="only valid for the first 5 users",
+ contest_type=ContestType.MILESTONE,
+ prizes=[
+ ContestPrize(
+ name="50% for 7 days",
+ kind=ContestPrizeKind.PROMOTION,
+ estimated_cash_value=USDCent(0),
+ ),
+ ContestPrize(
+ name="$1 Bonus",
+ kind=ContestPrizeKind.CASH,
+ cash_amount=USDCent(1_00),
+ estimated_cash_value=USDCent(1_00),
+ ),
+ ],
+ end_condition=MilestoneContestEndCondition(
+ ends_at=datetime(year=2030, month=1, day=1, tzinfo=timezone.utc),
+ max_winners=5,
+ ),
+ entry_trigger=ContestEntryTrigger.TASK_COMPLETE,
+ target_amount=3,
+ )
+
+
+@pytest.fixture
+def milestone_contest_in_db(
+ product_user_wallet_yes: Product,
+ milestone_contest_create: MilestoneContestCreate,
+ contest_manager: ContestManager,
+) -> Contest:
+ return contest_manager.create(
+ product_id=product_user_wallet_yes.uuid, contest_create=milestone_contest_create
+ )
+
+
+@pytest.fixture
+def milestone_contest(
+ product_user_wallet_yes: Product,
+ milestone_contest_create: MilestoneContestCreate,
+) -> Contest:
+ from generalresearch.models.thl.contest.io import contest_create_to_contest
+
+ return contest_create_to_contest(
+ product_id=product_user_wallet_yes.uuid, contest_create=milestone_contest_create
+ )
+
+
+@pytest.fixture(scope="function")
+def milestone_contest_factory(
+ product_user_wallet_yes: Product,
+ milestone_contest_create: MilestoneContestCreate,
+ contest_manager: ContestManager,
+) -> Callable[..., Contest]:
+
+ def _inner(**kwargs):
+ milestone_contest_create.update(**kwargs)
+ return contest_manager.create(
+ product_id=product_user_wallet_yes.uuid,
+ contest_create=milestone_contest_create,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def leaderboard_contest_create(
+ product_user_wallet_yes: Product,
+) -> LeaderboardContestCreate:
+ from generalresearch.models.thl.contest import (
+ ContestPrize,
+ )
+ from generalresearch.models.thl.contest.definitions import (
+ ContestPrizeKind,
+ ContestType,
+ )
+ from generalresearch.models.thl.contest.leaderboard import (
+ LeaderboardContestCreate,
+ )
+
+ # This is what we'll get from the fastapi endpoint
+ return LeaderboardContestCreate(
+ name="test",
+ contest_type=ContestType.LEADERBOARD,
+ prizes=[
+ ContestPrize(
+ name="$15 Cash",
+ estimated_cash_value=USDCent(15_00),
+ cash_amount=USDCent(15_00),
+ kind=ContestPrizeKind.CASH,
+ leaderboard_rank=1,
+ ),
+ ContestPrize(
+ name="$10 Cash",
+ estimated_cash_value=USDCent(10_00),
+ cash_amount=USDCent(10_00),
+ kind=ContestPrizeKind.CASH,
+ leaderboard_rank=2,
+ ),
+ ],
+ leaderboard_key=f"leaderboard:{product_user_wallet_yes.uuid}:us:daily:2025-01-01:complete_count",
+ )
+
+
+@pytest.fixture
+def leaderboard_contest_in_db(
+ product_user_wallet_yes: Product,
+ leaderboard_contest_create: LeaderboardContestCreate,
+ contest_manager: ContestManager,
+) -> Contest:
+ return contest_manager.create(
+ product_id=product_user_wallet_yes.uuid,
+ contest_create=leaderboard_contest_create,
+ )
+
+
+@pytest.fixture
+def leaderboard_contest(
+ product_user_wallet_yes: Product,
+ leaderboard_contest_create: LeaderboardContestCreate,
+):
+ from generalresearch.models.thl.contest.io import contest_create_to_contest
+
+ return contest_create_to_contest(
+ product_id=product_user_wallet_yes.uuid,
+ contest_create=leaderboard_contest_create,
+ )
+
+
+@pytest.fixture(scope="function")
+def leaderboard_contest_factory(
+ product_user_wallet_yes: Product,
+ leaderboard_contest_create: LeaderboardContestCreate,
+ contest_manager: ContestManager,
+) -> Callable[..., Contest]:
+
+ def _inner(**kwargs):
+ leaderboard_contest_create.update(**kwargs)
+ return contest_manager.create(
+ product_id=product_user_wallet_yes.uuid,
+ contest_create=leaderboard_contest_create,
+ )
+
+ return _inner
+
+
+@pytest.fixture
+def user_with_money(
+ request: Request,
+ user_factory: Callable[..., User],
+ product_user_wallet_yes: Product,
+ thl_lm: ThlLedgerManager,
+) -> User:
+
+ params = getattr(request, "param", {}) or {}
+ min_balance = int(params.get("min_balance", USDCent(1_00)))
+
+ user: User = user_factory(product=product_user_wallet_yes)
+ wallet = thl_lm.get_account_or_create_user_wallet(user)
+ balance = thl_lm.get_account_balance(wallet)
+ todo = min_balance - balance
+ if todo > 0:
+ # # Put money in user's wallet
+ thl_lm.create_tx_user_bonus(
+ user=user,
+ ref_uuid=uuid4().hex,
+ description="bonus",
+ amount=Decimal(todo) / 100,
+ )
+ print(f"wallet balance: {thl_lm.get_user_wallet_balance(user=user)}")
+
+ return user