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

167 lines
7.2 KiB
Python

import unittest
from types import SimpleNamespace
from unittest.mock import AsyncMock, Mock, patch
from database.coupons import check_coupon_usage, create_coupon_usage, has_any_coupon_usage
from database.keys import store_key
class KeysLegacyResolutionTests(unittest.IsolatedAsyncioTestCase):
async def test_store_key_raises_when_user_missing(self):
session = SimpleNamespace(execute=AsyncMock(), add=Mock(), commit=AsyncMock(), rollback=AsyncMock())
with patch("database.keys.resolve_user_optional", new=AsyncMock(return_value=None)):
with self.assertRaises(ValueError):
await store_key(
session=session,
legacy_user_ref=9999,
client_id="client_1",
email="u@test",
expiry_time=1111111111111,
key="k",
server_id="s1",
)
session.add.assert_not_called()
session.commit.assert_not_called()
async def test_store_key_creates_with_billing_user_and_tg_mirror(self):
user = SimpleNamespace(id=55, tg_id=5050)
first_query_result = SimpleNamespace(scalar_one_or_none=lambda: None)
session = SimpleNamespace(
execute=AsyncMock(return_value=first_query_result),
add=Mock(),
commit=AsyncMock(),
rollback=AsyncMock(),
)
with (
patch("database.keys.resolve_user_optional", new=AsyncMock(return_value=user)),
patch("database.keys.invalidate_keys_list", new=AsyncMock()),
patch("database.keys.invalidate_key_details", new=AsyncMock()),
patch("database.keys.invalidate_user_snapshot", new=Mock()),
):
await store_key(
session=session,
legacy_user_ref=5050,
client_id="client_2",
email="x@test",
expiry_time=2222222222222,
key="kk",
server_id="s2",
tariff_id=3,
)
session.add.assert_called_once()
added_key = session.add.call_args.args[0]
self.assertEqual(added_key.user_id, 55)
self.assertEqual(added_key.tg_id, 5050)
self.assertEqual(added_key.client_id, "client_2")
session.commit.assert_not_called()
async def test_store_key_updates_existing_key_with_tg_mirror(self):
user = SimpleNamespace(id=88, tg_id=8080)
existing_key = SimpleNamespace(id=1, client_id="client_3")
first_query_result = SimpleNamespace(scalar_one_or_none=lambda: existing_key)
session = SimpleNamespace(
execute=AsyncMock(side_effect=[first_query_result, SimpleNamespace()]),
add=Mock(),
commit=AsyncMock(),
rollback=AsyncMock(),
)
with (
patch("database.keys.resolve_user_optional", new=AsyncMock(return_value=user)),
patch("database.keys.invalidate_keys_list", new=AsyncMock()),
patch("database.keys.invalidate_key_details", new=AsyncMock()),
patch("database.keys.invalidate_user_snapshot", new=Mock()),
):
await store_key(
session=session,
legacy_user_ref=8080,
client_id="client_3",
email="upd@test",
expiry_time=3333333333333,
key="new_key",
server_id="s3",
selected_device_limit=5,
current_device_limit=7,
)
session.add.assert_not_called()
self.assertEqual(session.execute.await_count, 2)
update_stmt = session.execute.await_args_list[1].args[0]
compiled = update_stmt.compile()
self.assertEqual(compiled.params["email"], "upd@test")
self.assertEqual(compiled.params["tg_id"], 8080)
self.assertEqual(compiled.params["selected_device_limit"], 5)
self.assertEqual(compiled.params["current_device_limit"], 7)
session.commit.assert_not_called()
class CouponsLegacyResolutionTests(unittest.IsolatedAsyncioTestCase):
async def test_create_coupon_usage_uses_resolved_user_and_tg_mirror(self):
user = SimpleNamespace(id=77, tg_id=7007)
session = SimpleNamespace(execute=AsyncMock(), commit=AsyncMock(), rollback=AsyncMock())
with patch("database.coupons.resolve_user_optional", new=AsyncMock(return_value=user)):
await create_coupon_usage(session, coupon_id=11, user_id=7007)
session.execute.assert_awaited_once()
stmt = session.execute.await_args.args[0]
compiled = stmt.compile()
self.assertEqual(compiled.params["coupon_id"], 11)
self.assertEqual(compiled.params["user_id"], 77)
self.assertEqual(compiled.params["tg_id"], 7007)
session.commit.assert_not_called()
async def test_create_coupon_usage_falls_back_to_legacy_when_user_missing(self):
session = SimpleNamespace(execute=AsyncMock(), commit=AsyncMock(), rollback=AsyncMock())
with patch("database.coupons.resolve_user_optional", new=AsyncMock(return_value=None)):
await create_coupon_usage(session, coupon_id=15, user_id=9090)
session.execute.assert_awaited_once()
stmt = session.execute.await_args.args[0]
compiled = stmt.compile()
self.assertEqual(compiled.params["coupon_id"], 15)
self.assertEqual(compiled.params["user_id"], 9090)
self.assertIsNone(compiled.params["tg_id"])
session.commit.assert_not_called()
async def test_check_coupon_usage_matches_by_billing_or_tg(self):
user = SimpleNamespace(id=41, tg_id=4141)
session = SimpleNamespace(execute=AsyncMock(return_value=SimpleNamespace(scalar_one_or_none=lambda: object())))
with patch("database.coupons.resolve_user_optional", new=AsyncMock(return_value=user)):
used = await check_coupon_usage(session, coupon_id=5, legacy_user_ref=4141)
self.assertTrue(used)
stmt = session.execute.await_args.args[0]
compiled = stmt.compile()
self.assertEqual(compiled.params["coupon_id_1"], 5)
self.assertEqual(compiled.params["user_id_1"], 41)
self.assertEqual(compiled.params["tg_id_1"], 4141)
async def test_has_any_coupon_usage_returns_false_when_no_rows(self):
user = SimpleNamespace(id=50, tg_id=5050)
session = SimpleNamespace(execute=AsyncMock(return_value=SimpleNamespace(first=lambda: None)))
with patch("database.coupons.resolve_user_optional", new=AsyncMock(return_value=user)):
has_usage = await has_any_coupon_usage(session, legacy_user_ref=5050)
self.assertFalse(has_usage)
async def test_has_any_coupon_usage_fallbacks_to_legacy_when_user_missing(self):
session = SimpleNamespace(execute=AsyncMock(return_value=SimpleNamespace(first=lambda: (1,))))
with patch("database.coupons.resolve_user_optional", new=AsyncMock(return_value=None)):
has_usage = await has_any_coupon_usage(session, legacy_user_ref=6060)
self.assertTrue(has_usage)
stmt = session.execute.await_args.args[0]
compiled = stmt.compile()
self.assertEqual(compiled.params["user_id_1"], 6060)
self.assertEqual(compiled.params["tg_id_1"], 6060)