Arag / tests /unit /test_billing_service.py
AuthorBot
Add enterprise growth APIs, billing, admin UI, and test suite.
12930b5
Raw
History Blame Contribute Delete
2.89 kB
"""Unit tests: BillingService — activation, payment events, plan changes."""
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from datetime import datetime, timezone
@pytest.mark.asyncio
async def test_activate_unpaid_session_raises(db_session):
from app.services.billing_service import BillingService
svc = BillingService(db_session)
mock_session = MagicMock()
mock_session.payment_status = "unpaid"
with patch("app.services.billing_service.get_checkout_session",
new_callable=AsyncMock, return_value=mock_session):
with pytest.raises(ValueError, match="Payment not completed"):
await svc.activate_from_session("cs_fake", "hash123")
@pytest.mark.asyncio
async def test_payment_succeeded_resets_tokens(db_session, test_author):
from app.services.billing_service import BillingService
from app.models.client_access import ClientAccess
from sqlalchemy import select
# Set tokens_used to non-zero
result = await db_session.execute(
select(ClientAccess).where(ClientAccess.author_id == test_author.id)
)
access = result.scalar_one_or_none()
if access:
access.tokens_used = 250_000
access.stripe_subscription_id = "sub_test_reset"
await db_session.commit()
svc = BillingService(db_session)
await svc.handle_payment_succeeded("sub_test_reset")
await db_session.refresh(access)
assert access.tokens_used == 0
@pytest.mark.asyncio
async def test_payment_failed_sets_grace_period(db_session, test_author):
from app.services.billing_service import BillingService
from app.models.user import User
from sqlalchemy import select
test_author.stripe_subscription_id = "sub_grace_test"
await db_session.commit()
svc = BillingService(db_session)
await svc.handle_payment_failed("sub_grace_test", grace_days=7)
result = await db_session.execute(
select(User).where(User.id == test_author.id)
)
user = result.scalar_one_or_none()
if user:
assert user.payment_grace_until is not None
assert user.payment_grace_until > datetime.now(timezone.utc)
@pytest.mark.asyncio
async def test_subscription_cancelled_revokes_access(db_session, test_author):
from app.services.billing_service import BillingService
from app.models.client_access import ClientAccess
from sqlalchemy import select
result = await db_session.execute(
select(ClientAccess).where(ClientAccess.author_id == test_author.id)
)
access = result.scalar_one_or_none()
if access:
access.stripe_subscription_id = "sub_cancel_test"
await db_session.commit()
svc = BillingService(db_session)
await svc.handle_subscription_cancelled("sub_cancel_test")
await db_session.refresh(access)
assert access.is_revoked is True