aboutsummaryrefslogtreecommitdiff
path: root/tests/models/thl/test_contest/test_leaderboard_contest.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/models/thl/test_contest/test_leaderboard_contest.py')
-rw-r--r--tests/models/thl/test_contest/test_leaderboard_contest.py213
1 files changed, 213 insertions, 0 deletions
diff --git a/tests/models/thl/test_contest/test_leaderboard_contest.py b/tests/models/thl/test_contest/test_leaderboard_contest.py
new file mode 100644
index 0000000..98f3215
--- /dev/null
+++ b/tests/models/thl/test_contest/test_leaderboard_contest.py
@@ -0,0 +1,213 @@
+from datetime import timezone
+from uuid import uuid4
+
+import pytest
+
+from generalresearch.currency import USDCent
+from generalresearch.managers.leaderboard.manager import LeaderboardManager
+from generalresearch.models.thl.contest import ContestPrize
+from generalresearch.models.thl.contest.definitions import (
+ ContestType,
+ ContestPrizeKind,
+)
+from generalresearch.models.thl.contest.leaderboard import (
+ LeaderboardContest,
+)
+from generalresearch.models.thl.contest.utils import (
+ distribute_leaderboard_prizes,
+)
+from generalresearch.models.thl.leaderboard import LeaderboardRow
+from tests.models.thl.test_contest.test_contest import TestContest
+
+
+class TestLeaderboardContest(TestContest):
+
+ @pytest.fixture
+ def leaderboard_contest(
+ self, product, thl_redis, user_manager
+ ) -> "LeaderboardContest":
+ board_key = f"leaderboard:{product.uuid}:us:weekly:2025-05-26:complete_count"
+
+ c = LeaderboardContest(
+ uuid=uuid4().hex,
+ product_id=product.uuid,
+ contest_type=ContestType.LEADERBOARD,
+ leaderboard_key=board_key,
+ name="$15 1st place, $10 2nd, $5 3rd place US weekly",
+ 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,
+ ),
+ ContestPrize(
+ name="$5 Cash",
+ estimated_cash_value=USDCent(5_00),
+ cash_amount=USDCent(5_00),
+ kind=ContestPrizeKind.CASH,
+ leaderboard_rank=3,
+ ),
+ ],
+ )
+ c._redis_client = thl_redis
+ c._user_manager = user_manager
+ return c
+
+ def test_init(self, leaderboard_contest, thl_redis, user_1, user_2):
+ model = leaderboard_contest.leaderboard_model
+ assert leaderboard_contest.end_condition.ends_at is not None
+
+ lbm = LeaderboardManager(
+ redis_client=thl_redis,
+ board_code=model.board_code,
+ country_iso=model.country_iso,
+ freq=model.freq,
+ product_id=leaderboard_contest.product_id,
+ within_time=model.period_start_local,
+ )
+
+ lbm.hit_complete_count(product_user_id=user_1.product_user_id)
+ lbm.hit_complete_count(product_user_id=user_2.product_user_id)
+ lbm.hit_complete_count(product_user_id=user_2.product_user_id)
+
+ lb = leaderboard_contest.get_leaderboard()
+ print(lb)
+
+ def test_win(self, leaderboard_contest, thl_redis, user_1, user_2, user_3):
+ model = leaderboard_contest.leaderboard_model
+ lbm = LeaderboardManager(
+ redis_client=thl_redis,
+ board_code=model.board_code,
+ country_iso=model.country_iso,
+ freq=model.freq,
+ product_id=leaderboard_contest.product_id,
+ within_time=model.period_start_local.astimezone(tz=timezone.utc),
+ )
+
+ lbm.hit_complete_count(product_user_id=user_1.product_user_id)
+ lbm.hit_complete_count(product_user_id=user_1.product_user_id)
+
+ lbm.hit_complete_count(product_user_id=user_2.product_user_id)
+
+ lbm.hit_complete_count(product_user_id=user_3.product_user_id)
+
+ leaderboard_contest.end_contest()
+ assert len(leaderboard_contest.all_winners) == 3
+
+ # Prizes are $15, $10, $5. user 2 and 3 ties for 2nd place, so they split (10 + 5)
+ assert leaderboard_contest.all_winners[0].awarded_cash_amount == USDCent(15_00)
+ assert (
+ leaderboard_contest.all_winners[0].user.product_user_id
+ == user_1.product_user_id
+ )
+ assert leaderboard_contest.all_winners[0].prize == leaderboard_contest.prizes[0]
+ assert leaderboard_contest.all_winners[1].awarded_cash_amount == USDCent(
+ 15_00 / 2
+ )
+ assert leaderboard_contest.all_winners[2].awarded_cash_amount == USDCent(
+ 15_00 / 2
+ )
+
+
+class TestLeaderboardContestPrizes:
+
+ def test_distribute_prizes_1(self):
+ prizes = [USDCent(15_00)]
+ leaderboard_rows = [
+ LeaderboardRow(bpuid="a", value=20, rank=1),
+ LeaderboardRow(bpuid="b", value=10, rank=2),
+ ]
+ result = distribute_leaderboard_prizes(prizes, leaderboard_rows)
+
+ # a gets first prize, b gets nothing.
+ assert result == {
+ "a": USDCent(15_00),
+ }
+
+ def test_distribute_prizes_2(self):
+ prizes = [USDCent(15_00), USDCent(10_00)]
+ leaderboard_rows = [
+ LeaderboardRow(bpuid="a", value=20, rank=1),
+ LeaderboardRow(bpuid="b", value=10, rank=2),
+ ]
+ result = distribute_leaderboard_prizes(prizes, leaderboard_rows)
+
+ # a gets first prize, b gets 2nd prize
+ assert result == {
+ "a": USDCent(15_00),
+ "b": USDCent(10_00),
+ }
+
+ def test_distribute_prizes_3(self):
+ prizes = [USDCent(15_00), USDCent(10_00)]
+ leaderboard_rows = [
+ LeaderboardRow(bpuid="a", value=20, rank=1),
+ ]
+ result = distribute_leaderboard_prizes(prizes, leaderboard_rows)
+
+ # A gets first prize, no-one gets $10
+ assert result == {
+ "a": USDCent(15_00),
+ }
+
+ def test_distribute_prizes_4(self):
+ prizes = [USDCent(15_00)]
+ leaderboard_rows = [
+ LeaderboardRow(bpuid="a", value=20, rank=1),
+ LeaderboardRow(bpuid="b", value=20, rank=1),
+ LeaderboardRow(bpuid="c", value=20, rank=1),
+ LeaderboardRow(bpuid="d", value=20, rank=1),
+ ]
+ result = distribute_leaderboard_prizes(prizes, leaderboard_rows)
+
+ # 4-way tie for the $15 prize; it gets split
+ assert result == {
+ "a": USDCent(3_75),
+ "b": USDCent(3_75),
+ "c": USDCent(3_75),
+ "d": USDCent(3_75),
+ }
+
+ def test_distribute_prizes_5(self):
+ prizes = [USDCent(15_00), USDCent(10_00)]
+ leaderboard_rows = [
+ LeaderboardRow(bpuid="a", value=20, rank=1),
+ LeaderboardRow(bpuid="b", value=20, rank=1),
+ LeaderboardRow(bpuid="c", value=10, rank=3),
+ ]
+ result = distribute_leaderboard_prizes(prizes, leaderboard_rows)
+
+ # 2-way tie for the $15 prize; the top two prizes get split. Rank 3
+ # and below get nothing
+ assert result == {
+ "a": USDCent(12_50),
+ "b": USDCent(12_50),
+ }
+
+ def test_distribute_prizes_6(self):
+ prizes = [USDCent(15_00), USDCent(10_00), USDCent(5_00)]
+ leaderboard_rows = [
+ LeaderboardRow(bpuid="a", value=20, rank=1),
+ LeaderboardRow(bpuid="b", value=10, rank=2),
+ LeaderboardRow(bpuid="c", value=10, rank=2),
+ LeaderboardRow(bpuid="d", value=10, rank=2),
+ ]
+ result = distribute_leaderboard_prizes(prizes, leaderboard_rows)
+
+ # A gets first prize, 3 way tie for 2nd rank: they split the 2nd and
+ # 3rd place prizes (10 + 5)/3
+ assert result == {
+ "a": USDCent(15_00),
+ "b": USDCent(5_00),
+ "c": USDCent(5_00),
+ "d": USDCent(5_00),
+ }