Files
Solo_bot/tests/test_referrals_and_gifts_resolution.py
2026-04-14 07:19:14 +00:00

152 lines
6.8 KiB
Python

import unittest
from datetime import UTC, datetime
from types import SimpleNamespace
from unittest.mock import AsyncMock, patch
from api.v2.routes.referrals import apply_referral
from api.v2.schemas.web_public import ReferralApplyRequest
from database.gifts import store_gift_link
from database.referrals import add_referral, get_total_referrals
from services.gifts import redeem_gift
class ReferralsResolutionTests(unittest.IsolatedAsyncioTestCase):
async def test_add_referral_creates_relation_for_resolved_users(self):
referred = SimpleNamespace(id=10, tg_id=1010)
referrer = SimpleNamespace(id=20, tg_id=2020)
session = SimpleNamespace(execute=AsyncMock(), commit=AsyncMock(), rollback=AsyncMock())
with patch(
"database.referrals.resolve_user_optional",
new=AsyncMock(side_effect=[referred, referrer]),
):
await add_referral(session, referred_legacy=1010, referrer_legacy=2020)
session.execute.assert_awaited_once()
session.commit.assert_not_called()
async def test_add_referral_ignores_self_referral(self):
same_user = SimpleNamespace(id=30, tg_id=3030)
session = SimpleNamespace(execute=AsyncMock(), commit=AsyncMock(), rollback=AsyncMock())
with patch(
"database.referrals.resolve_user_optional",
new=AsyncMock(side_effect=[same_user, same_user]),
):
await add_referral(session, referred_legacy=3030, referrer_legacy=3030)
session.execute.assert_not_awaited()
session.commit.assert_not_awaited()
async def test_get_total_referrals_returns_zero_when_user_missing(self):
session = SimpleNamespace(execute=AsyncMock())
with patch("database.referrals.resolve_user_optional", new=AsyncMock(return_value=None)):
total = await get_total_referrals(session, referrer_legacy=4040)
self.assertEqual(total, 0)
session.execute.assert_not_awaited()
async def test_apply_referral_accepts_site_referral_code(self):
session = object()
identity = SimpleNamespace(id="ident-email")
body = ReferralApplyRequest(referrer_code="https://example.com/referral/321")
referrer_user = SimpleNamespace(id=321, tg_id=None)
referred_user = SimpleNamespace(id=555, tg_id=None)
with (
patch("api.v2.routes.referrals.idb.ensure_billing_user_for_identity", new=AsyncMock(return_value=555)),
patch(
"api.v2.routes.referrals.resolve_user_optional",
new=AsyncMock(side_effect=[referrer_user, referred_user]),
),
patch("api.v2.routes.referrals.get_referral_by_referred_id", new=AsyncMock(return_value=None)),
patch("api.v2.routes.referrals.add_referral", new=AsyncMock()) as add_referral_mock,
):
result = await apply_referral(body, session=session, identity=identity)
self.assertTrue(result.ok)
self.assertEqual(result.referrer_code, "321")
self.assertEqual(result.referrer_user_id, 321)
self.assertEqual(result.referred_user_id, 555)
add_referral_mock.assert_awaited_once_with(session, 555, 321)
class GiftsResolutionTests(unittest.IsolatedAsyncioTestCase):
async def test_store_gift_link_resolves_sender(self):
sender = SimpleNamespace(id=77, tg_id=7007)
session = SimpleNamespace(execute=AsyncMock(), commit=AsyncMock(), rollback=AsyncMock())
with patch("database.gifts.resolve_user_optional", new=AsyncMock(return_value=sender)):
ok = await store_gift_link(
session=session,
gift_id="gift_1",
sender_legacy_ref=7007,
selected_months=1,
expiry_time=datetime.now(UTC),
gift_link="https://t.me/test",
tariff_id=1,
max_usages=1,
)
self.assertTrue(ok)
session.execute.assert_awaited_once()
session.commit.assert_not_awaited()
async def test_store_gift_link_raises_when_sender_missing(self):
session = SimpleNamespace(execute=AsyncMock(), commit=AsyncMock(), rollback=AsyncMock())
with patch("database.gifts.resolve_user_optional", new=AsyncMock(return_value=None)):
with self.assertRaises(ValueError):
await store_gift_link(
session=session,
gift_id="gift_2",
sender_legacy_ref=9999,
selected_months=1,
expiry_time=datetime.now(UTC),
gift_link="https://t.me/test",
)
session.execute.assert_not_awaited()
session.commit.assert_not_awaited()
async def test_redeem_gift_uses_billing_user_id_without_telegram(self):
gift_info = SimpleNamespace(
gift_id="gift_1",
sender_user_id=77,
sender_tg_id=7007,
recipient_user_id=None,
is_unlimited=False,
is_used=False,
max_usages=1,
tariff_id=5,
expiry_time=None,
selected_device_limit=2,
selected_traffic_gb=50,
selected_price_rub=990,
)
billing_user = SimpleNamespace(id=555, tg_id=None)
tariff_dict = {"id": 5, "name": "Gift tariff", "duration_days": 30, "group_code": "gifts"}
session = SimpleNamespace(execute=AsyncMock(), commit=AsyncMock(), rollback=AsyncMock())
with (
patch("services.gifts.get_gift_locked", new=AsyncMock(return_value=gift_info)),
patch("services.gifts.resolve_user_optional", new=AsyncMock(return_value=billing_user)),
patch("services.gifts.get_gift_usage", new=AsyncMock(return_value=None)),
patch("services.gifts.count_gift_usages", new=AsyncMock(return_value=0)),
patch("services.gifts.get_referral_by_referred_id", new=AsyncMock(return_value=None)),
patch("services.gifts.add_referral", new=AsyncMock()) as add_referral_mock,
patch("services.gifts.update_trial", new=AsyncMock()),
patch("services.gifts.get_tariff_by_id", new=AsyncMock(return_value=tariff_dict)),
patch("services.gifts.record_gift_usage", new=AsyncMock()),
patch("services.gifts.mark_gift_fully_redeemed", new=AsyncMock()),
patch("services.keys.create_vpn_key_headless", new=AsyncMock()) as create_key_mock,
):
result = await redeem_gift(session, "gift_1", 555)
self.assertEqual(result.gift_id, "gift_1")
self.assertEqual(result.tariff_id, 5)
self.assertEqual(result.duration_days, 30)
add_referral_mock.assert_awaited_once_with(session, 555, 77)
create_key_mock.assert_awaited_once()
self.assertEqual(create_key_mock.await_args.kwargs["tg_id"], 555)
self.assertTrue(create_key_mock.await_args.kwargs["skip_balance_charge"])