@@ -0,0 +1,94 @@ +from authentication.models import CustomUserModel, BusinessUserHost, BusinessAccount + +from core.tests import BaseAuthorizedAPITest +from payments.models import PaymentPlan + + +class MeAPITest(BaseAuthorizedAPITest): + ENDPOINT = '/api/v1/auth/me' + + @classmethod + def setup_host(cls) -> None: + cls.host_user = CustomUserModel.objects.create_user(email='test_2@test.test', password='test_2') + cls.host = BusinessUserHost.objects.create(user=cls.host_user) + cls.host_payment_plan = PaymentPlan.objects.create( + price=1000, tokens_per_plan=900, is_corporate=True, title='Test plan 2' + ) + cls.host_user.payment_plan.plan = cls.host_payment_plan + cls.host_user.payment_plan.save() + + @classmethod + def setup_test_data(cls) -> None: + cls.payment_plan, _ = PaymentPlan.objects.update_or_create( + price=0, tokens_per_plan=10, defaults={'title': 'Test plan 1'} + ) + cls.setup_host() + + def test_unauthorized_status_code(self) -> None: + response = self.client.get(self.ENDPOINT) + self.assertEqual(response.status_code, 401) + self.assertEqual(response.json(), {'detail': 'Unauthorized'}) + + def test_authorized_status_code(self) -> None: + response = self.get() + self.assertEqual(response.status_code, 200) + + def test_completeness_response(self) -> None: + response = self.get() + keys = list(response.json().keys()) + self.assertEqual( + keys, + [ + 'uid', + 'first_name', + 'last_name', + 'created_at', + 'email', + 'is_active', + 'is_superuser', + 'is_staff', + 'is_confirmed', + 'is_subscribed_to_emails', + 'show_balance', + 'profile_picture_link', + 'account_type', + 'token', + 'payment_plan', + 'referral_code', + 'is_social', + 'social_auth', + ], + ) + + def test_account_type(self) -> None: + def _check_account_type(necessary_type: str) -> None: + account_type = self.get().json()['account_type'] + self.assertEqual(account_type, necessary_type) + + _check_account_type('regular') + host = BusinessUserHost.objects.create(user=self.user) + _check_account_type('business_host') + host.delete() + business_account = BusinessAccount.objects.create(user=self.user, parent_company=self.host) + _check_account_type('business_account') + for privilege, acc_type in {'admin': 'business_admin', 'sec': 'business_security'}.items(): + business_account.account_privileges = privilege + business_account.save() + _check_account_type(acc_type) + + def test_show_balance(self) -> None: + business_account = BusinessAccount.objects.create(user=self.user, parent_company=self.host) + show_balance = self.get().json()['show_balance'] + self.assertTrue(show_balance) + business_account.show_balance = False + business_account.save() + show_balance = self.get().json()['show_balance'] + self.assertFalse(show_balance) + + def test_payment_plan(self) -> None: + payment_plan_title = self.get().json()['payment_plan']['plan']['title'] + self.assertEqual(payment_plan_title, 'Test plan 1') + BusinessAccount.objects.create(user=self.user, parent_company=self.host) + payment_plan_title = self.get().json()['payment_plan']['plan']['title'] + self.assertEqual(payment_plan_title, 'Test plan 2') + @@ -0,0 +1,102 @@ +from abc import abstractmethod +from typing import Any + +from django.test import TestCase +from ninja.testing import TestClient +from rest_framework_simplejwt.tokens import RefreshToken +from backend.urls import compatibility_api + +from authentication.models import CustomUserModel + + +class BaseAPITest(TestCase): + ENDPOINT: str + + @classmethod + @abstractmethod + def setUpTestData(cls) -> None: ... + + @abstractmethod + def test_unauthorized_status_code(self) -> None: ... + + +class BaseAuthorizedAPITest(BaseAPITest): + TEST_USER_EMAIL = 'test@test.test' + TEST_USER_PASSWORD = 'test' + + user: CustomUserModel + access_token: str + client: Any + + @classmethod + def setUpTestData(cls) -> None: + cls.setup_client() + cls.setup_user() + cls.setup_test_data() + cls.setup_authentication() + + @classmethod + def setup_client(cls) -> None: + cls.client = TestClient(compatibility_api) + + @classmethod + def setup_user(cls) -> None: + cls.user = CustomUserModel.objects.create_user( + email=cls.TEST_USER_EMAIL, password=cls.TEST_USER_PASSWORD + ) + + @classmethod + def setup_test_data(cls) -> None: + pass + + @classmethod + def setup_authentication(cls) -> None: + cls.access_token = str(RefreshToken.for_user(cls.user).access_token) + + def auth_headers(self) -> dict[str, str]: + return {'Authorization': f'Bearer {self.access_token}'} + + def get(self, endpoint: str | None = None, headers: dict[str, str] | None = None) -> Any: + endpoint = endpoint or self.ENDPOINT + headers = headers or self.auth_headers() + return self.client.get(endpoint, headers=headers) + + def post( + self, + data: dict[str, Any] | None = None, + endpoint: str | None = None, + headers: dict[str, str] | None = None, + ) -> Any: + endpoint = endpoint or self.ENDPOINT + headers = headers or self.auth_headers() + return self.client.post(endpoint, data=data, headers=headers) + + def put( + self, + data: dict[str, Any] | None = None, + endpoint: str | None = None, + headers: dict[str, str] | None = None, + ) -> Any: + endpoint = endpoint or self.ENDPOINT + headers = headers or self.auth_headers() + return self.client.put(endpoint, data=data, headers=headers) + + def patch( + self, + data: dict[str, Any] | None = None, + endpoint: str | None = None, + headers: dict[str, str] | None = None, + ) -> Any: + endpoint = endpoint or self.ENDPOINT + headers = headers or self.auth_headers() + return self.client.patch(endpoint, data=data, headers=headers) + + def delete(self, endpoint: str | None = None, headers: dict[str, str] | None = None) -> Any: + endpoint = endpoint or self.ENDPOINT + headers = headers or self.auth_headers() + return self.client.delete(endpoint, headers=headers) + + @abstractmethod + def test_authorized_status_code(self) -> None: ... + + @@ -0,0 +1,219 @@ +from decimal import Decimal + +from django.utils.translation import gettext as _ + +from authentication.models import BusinessUserHost, BusinessAccount + +from core.tests import BaseAuthorizedAPITest +from ml_model.models import ModelCategory, NeuronModel +from payments.models import PaymentPlan, PaymentPlanFeature + + +class PlansAPITest(BaseAuthorizedAPITest): + ENDPOINT = '/api/v1/payments/plans' + + @classmethod + def setup_test_data(cls) -> None: + cls.free_plan, created = PaymentPlan.objects.update_or_create( + tokens_per_plan=10, defaults={'title': 'Zero Price Plan'} + ) + + cls.category_chat_bots = ModelCategory.objects.create( + slug='chat-bots', + title=_('Chat-bots'), + ) + cls.category_images = ModelCategory.objects.create( + slug='images', + title=_('Images'), + ) + cls.category_videos = ModelCategory.objects.create( + slug='videos', + title=_('Video'), + ) + cls.category_audio = ModelCategory.objects.create( + slug='audio', + title=_('Audio'), + ) + + cls.model1 = NeuronModel.objects.create(title='Model 1', slug='model-1', category=cls.category_chat_bots) + cls.model2 = NeuronModel.objects.create(title='Model 2', slug='model-2', category=cls.category_chat_bots) + cls.model3 = NeuronModel.objects.create(title='Model 3', slug='model-3', category=cls.category_images) + + cls.regular_plan1 = PaymentPlan.objects.create( + title='Regular Plan 1', + price=1000, + tokens_per_plan=100, + is_corporate=False, + is_visible=True, + ) + + cls.regular_plan2 = PaymentPlan.objects.create( + title='Regular Plan 2', + price=2000, + tokens_per_plan=200, + is_corporate=False, + is_visible=True, + ) + + PaymentPlanFeature.objects.create( + plan=cls.regular_plan1, + model=cls.model1, + quantity=10, + measurement_unit='text_page', + ) + PaymentPlanFeature.objects.create( + plan=cls.regular_plan1, + model=cls.model2, + quantity=20, + measurement_unit='file', + ) + PaymentPlanFeature.objects.create( + plan=cls.regular_plan1, + model=cls.model3, + quantity=30, + measurement_unit='time', + ) + + cls.corporate_plan1 = PaymentPlan.objects.create( + title='Corporate Plan 1', + price=10000, + tokens_per_plan=1000, + is_corporate=True, + is_visible=True, + ) + cls.corporate_plan2 = PaymentPlan.objects.create( + title='Corporate Plan 2', + price=20000, + tokens_per_plan=2000, + is_corporate=True, + is_visible=True, + ) + + PaymentPlan.objects.create( + title='Hidden Plan', price=500, tokens_per_plan=50, is_corporate=False, is_visible=False + ) + + def test_unauthorized_status_code(self) -> None: + response = self.client.get(self.ENDPOINT) + self.assertEqual(response.status_code, 401) + self.assertEqual(response.json(), {'detail': 'Unauthorized'}) + + def test_unauthorized_by_permission(self) -> None: + from authentication.models import CustomUserModel + host_user = CustomUserModel.objects.create_user(email='test_2@test.test', password='test_2') + host = BusinessUserHost.objects.create(user=host_user) + BusinessAccount.objects.create(user=self.user, parent_company=host) + response = self.client.get(self.ENDPOINT) + self.assertEqual(response.status_code, 401) + self.assertEqual(response.json(), {'detail': 'Unauthorized'}) + + def test_authorized_status_code(self) -> None: + response = self.get() + self.assertEqual(response.status_code, 200) + + def test_completeness_response(self) -> None: + plans = self.get().json() + self.assertGreater(len(plans), 0) + plan = plans[0] + keys = list(plan.keys()) + self.assertEqual( + keys, + [ + 'uid', + 'title', + 'price', + 'tokens_per_plan', + 'duration', + 'points', + 'grouped_features', + 'accessed_models', + ], + ) + + def test_regular_plans(self) -> None: + plans = self.get().json() + plan_titles = [plan['title'] for plan in plans] + self.assertSetEqual({'Regular Plan 2', 'Regular Plan 1'}, set(plan_titles)) + + def test_hidden_plans(self) -> None: + plans = self.get().json() + plan_titles = [plan['title'] for plan in plans] + self.assertNotIn('Hidden Plan', plan_titles) + + def test_zero_price_plans(self) -> None: + plans = self.get().json() + plan_titles = [plan['title'] for plan in plans] + self.assertNotIn('Zero Price Plan', plan_titles) + + def test_corporate_plans(self) -> None: + BusinessUserHost.objects.create(user=self.user) + plans = self.get().json() + plan_titles = [plan['title'] for plan in plans] + self.assertSetEqual({'Corporate Plan 1', 'Corporate Plan 2'}, set(plan_titles)) + + def test_grouped_features_structure(self) -> None: + plans = self.get().json() + plan_with_features = [plan for plan in plans if plan['grouped_features']][0] + + grouped_features = plan_with_features['grouped_features'] + self.assertIsInstance(grouped_features, list) + self.assertGreater(len(grouped_features), 0) + + for group in grouped_features: + self.assertIn('name', group) + self.assertIn('features', group) + self.assertIsInstance(group['name'], str) + self.assertIsInstance(group['features'], list) + + for feature in group['features']: + self.assertIn('name', feature) + self.assertIn('quantity', feature) + self.assertIn('measurement_unit', feature) + self.assertIsInstance(feature['name'], str) + self.assertIsInstance(feature['quantity'], int) + self.assertIsInstance(feature['measurement_unit'], str) + + def test_features_grouped_by_category(self) -> None: + plans = self.get().json() + plan_with_features = [plan for plan in plans if plan['grouped_features']][0] + + grouped_features = plan_with_features['grouped_features'] + category_names = [group['name'] for group in grouped_features] + self.assertIn(_('Chat-bots'), category_names) + self.assertIn(_('Images'), category_names) + + category1_group = [g for g in grouped_features if g['name'] == _('Chat-bots')][0] + self.assertEqual(len(category1_group['features']), 2) + + category2_group = [g for g in grouped_features if g['name'] == _('Images')][0] + self.assertEqual(len(category2_group['features']), 1) + + def test_feature_values(self) -> None: + plans = self.get().json() + plan_with_features = [plan for plan in plans if plan['grouped_features']][0] + self.assertIsNotNone(plan_with_features) + + all_features = [] + for group in plan_with_features['grouped_features']: + all_features.extend(group['features']) + + feature_names = {f['name'] for f in all_features} + self.assertSetEqual({'Model 1', 'Model 2', 'Model 3'}, feature_names) + + feature1 = [f for f in all_features if f['name'] == 'Model 1'][0] + self.assertEqual(feature1['quantity'], 10) + self.assertEqual(feature1['measurement_unit'], 'text_page') + + def test_accessed_models(self) -> None: + plans = self.get().json() + plan_with_models = [p for p in plans if p['title'] == 'Regular Plan 1'][0] + self.assertIsNotNone(plan_with_models) + + accessed_models = plan_with_models['accessed_models'] + self.assertIsInstance(accessed_models, list) + self.assertEqual(len(accessed_models), 0) + + def test_tokens_per_plan(self) -> None: + plans = self.get().json() + for plan in plans: + self.assertGreater(Decimal(str(plan['tokens_per_plan'])), 0) \ No newline at end of file @@ -0,0 +1,66 @@ +from decimal import Decimal + +from authentication.models import CustomUserModel, BusinessUserHost, BusinessAccount, BusinessGroup + +from core.tests import BaseAuthorizedAPITest +from payments.models import PaymentPlan + + +class BalanceAPITest(BaseAuthorizedAPITest): + ENDPOINT = '/api/v1/payments/user-balance' + + @classmethod + def setup_host(cls) -> None: + cls.host_user = CustomUserModel.objects.create_user(email='test_2@test.test', password='test_2') + cls.host = BusinessUserHost.objects.create(user=cls.host_user) + cls.host_payment_plan = PaymentPlan.objects.create( + price=1000, tokens_per_plan=900, is_corporate=True, title='Test plan 2' + ) + cls.host_user.payment_plan.plan = cls.host_payment_plan + cls.host_user.payment_plan.save() + + @classmethod + def setup_test_data(cls) -> None: + PaymentPlan.objects.update_or_create(price=0, tokens_per_plan=10, defaults={'title': 'Test plan 1'}) + cls.setup_host() + + def test_unauthorized_status_code(self) -> None: + response = self.client.get(self.ENDPOINT) + self.assertEqual(response.status_code, 401) + self.assertEqual(response.json(), {'detail': 'Unauthorized'}) + + def test_authorized_status_code(self) -> None: + response = self.get() + self.assertEqual(response.status_code, 200) + + def test_completeness_response(self) -> None: + response = self.get() + keys = list(response.json().keys()) + self.assertEqual(keys, ['current_token_balance']) + + def test_correct_balance(self) -> None: + balance = self.get().json()['current_token_balance'] + self.assertEqual(Decimal(balance), Decimal('10.00')) + self.user.payment_plan.current_token_balance -= 2 + self.user.payment_plan.save() + balance = self.get().json()['current_token_balance'] + self.assertEqual(Decimal(balance), Decimal('8.00')) + + def test_displaying_balance(self) -> None: + balance = self.get().json()['current_token_balance'] + self.assertEqual(Decimal(balance), Decimal('10.00')) + business_account = BusinessAccount.objects.create( + user=self.user, parent_company=self.host, acceptance_status='accepted', token_limit=Decimal('50') + ) + balance = self.get().json()['current_token_balance'] + self.assertEqual(Decimal(balance), business_account.token_limit) + business_account.token_limit = None + business_account.save() + balance = self.get().json()['current_token_balance'] + self.assertEqual(Decimal(balance), self.host_user.balance) + business_account.group = BusinessGroup.objects.create( + title='Test group 1', token_limit=100, parent_company=self.host + ) + business_account.save() + balance = self.get().json()['current_token_balance'] + self.assertEqual(Decimal(balance), business_account.group.token_limit) \ No newline at end of file @@ -0,0 +1,24 @@ +from rest_framework.test import APIClient + +from core.tests import BaseAuthorizedAPITest + + +class SupportAPITest(BaseAuthorizedAPITest): + ENDPOINT = '/api/v1/reports/' + + @classmethod + def setup_client(cls) -> None: + cls.client = APIClient() + + def test_unauthorized_status_code(self) -> None: + response = self.client.post(self.ENDPOINT, data={'report_text': 'test', 'images': []}) + self.assertEqual(response.status_code, 401) + self.assertEqual(response.json(), {'detail': 'Учетные данные не были предоставлены.'}) + + def test_authorized_status_code(self) -> None: + response = self.post(data={'report_text': 'test', 'images': []}) + self.assertEqual(response.status_code, 201) + + def test_completeness_response(self) -> None: + response = self.post(data={'report_text': 'test', 'images': []}) + self.assertEqual(response.json(), {'detail': 'error report sent'}) @@ -0,0 +1,46 @@ +from datetime import date + +from rest_framework.test import APIClient + +from core.tests import BaseAuthorizedAPITest +from tools.public_api.models import APIKey + + +class APIKeyAPITest(BaseAuthorizedAPITest): + ENDPOINT = '/api/v1/public/api-key' + + @classmethod + def setup_client(cls) -> None: + cls.client = APIClient() + + def test_unauthorized_status_code(self) -> None: + response = self.client.get(self.ENDPOINT) + self.assertEqual(response.status_code, 401) + self.assertEqual(response.json(), {'detail': 'Учетные данные не были предоставлены.'}) + + def test_authorized_status_code_on_create(self) -> None: + response = self.post(data={'name': 'Test key'}) + self.assertEqual(response.status_code, 201) + + def test_create_response_structure(self) -> None: + response = self.post(data={'name': 'Test key'}) + keys = list(response.json().keys()) + self.assertEqual(keys, ['created_at', 'name', 'key', 'expires_at', 'user', 'token_limit']) + + def test_list_keys_structure(self) -> None: + APIKey.objects.create(user=self.user, name='Key 1') + APIKey.objects.create(user=self.user, name='Key 2') + + response = self.get() + self.assertEqual(response.status_code, 200) + + data = response.json() + keys = list(data[0].keys()) + self.assertEqual(keys, ['created_at', 'name', 'key', 'expires_at', 'user', 'token_limit']) + + def test_create_with_expires_at_and_verify_in_db(self) -> None: + expires = date(2030, 1, 1) + self.post(data={'name': 'Key with TTL', 'expires_at': expires.isoformat()}) + api_key = APIKey.objects.get(user=self.user, name='Key with TTL', is_deleted=False) + self.assertEqual(api_key.name, 'Key with TTL') + self.assertEqual(api_key.expires_at, expires) @@ -1,3 +0,0 @@ -# from django.test import TestCase # Flake8 angery >:( - -# Create your tests here.