import json from unittest.mock import patch, MagicMock from graphene_django.utils.testing import GraphQLTestCase from .models import Account import uuid class BillingGraphQLTests(GraphQLTestCase): GRAPHQL_URL = '/graphql/public/' @patch('billing_app.schemas.tigerbeetle_client') def test_create_transfer_new_accounts(self, mock_tb_client): """ Tests that a transfer is created successfully and that new accounts are created lazily in both the local DB and in TigerBeetle. """ # Configure the mock to return no errors mock_tb_client.create_accounts.return_value = [] mock_tb_client.create_transfers.return_value = [] debit_account_id = str(uuid.uuid4()) credit_account_id = str(uuid.uuid4()) amount = 100 ledger = 1 code = 200 # Ensure accounts do not exist locally self.assertEqual(Account.objects.count(), 0) response = self.query( ''' mutation createTransfer( $debitAccountId: String!, $creditAccountId: String!, $amount: Int!, $ledger: Int!, $code: Int! ) { createTransfer( debitAccountId: $debitAccountId, creditAccountId: $creditAccountId, amount: $amount, ledger: $ledger, code: $code ) { success message transferId } } ''', variables={ 'debitAccountId': debit_account_id, 'creditAccountId': credit_account_id, 'amount': amount, 'ledger': ledger, 'code': code } ) self.assertResponseNoErrors(response) content = json.loads(response.content) result = content['data']['createTransfer'] self.assertTrue(result['success']) self.assertIsNotNone(result['transferId']) self.assertEqual(result['message'], 'Transfer completed successfully.') # Verify local accounts were created self.assertEqual(Account.objects.count(), 2) self.assertTrue(Account.objects.filter(uuid=debit_account_id).exists()) self.assertTrue(Account.objects.filter(uuid=credit_account_id).exists()) # Verify TigerBeetle client was called correctly mock_tb_client.create_accounts.assert_called_once() self.assertEqual(len(mock_tb_client.create_accounts.call_args[0][0]), 2) # Called with 2 accounts mock_tb_client.create_transfers.assert_called_once() self.assertEqual(len(mock_tb_client.create_transfers.call_args[0][0]), 1) # Called with 1 transfer transfer_arg = mock_tb_client.create_transfers.call_args[0][0][0] self.assertEqual(transfer_arg.amount, amount) @patch('billing_app.schemas.tigerbeetle_client') def test_create_transfer_existing_accounts(self, mock_tb_client): """ Tests that a transfer is created successfully with existing accounts and that `create_accounts` is not called. """ mock_tb_client.create_transfers.return_value = [] debit_account_id = uuid.uuid4() credit_account_id = uuid.uuid4() # Pre-populate the local database Account.objects.create(uuid=debit_account_id) Account.objects.create(uuid=credit_account_id) self.assertEqual(Account.objects.count(), 2) response = self.query( ''' mutation createTransfer( $debitAccountId: String!, $creditAccountId: String!, $amount: Int!, $ledger: Int!, $code: Int! ) { createTransfer( debitAccountId: $debitAccountId, creditAccountId: $creditAccountId, amount: $amount, ledger: $ledger, code: $code ) { success message transferId } } ''', variables={ 'debitAccountId': str(debit_account_id), 'creditAccountId': str(credit_account_id), 'amount': 50, 'ledger': 1, 'code': 201 } ) self.assertResponseNoErrors(response) # Verify that create_accounts was NOT called mock_tb_client.create_accounts.assert_not_called() # Verify that create_transfers WAS called mock_tb_client.create_transfers.assert_called_once() def test_create_transfer_invalid_uuid(self): """ Tests that the mutation fails gracefully with an invalid UUID. """ response = self.query( ''' mutation createTransfer( $debitAccountId: String!, $creditAccountId: String!, $amount: Int!, $ledger: Int!, $code: Int! ) { createTransfer( debitAccountId: $debitAccountId, creditAccountId: $creditAccountId, amount: $amount, ledger: $ledger, code: $code ) { success message transferId } } ''', variables={ 'debitAccountId': 'not-a-uuid', 'creditAccountId': str(uuid.uuid4()), 'amount': 50, 'ledger': 1, 'code': 202 } ) self.assertResponseNoErrors(response) content = json.loads(response.content) result = content['data']['createTransfer'] self.assertFalse(result['success']) self.assertEqual(result['message'], 'Invalid account ID format. Must be a valid UUID.')