463 lines
22 KiB
Python
Executable file
463 lines
22 KiB
Python
Executable file
import uuid
|
|
from datetime import timedelta
|
|
|
|
from django.urls import reverse
|
|
from django.utils import timezone
|
|
from oauth2_provider.models import get_access_token_model, get_application_model
|
|
from rest_framework.test import APITestCase, override_settings
|
|
|
|
from apps.users.models import User
|
|
from apps.wallet.constans import TypeChoices
|
|
from apps.wallet.models import Wallet
|
|
from apps.wallet.models import Category
|
|
|
|
AccessToken = get_access_token_model()
|
|
Application = get_application_model()
|
|
|
|
|
|
class ApplicationApiFlowsTests(APITestCase):
|
|
client_id = '4INGOCMoulE0fNY1SQlTbPtsWqqxGj2DdqjADq6u'
|
|
application_uuid = uuid.UUID('b14e8b86-8f4a-44d9-b29d-badceb470053')
|
|
application_access_token = '14naVsdKCbKNOhnElPyXcrwSnqqFbm'
|
|
payer_access_token = '24naVsdKCbKNOhnElPyXcrwSnqqFbm'
|
|
payer_uuid = uuid.UUID('b14e8b86-8f4a-44d9-b29d-badceb470051')
|
|
payee_uuid = uuid.UUID('b14e8b86-8f4a-44d9-b29d-badceb470052')
|
|
wallet_category1_uuid = uuid.UUID('af7d967f-30c0-409b-9066-2549f2da5e5e')
|
|
wallet_category2_uuid = uuid.UUID('214e8b86-8f4a-44d9-b29d-badceb470051')
|
|
# application, _ = Application.objects.get_or_create(client_id=client_id, uuid=application_uuid)
|
|
|
|
scopes = [
|
|
'wallet.application.deposit:verify',
|
|
'wallet.application:get_balance',
|
|
'wallet.application.deposit:submit',
|
|
'wallet.deposit:submit',
|
|
'wallet.wallet:get_balance',
|
|
'wallet.application:get_user_balance',
|
|
|
|
'wallet.application.withdraw:submit',
|
|
'wallet.application.withdraw:verify',
|
|
]
|
|
|
|
def setUp(self):
|
|
self.application_user, _ = User.objects.get_or_create(pk=self.application_uuid)
|
|
self.payer_user, _ = User.objects.get_or_create(pk=self.payer_uuid)
|
|
self.application_wallet, _ = Wallet.objects.get_or_create(owner_uuid=self.application_uuid, owner_type=TypeChoices.APPLICATION, balance=300)
|
|
self.payee_wallet, _ = Wallet.objects.get_or_create(owner_uuid=self.payee_uuid, owner_type=TypeChoices.USER)
|
|
self.payer_wallet, _ = Wallet.objects.get_or_create(owner_uuid=self.payer_uuid, owner_type=TypeChoices.USER, balance=300)
|
|
expire_datetime = timezone.now() + timedelta(seconds=3600)
|
|
expire_datetime.isoformat()
|
|
|
|
self.application_access_token, _created = AccessToken.objects.update_or_create(
|
|
token=self.application_access_token,
|
|
defaults={
|
|
"user": self.application_user,
|
|
"client_id": self.client_id,
|
|
# "client_owner": owner,
|
|
"application_id": self.application_uuid,
|
|
"scope": ' '.join(self.scopes),
|
|
"expires": expire_datetime.isoformat(),
|
|
},
|
|
)
|
|
|
|
self.payer_access_token, _created = AccessToken.objects.update_or_create(
|
|
token=self.payer_access_token,
|
|
defaults={
|
|
"user": self.payer_user,
|
|
"client_id": self.client_id,
|
|
# "client_owner": owner,
|
|
"application_id": self.application_uuid,
|
|
"scope": ' '.join(self.scopes),
|
|
"expires": expire_datetime.isoformat(),
|
|
},
|
|
)
|
|
|
|
self.application, _created = Application.objects.get_or_create(
|
|
client_id=self.client_id,
|
|
uuid=self.application_uuid,
|
|
)
|
|
self.wallet_category1, _ = Category.objects.get_or_create(application=self.application, uuid=self.wallet_category1_uuid)
|
|
self.wallet_category2, _ = Category.objects.get_or_create(application=self.application, uuid=self.wallet_category2_uuid)
|
|
self.application_wallet1, _ = Wallet.objects.get_or_create(owner_uuid=self.application_uuid, owner_type=TypeChoices.APPLICATION, balance=300, category=self.wallet_category1)
|
|
self.application_wallet2, _ = Wallet.objects.get_or_create(owner_uuid=self.application_uuid, owner_type=TypeChoices.APPLICATION, balance=300, category=self.wallet_category2)
|
|
self.payee_wallet1, _ = Wallet.objects.get_or_create(owner_uuid=self.payee_uuid, owner_type=TypeChoices.USER, category=self.wallet_category1)
|
|
self.payee_wallet2, _ = Wallet.objects.get_or_create(owner_uuid=self.payee_uuid, owner_type=TypeChoices.USER, category=self.wallet_category2)
|
|
self.payer_wallet1, _ = Wallet.objects.get_or_create(owner_uuid=self.payer_uuid, owner_type=TypeChoices.USER, balance=300, category=self.wallet_category1)
|
|
self.payer_wallet2, _ = Wallet.objects.get_or_create(owner_uuid=self.payer_uuid, owner_type=TypeChoices.USER, balance=300, category=self.wallet_category2)
|
|
|
|
def tearDown(self):
|
|
super().tearDown()
|
|
|
|
def _create_authorization_header(self, token):
|
|
return "Bearer {0}".format(token)
|
|
|
|
def test_authentication_allow(self):
|
|
auth = self._create_authorization_header(self.application_access_token.token)
|
|
response = self.client.get(reverse('wallet:user_wallet_balance_api'), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
|
|
|
|
def test_authentication_expired_token(self):
|
|
access_token = '34naVsdKCbKNOhnElPyXcrwSnqqFbm'
|
|
expired_access_token, _created = AccessToken.objects.update_or_create(
|
|
token=access_token,
|
|
defaults={
|
|
"user": self.application_user,
|
|
"client_id": self.client_id,
|
|
# "client_owner": owner,
|
|
"application_id": self.application_uuid,
|
|
"scope": ' '.join(self.scopes),
|
|
"expires": (timezone.now() - timedelta(seconds=3600)).isoformat(),
|
|
},
|
|
)
|
|
auth = self._create_authorization_header(expired_access_token.token)
|
|
response = self.client.get(reverse('wallet:user_wallet_balance_api'), HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 401)
|
|
|
|
# def test_authentication_disallow(self):
|
|
# auth = self._create_authorization_header('fake_token')
|
|
# response = self.client.get(reverse('wallet:user_wallet_balance_api'), HTTP_AUTHORIZATION=auth)
|
|
# self.assertEqual(response.status_code, 401)
|
|
|
|
def test_deposit_flow_success(self):
|
|
auth = self._create_authorization_header(self.application_access_token.token)
|
|
|
|
# Checking wallets initials values(application balance = 300 and payee balance = zero)
|
|
response = self.client.get(reverse('wallet:application_wallet_balance_api'), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 300)
|
|
params = {
|
|
'uuid': self.payee_uuid,
|
|
}
|
|
response = self.client.get(reverse('wallet:application_user_wallet_balance_api', kwargs=params), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 0)
|
|
|
|
# Deposit process
|
|
data = {
|
|
'amount': 100,
|
|
'payee_id': self.payee_uuid,
|
|
'payee_type': TypeChoices.USER
|
|
}
|
|
response = self.client.post(reverse('wallet:application_deposit_submit_api'), data=data, HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 201)
|
|
json_response = response.json()
|
|
|
|
params = {
|
|
'uuid': json_response['uuid']
|
|
}
|
|
response = self.client.get(reverse('wallet:application_deposit_verify_api', kwargs=params), HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response.json()['state'], 5)
|
|
|
|
# Desired results
|
|
response = self.client.get(reverse('wallet:application_wallet_balance_api'), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 200)
|
|
|
|
params = {
|
|
'uuid': self.payee_uuid,
|
|
}
|
|
response = self.client.get(reverse('wallet:application_user_wallet_balance_api', kwargs=params), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 100)
|
|
|
|
def test_deposit_flow_category_success(self):
|
|
auth = self._create_authorization_header(self.application_access_token.token)
|
|
|
|
# Checking wallets initials values(application balance = 300 and payee balance = zero)
|
|
kwargs_category_uuid = {
|
|
'category_uuid': self.wallet_category1_uuid
|
|
}
|
|
response = self.client.get(reverse('wallet:application_wallet_balance_api', kwargs=kwargs_category_uuid), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 300)
|
|
kwargs_category_uuid_payee_uuid = {
|
|
'category_uuid': self.wallet_category1_uuid,
|
|
'uuid': self.payee_uuid,
|
|
}
|
|
response = self.client.get(reverse('wallet:application_user_wallet_balance_api', kwargs=kwargs_category_uuid_payee_uuid), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 0)
|
|
|
|
# Deposit process
|
|
data = {
|
|
'amount': 100,
|
|
'payee_id': self.payee_uuid,
|
|
'payee_type': TypeChoices.USER
|
|
}
|
|
response = self.client.post(reverse('wallet:application_deposit_submit_api', kwargs=kwargs_category_uuid), data=data, HTTP_AUTHORIZATION=auth)
|
|
print(response.json())
|
|
self.assertEqual(response.status_code, 201)
|
|
json_response = response.json()
|
|
|
|
kwargs_category_uuid_transaction_uuid = {
|
|
'category_uuid': self.wallet_category1_uuid,
|
|
'uuid': json_response['uuid'],
|
|
}
|
|
response = self.client.get(reverse('wallet:application_deposit_verify_api', kwargs=kwargs_category_uuid_transaction_uuid), HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response.json()['state'], 5)
|
|
|
|
# Desired results
|
|
response = self.client.get(reverse('wallet:application_wallet_balance_api', kwargs=kwargs_category_uuid), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 200)
|
|
|
|
kwargs_category_uuid_payee_uuid = {
|
|
'category_uuid': self.wallet_category2_uuid,
|
|
'uuid': self.payee_uuid,
|
|
}
|
|
|
|
response = self.client.get(reverse('wallet:application_user_wallet_balance_api', kwargs=kwargs_category_uuid_payee_uuid), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 0)
|
|
|
|
def test_deposit_flow_insufficient_balance(self):
|
|
auth = self._create_authorization_header(self.application_access_token.token)
|
|
|
|
# Checking wallets initials values(application balance = 300 and payee balance = zero)
|
|
response = self.client.get(reverse('wallet:application_wallet_balance_api'), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 300)
|
|
params = {
|
|
'uuid': self.payee_uuid,
|
|
}
|
|
response = self.client.get(reverse('wallet:application_user_wallet_balance_api', kwargs=params), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 0)
|
|
|
|
# Deposit process
|
|
data = {
|
|
'amount': 500,
|
|
'payee_id': self.payee_uuid,
|
|
'payee_type': TypeChoices.USER
|
|
}
|
|
response = self.client.post(reverse('wallet:application_deposit_submit_api'), data=data, HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 422)
|
|
|
|
@override_settings(ALLOWED_NEGATIVE_BALANCE_APPLICATIONS=['b14e8b86-8f4a-44d9-b29d-badceb470053'])
|
|
def test_deposit_flow_skip_insufficient_balance_for_allowed_negative_balance_applications(self):
|
|
auth = self._create_authorization_header(self.application_access_token.token)
|
|
|
|
# Checking wallets initials values(application balance = 300 and payee balance = zero)
|
|
response = self.client.get(reverse('wallet:application_wallet_balance_api'), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 300)
|
|
params = {
|
|
'uuid': self.payee_uuid,
|
|
}
|
|
response = self.client.get(reverse('wallet:application_user_wallet_balance_api', kwargs=params), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 0)
|
|
|
|
# Deposit process
|
|
data = {
|
|
'amount': 500,
|
|
'payee_id': self.payee_uuid,
|
|
'payee_type': TypeChoices.USER
|
|
}
|
|
response = self.client.post(reverse('wallet:application_deposit_submit_api'), data=data, HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 201)
|
|
|
|
def test_deposit_flow_zero_amount(self):
|
|
auth = self._create_authorization_header(self.application_access_token.token)
|
|
|
|
# Deposit process
|
|
data = {
|
|
'amount': 0,
|
|
'payee_id': self.payee_uuid,
|
|
'payee_type': TypeChoices.USER
|
|
}
|
|
response = self.client.post(reverse('wallet:application_deposit_submit_api'), data=data, HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 400)
|
|
|
|
def test_deposit_flow_negative_amount(self):
|
|
auth = self._create_authorization_header(self.application_access_token.token)
|
|
|
|
# Deposit process
|
|
data = {
|
|
'amount': -100,
|
|
'payee_id': self.payee_uuid,
|
|
'payee_type': TypeChoices.USER
|
|
}
|
|
response = self.client.post(reverse('wallet:application_deposit_submit_api'), data=data, HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 400)
|
|
|
|
def test_deposit_flow_prevent_double_spending(self):
|
|
auth = self._create_authorization_header(self.application_access_token.token)
|
|
|
|
# Checking wallets initials values(application balance = 300 and payee balance = zero)
|
|
response = self.client.get(reverse('wallet:application_wallet_balance_api'), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 300)
|
|
params = {
|
|
'uuid': self.payee_uuid,
|
|
}
|
|
response = self.client.get(reverse('wallet:application_user_wallet_balance_api', kwargs=params), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 0)
|
|
|
|
# Deposit process
|
|
data = {
|
|
'amount': 200,
|
|
'payee_id': self.payee_uuid,
|
|
'payee_type': TypeChoices.USER
|
|
}
|
|
response = self.client.post(reverse('wallet:application_deposit_submit_api'), data=data, HTTP_AUTHORIZATION=auth)
|
|
print(response.json())
|
|
self.assertEqual(response.status_code, 201)
|
|
|
|
response = self.client.post(reverse('wallet:application_deposit_submit_api'), data=data, HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 422)
|
|
|
|
def test_withdraw_flow_success(self):
|
|
auth = self._create_authorization_header(self.payer_access_token.token)
|
|
|
|
# Checking wallets initials values(application balance = 300 and payee balance = zero)
|
|
response = self.client.get(reverse('wallet:application_wallet_balance_api'), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 300)
|
|
params = {
|
|
'uuid': self.payer_uuid,
|
|
}
|
|
response = self.client.get(reverse('wallet:application_user_wallet_balance_api', kwargs=params), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 300)
|
|
|
|
# Deposit process
|
|
data = {
|
|
'amount': 100,
|
|
'payer_id': self.payer_uuid,
|
|
'payer_type': TypeChoices.USER
|
|
}
|
|
response = self.client.post(reverse('wallet:application_withdraw_submit_api'), data=data, HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 201)
|
|
json_response = response.json()
|
|
|
|
params = {
|
|
'uuid': json_response['uuid']
|
|
}
|
|
response = self.client.get(reverse('wallet:application_withdraw_verify_api', kwargs=params), HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response.json()['state'], 5)
|
|
|
|
# Desired results
|
|
response = self.client.get(reverse('wallet:application_wallet_balance_api'), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 400)
|
|
|
|
params = {
|
|
'uuid': self.payer_uuid,
|
|
}
|
|
response = self.client.get(reverse('wallet:application_user_wallet_balance_api', kwargs=params), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 200)
|
|
|
|
def test_withdraw_flow_category_success(self):
|
|
auth = self._create_authorization_header(self.payer_access_token.token)
|
|
|
|
# Checking wallets initials values(application balance = 300 and payee balance = zero)
|
|
kwargs_category_uuid = {
|
|
'category_uuid': self.wallet_category1_uuid
|
|
}
|
|
response = self.client.get(reverse('wallet:application_wallet_balance_api', kwargs=kwargs_category_uuid), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 300)
|
|
kwargs_category_uuid_payer_uuid = {
|
|
'category_uuid': self.wallet_category1_uuid,
|
|
'uuid': self.payer_uuid,
|
|
}
|
|
response = self.client.get(reverse('wallet:application_user_wallet_balance_api', kwargs=kwargs_category_uuid_payer_uuid), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 300)
|
|
|
|
# Deposit process
|
|
data = {
|
|
'amount': 100,
|
|
'payer_id': self.payer_uuid,
|
|
'payer_type': TypeChoices.USER
|
|
}
|
|
response = self.client.post(reverse('wallet:application_withdraw_submit_api', kwargs=kwargs_category_uuid), data=data, HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 201)
|
|
json_response = response.json()
|
|
|
|
kwargs_category_uuid_transaction_uuid = {
|
|
'category_uuid': self.wallet_category1_uuid,
|
|
'uuid': json_response['uuid'],
|
|
}
|
|
response = self.client.get(reverse('wallet:application_withdraw_verify_api', kwargs=kwargs_category_uuid_transaction_uuid), HTTP_AUTHORIZATION=auth)
|
|
print(response.json())
|
|
self.assertEqual(response.status_code, 200)
|
|
self.assertEqual(response.json()['state'], 5)
|
|
|
|
# Desired results
|
|
response = self.client.get(reverse('wallet:application_wallet_balance_api', kwargs=kwargs_category_uuid), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 400)
|
|
|
|
response = self.client.get(reverse('wallet:application_user_wallet_balance_api', kwargs=kwargs_category_uuid_payer_uuid), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 200)
|
|
|
|
kwargs_category_uuid_payer_uuid = {
|
|
'category_uuid': self.wallet_category2_uuid,
|
|
'uuid': self.payer_uuid,
|
|
}
|
|
|
|
response = self.client.get(reverse('wallet:application_user_wallet_balance_api', kwargs=kwargs_category_uuid_payer_uuid), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 300)
|
|
|
|
def test_withdraw_flow_zero_amount(self):
|
|
auth = self._create_authorization_header(self.payer_access_token.token)
|
|
|
|
# Deposit process
|
|
data = {
|
|
'amount': 0,
|
|
'payer_id': self.payer_uuid,
|
|
'payer_type': TypeChoices.USER
|
|
}
|
|
response = self.client.post(reverse('wallet:application_withdraw_submit_api'), data=data,
|
|
HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 400)
|
|
|
|
def test_withdraw_flow_negative_amount(self):
|
|
auth = self._create_authorization_header(self.payer_access_token.token)
|
|
|
|
# Deposit process
|
|
data = {
|
|
'amount': -500,
|
|
'payer_id': self.payer_uuid,
|
|
'payer_type': TypeChoices.USER
|
|
}
|
|
response = self.client.post(reverse('wallet:application_withdraw_submit_api'), data=data,
|
|
HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 400)
|
|
|
|
def test_withdraw_flow_prevent_double_spending(self):
|
|
auth = self._create_authorization_header(self.payer_access_token.token)
|
|
|
|
# Checking wallets initials values(application balance = 300 and payee balance = zero)
|
|
response = self.client.get(reverse('wallet:application_wallet_balance_api'), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 300)
|
|
params = {
|
|
'uuid': self.payer_uuid,
|
|
}
|
|
response = self.client.get(reverse('wallet:application_user_wallet_balance_api', kwargs=params), HTTP_AUTHORIZATION=auth)
|
|
self.assertContains(response, 'balance')
|
|
self.assertEqual(response.json()['balance'], 300)
|
|
|
|
# Deposit process
|
|
data = {
|
|
'amount': 200,
|
|
'payer_id': self.payer_uuid,
|
|
'payer_type': TypeChoices.USER
|
|
}
|
|
response = self.client.post(reverse('wallet:application_withdraw_submit_api'), data=data, HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 201)
|
|
|
|
response = self.client.post(reverse('wallet:application_withdraw_submit_api'), data=data, HTTP_AUTHORIZATION=auth)
|
|
self.assertEqual(response.status_code, 422)
|
|
|
|
|