from django.test import TestCase from labs.billing.exam import redeem_exam_with_credits from labs.billing.exceptions import InsufficientCreditsError from labs.billing.user import INITIAL_FREE_CREDITS_AMOUNT from labs.models import ( User, Exam, UserExamRedemption, CreditTransaction, ) class TestBillingExam(TestCase): def setUp(self): self.user = User.objects.create_user(email="test@test.com") def test_redeem_exam_with_credits_success(self): exam = Exam.objects.create(code="exam_001", credits=1) redemption = redeem_exam_with_credits(user=self.user, exam=exam) self.assertEqual(redemption.user_id, self.user.id) self.assertEqual(redemption.exam_id, exam.id) self.assertIsNone(redemption.exam_attempt_id) self.assertEqual(redemption.redeem_type, UserExamRedemption.RedeemType.CREDITS) self.assertEqual(redemption.redeem_detail, {"credits": 1}) self.user.credit_summary.refresh_from_db() self.assertEqual( self.user.credit_summary.free_credits, INITIAL_FREE_CREDITS_AMOUNT - 1, ) self.assertEqual(self.user.credit_summary.paid_credits, 0) txn = CreditTransaction.objects.get( user=self.user, transaction_type=CreditTransaction.TransactionType.REDEEM_EXAM, ) self.assertEqual(txn.paid_credits, 0) self.assertEqual(txn.free_credits, -1) self.assertIsNone(txn.redemption_id) self.assertEqual(txn.exam_redemption_id, redemption.id) def test_redeem_exam_with_credits_insufficient_credits(self): exam = Exam.objects.create(code="exam_001", credits=INITIAL_FREE_CREDITS_AMOUNT + 1) with self.assertRaises(InsufficientCreditsError): redeem_exam_with_credits(user=self.user, exam=exam) self.user.credit_summary.refresh_from_db() self.assertEqual(self.user.credit_summary.free_credits, INITIAL_FREE_CREDITS_AMOUNT) self.assertEqual(self.user.credit_summary.paid_credits, 0) self.assertEqual(UserExamRedemption.objects.filter(user=self.user).count(), 0) self.assertEqual( CreditTransaction.objects.filter( user=self.user, transaction_type=CreditTransaction.TransactionType.REDEEM_EXAM, ).count(), 0, ) def test_redeem_exam_with_credits_idempotent(self): exam = Exam.objects.create(code="exam_001", credits=1) redemption_1 = redeem_exam_with_credits(user=self.user, exam=exam) redemption_2 = redeem_exam_with_credits(user=self.user, exam=exam) self.assertEqual(redemption_1.id, redemption_2.id) self.assertEqual( UserExamRedemption.objects.filter( user=self.user, exam=exam, exam_attempt__isnull=True ).count(), 1, ) self.assertEqual( CreditTransaction.objects.filter( user=self.user, transaction_type=CreditTransaction.TransactionType.REDEEM_EXAM, ).count(), 1, ) self.user.credit_summary.refresh_from_db() self.assertEqual( self.user.credit_summary.free_credits, INITIAL_FREE_CREDITS_AMOUNT - 1, ) self.assertEqual(self.user.credit_summary.paid_credits, 0)