Features: 1) Add test cases for DRF and GraphQL views in core, blog, payments, and vibes_auth applications; 2) Implement reusable GraphQL testing utilities in test classes; 3) Introduce test configuration scripts for Windows and Unix environments.

Fixes: 1) Correct entrypoint scripts by removing redundant `python` reference in `uv run` commands; 2) Resolve incorrect imports and adjust class renaming in vibes_auth tests; 3) Address typing errors and minor omissions in existing code.

Extra: 1) Improve formatting in settings and middleware files; 2) Update messaging test class names for clarity; 3) Cleanup unused imports and extra whitespaces, ensuring cleaner codebase.
This commit is contained in:
Egor Pavlovich Gorbunov 2025-11-13 16:42:04 +03:00
parent 3228a89d4b
commit 943aa02cd3
30 changed files with 198 additions and 42 deletions

View file

@ -0,0 +1,8 @@
from django.test import TestCase
from rest_framework.test import APIClient
class DRFBlogViewsTests(TestCase):
def setUp(self):
super().setUp()
self.client = APIClient()

View file

@ -0,0 +1,15 @@
from typing import Any
from django.test import TestCase
from django.urls import reverse
class GraphQLBlogTests(TestCase):
def graphql(self, query: str, variables: dict | None = None):
url = reverse("graphql-platform")
payload: dict[str, Any] = {"query": query}
if variables:
payload["variables"] = variables
response = self.client.post(url, data=payload, content_type="application/json")
self.assertEqual(response.status_code, 200, response.json())
return response.json()

View file

@ -0,0 +1,8 @@
from django.test import TestCase
from rest_framework.test import APIClient
class DRFCoreViewsTests(TestCase):
def setUp(self):
super().setUp()
self.client = APIClient()

View file

@ -0,0 +1,15 @@
from typing import Any
from django.test import TestCase
from django.urls import reverse
class GraphQLCoreTests(TestCase):
def graphql(self, query: str, variables: dict | None = None):
url = reverse("graphql-platform")
payload: dict[str, Any] = {"query": query}
if variables:
payload["variables"] = variables
response = self.client.post(url, data=payload, content_type="application/json")
self.assertEqual(response.status_code, 200, response.json())
return response.json()

View file

@ -0,0 +1,8 @@
from django.test import TestCase
from rest_framework.test import APIClient
class DRFPaymentsViewsTests(TestCase):
def setUp(self):
super().setUp()
self.client = APIClient()

View file

@ -0,0 +1,15 @@
from typing import Any
from django.test import TestCase
from django.urls import reverse
class GraphQLPaymentsTests(TestCase):
def graphql(self, query: str, variables: dict | None = None):
url = reverse("graphql-platform")
payload: dict[str, Any] = {"query": query}
if variables:
payload["variables"] = variables
response = self.client.post(url, data=payload, content_type="application/json")
self.assertEqual(response.status_code, 200, response.json())
return response.json()

View file

@ -13,7 +13,7 @@ from rest_framework_simplejwt.tokens import RefreshToken
from engine.vibes_auth.models import User from engine.vibes_auth.models import User
class DRFViewsTests(TestCase): class DRFAuthViewsTests(TestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
self.client = APIClient() self.client = APIClient()

View file

@ -8,7 +8,7 @@ from engine.vibes_auth.models import User
from engine.vibes_auth.messaging import auth as auth_module from engine.vibes_auth.messaging import auth as auth_module
class MessagingAuthTests(TestCase): class MessagingTests(TestCase):
def test_extract_jwt_from_subprotocols_cases(self): def test_extract_jwt_from_subprotocols_cases(self):
fn = auth_module._extract_jwt_from_subprotocols fn = auth_module._extract_jwt_from_subprotocols
self.assertIsNone(fn(None)) self.assertIsNone(fn(None))

View file

@ -1,7 +1,6 @@
import logging import logging
from typing import Any, Type from typing import Any, Type
from django.conf import settings
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django_ratelimit.decorators import ratelimit from django_ratelimit.decorators import ratelimit

View file

@ -109,7 +109,6 @@ class GrapheneLoggingErrorsDebugMiddleware:
class RateLimitMiddleware: class RateLimitMiddleware:
def __init__(self, get_response): def __init__(self, get_response):
self.get_response = get_response self.get_response = get_response

View file

@ -29,7 +29,11 @@ JAZZMIN_SETTINGS = {
"url": f"https://api.{BASE_DOMAIN}/docs/swagger", # type: ignore [index] "url": f"https://api.{BASE_DOMAIN}/docs/swagger", # type: ignore [index]
"new_window": True, "new_window": True,
}, },
{"name": _("Taskboard"), "url": "https://plane.wiseless.xyz/spaces/issues/dd33cb0ab9b04ef08a10f7eefae6d90c/?board=kanban", "new_window": True}, {
"name": _("Taskboard"),
"url": "https://plane.wiseless.xyz/spaces/issues/dd33cb0ab9b04ef08a10f7eefae6d90c/?board=kanban",
"new_window": True,
},
{"name": "GitLab", "url": "https://gitlab.com/wiseless/evibes", "new_window": True}, {"name": "GitLab", "url": "https://gitlab.com/wiseless/evibes", "new_window": True},
{"name": _("Support"), "url": "https://t.me/fureunoir", "new_window": True}, {"name": _("Support"), "url": "https://t.me/fureunoir", "new_window": True},
], ],

View file

@ -2,8 +2,6 @@ from enum import Enum
from importlib import import_module from importlib import import_module
from typing import Any from typing import Any
from django.core.exceptions import PermissionDenied
def create_object(module_name: str, class_name: str, *args: list[Any], **kwargs: dict[Any, Any]) -> Any: def create_object(module_name: str, class_name: str, *args: list[Any], **kwargs: dict[Any, Any]) -> Any:
module = import_module(module_name) module = import_module(module_name)
@ -27,7 +25,6 @@ class LogLevel(Enum):
class RatelimitedError(Exception): class RatelimitedError(Exception):
default_detail = "Rate limit exceeded. Please try again later." default_detail = "Rate limit exceeded. Please try again later."
default_code = "rate_limited" default_code = "rate_limited"
status_code = 429 status_code = 429

View file

@ -1,7 +1,7 @@
#!/usr/bin/bash #!/usr/bin/bash
set -e set -e
uv run python manage.py await_services uv run manage.py await_services
if [ "${DEBUG:-0}" = "1" ]; then if [ "${DEBUG:-0}" = "1" ]; then
uv run uvicorn --host 0.0.0.0 --port 8000 --reload --log-level debug --ws-ping-interval 20 --ws-ping-timeout 20 evibes.asgi:application uv run uvicorn --host 0.0.0.0 --port 8000 --reload --log-level debug --ws-ping-interval 20 --ws-ping-timeout 20 evibes.asgi:application

View file

@ -1,6 +1,6 @@
#!/usr/bin/bash #!/usr/bin/bash
set -e set -e
uv run python manage.py await_services uv run manage.py await_services
uv run celery -A evibes beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler uv run celery -A evibes beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler

View file

@ -1,6 +1,6 @@
#!/usr/bin/bash #!/usr/bin/bash
set -e set -e
uv run python manage.py await_services uv run manage.py await_services
uv run celery -A evibes worker --pool=prefork --concurrency=1 --queues=stock_updater --loglevel=info --max-tasks-per-child=1 uv run celery -A evibes worker --pool=prefork --concurrency=1 --queues=stock_updater --loglevel=info --max-tasks-per-child=1

View file

@ -1,6 +1,6 @@
#!/usr/bin/bash #!/usr/bin/bash
set -e set -e
uv run python manage.py await_services uv run manage.py await_services
uv run celery -A evibes worker --pool=prefork --concurrency=8 --loglevel=info -E --queues=default --prefetch-multiplier=1 --max-tasks-per-child=100 --max-memory-per-child=512000 --soft-time-limit=3600 --time-limit=7200 & /opt/evibes-python/bin/celery-prometheus-exporter uv run celery -A evibes worker --pool=prefork --concurrency=8 --loglevel=info -E --queues=default --prefetch-multiplier=1 --max-tasks-per-child=100 --max-memory-per-child=512000 --soft-time-limit=3600 --time-limit=7200 & /opt/evibes-python/bin/celery-prometheus-exporter

View file

@ -4,9 +4,9 @@ set -euo pipefail
source ./scripts/Unix/starter.sh source ./scripts/Unix/starter.sh
echo "Starting database backup process..." echo "Starting database backup process..."
docker compose exec app uv run python manage.py dbbackup docker compose exec app uv run manage.py dbbackup
echo "Database backup created under ./dbbackup" echo "Database backup created under ./dbbackup"
echo "Starting media backup process..." echo "Starting media backup process..."
docker compose exec app uv run python manage.py mediabackup docker compose exec app uv run manage.py mediabackup
echo "Media backup created under ./dbbackup" echo "Media backup created under ./dbbackup"

View file

@ -12,11 +12,11 @@ docker compose up -d --build --wait
echo "Services are up and healthy!" echo "Services are up and healthy!"
echo "Completing pre-run tasks..." echo "Completing pre-run tasks..."
docker compose exec app uv run python manage.py migrate --no-input --verbosity 0 docker compose exec app uv run manage.py migrate --no-input --verbosity 0
docker compose exec app uv run python manage.py initialize docker compose exec app uv run manage.py initialize
docker compose exec app uv run python manage.py set_default_caches docker compose exec app uv run manage.py set_default_caches
docker compose exec app uv run python manage.py search_index --rebuild -f docker compose exec app uv run manage.py search_index --rebuild -f
docker compose exec app uv run python manage.py collectstatic --clear --no-input --verbosity 0 docker compose exec app uv run manage.py collectstatic --clear --no-input --verbosity 0
echo "Pre-run tasks completed successfully!" echo "Pre-run tasks completed successfully!"
echo "Cleaning up unused Docker data..." echo "Cleaning up unused Docker data..."

View file

@ -24,11 +24,11 @@ docker compose up --no-build --detach --wait
echo "Services are up and healthy!" echo "Services are up and healthy!"
echo "Completing pre-run tasks..." echo "Completing pre-run tasks..."
docker compose exec app uv run python manage.py migrate --no-input --verbosity 0 docker compose exec app uv run manage.py migrate --no-input --verbosity 0
docker compose exec app uv run python manage.py initialize docker compose exec app uv run manage.py initialize
docker compose exec app uv run python manage.py set_default_caches docker compose exec app uv run manage.py set_default_caches
docker compose exec app uv run python manage.py search_index --rebuild -f docker compose exec app uv run manage.py search_index --rebuild -f
docker compose exec app uv run python manage.py collectstatic --clear --no-input --verbosity 0 docker compose exec app uv run manage.py collectstatic --clear --no-input --verbosity 0
echo "Pre-run tasks completed successfully!" echo "Pre-run tasks completed successfully!"
echo "Cleaning unused Docker data..." echo "Cleaning unused Docker data..."

50
scripts/Unix/test.sh Normal file
View file

@ -0,0 +1,50 @@
#!/usr/bin/env bash
set -euo pipefail
source ./scripts/Unix/starter.sh
report=""
while [ "$#" -gt 0 ]; do
case "$1" in
--report|-r)
if [ "${2-}" = "" ]; then
echo "Error: --report/-r requires an argument: xml or html" >&2
exit 1
fi
report="$2"
shift 2
;;
--report=*)
report="${1#*=}"
shift
;;
-r=*)
report="${1#*=}"
shift
;;
*)
echo "Unknown argument: $1" >&2
echo "Usage: $0 [--report|-r xml|html]" >&2
exit 1
;;
esac
done
case "${report:-}" in
"")
docker compose exec app uv run coverage erase
docker compose exec app uv run coverage run --source='.' --omit='storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*' manage.py test
docker compose exec app uv run coverage report -m
;;
xml)
docker compose exec app uv run coverage xml
;;
html)
docker compose exec app uv run coverage html
;;
*)
echo "Invalid report type: $report (expected xml or html)" >&2
exit 1
;;
esac

View file

@ -8,14 +8,14 @@ if ($LASTEXITCODE -ne 0) {
} }
Write-Host "Starting database backup process..." -ForegroundColor Magenta Write-Host "Starting database backup process..." -ForegroundColor Magenta
docker compose exec app uv run python manage.py dbbackup docker compose exec app uv run manage.py dbbackup
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }
Write-Host "Database backup created under ./dbbackup" -ForegroundColor Green Write-Host "Database backup created under ./dbbackup" -ForegroundColor Green
Write-Host "Starting media backup process..." -ForegroundColor Magenta Write-Host "Starting media backup process..." -ForegroundColor Magenta
docker compose exec app uv run python manage.py mediabackup docker compose exec app uv run manage.py mediabackup
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }

View file

@ -13,14 +13,14 @@ if (-not (Test-Path '.env'))
} }
Write-Host "Checking placeholders in PO files..." -ForegroundColor Magenta Write-Host "Checking placeholders in PO files..." -ForegroundColor Magenta
docker compose exec app uv run python manage.py check_translated -l ALL -a ALL docker compose exec app uv run manage.py check_translated -l ALL -a ALL
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }
Write-Host "PO files have no placeholder issues!" -ForegroundColor Green Write-Host "PO files have no placeholder issues!" -ForegroundColor Green
Write-Host "Compiling PO files into MO files..." -ForegroundColor Magenta Write-Host "Compiling PO files into MO files..." -ForegroundColor Magenta
docker compose exec app uv run python manage.py compilemessages -l ar_AR -l cs_CZ -l da_DK -l de_DE -l en_GB -l en_US -l es_ES -l fa_IR -l fr_FR -l he_IL -l hi_IN -l hr_HR -l id_ID -l it_IT -l ja_JP -l kk_KZ -l ko_KR -l nl_NL -l no_NO -l pl_PL -l pt_BR -l ro_RO -l ru_RU -l sv_SE -l th_TH -l tr_TR -l vi_VN -l zh_Hans docker compose exec app uv run manage.py compilemessages -l ar_AR -l cs_CZ -l da_DK -l de_DE -l en_GB -l en_US -l es_ES -l fa_IR -l fr_FR -l he_IL -l hi_IN -l hr_HR -l id_ID -l it_IT -l ja_JP -l kk_KZ -l ko_KR -l nl_NL -l no_NO -l pl_PL -l pt_BR -l ro_RO -l ru_RU -l sv_SE -l th_TH -l tr_TR -l vi_VN -l zh_Hans
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }

View file

@ -13,28 +13,28 @@ if (-not (Test-Path '.env'))
} }
Write-Host "Remove old fuzzy entries..." -ForegroundColor Magenta Write-Host "Remove old fuzzy entries..." -ForegroundColor Magenta
docker compose exec app uv run python manage.py fix_fuzzy docker compose exec app uv run manage.py fix_fuzzy
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }
Write-Host "Old fuzzy entries removed successfully!" -ForegroundColor Green Write-Host "Old fuzzy entries removed successfully!" -ForegroundColor Green
Write-Host "Updating PO files..." -ForegroundColor Magenta Write-Host "Updating PO files..." -ForegroundColor Magenta
docker compose exec app uv run python manage.py makemessages -l ar_AR -l cs_CZ -l da_DK -l de_DE -l en_GB -l en_US -l es_ES -l fa_IR -l fr_FR -l he_IL -l hi_IN -l hr_HR -l id_ID -l it_IT -l ja_JP -l kk_KZ -l ko_KR -l nl_NL -l no_NO -l pl_PL -l pt_BR -l ro_RO -l ru_RU -l sv_SE -l th_TH -l tr_TR -l vi_VN -l zh_Hans docker compose exec app uv run manage.py makemessages -l ar_AR -l cs_CZ -l da_DK -l de_DE -l en_GB -l en_US -l es_ES -l fa_IR -l fr_FR -l he_IL -l hi_IN -l hr_HR -l id_ID -l it_IT -l ja_JP -l kk_KZ -l ko_KR -l nl_NL -l no_NO -l pl_PL -l pt_BR -l ro_RO -l ru_RU -l sv_SE -l th_TH -l tr_TR -l vi_VN -l zh_Hans
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }
Write-Host "PO files updated successfully!" -ForegroundColor Green Write-Host "PO files updated successfully!" -ForegroundColor Green
Write-Host "Fixing new fuzzy entries..." -ForegroundColor Magenta Write-Host "Fixing new fuzzy entries..." -ForegroundColor Magenta
docker compose exec app uv run python manage.py fix_fuzzy docker compose exec app uv run manage.py fix_fuzzy
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }
Write-Host "New fuzzy entries fixed successfully!" -ForegroundColor Green Write-Host "New fuzzy entries fixed successfully!" -ForegroundColor Green
Write-Host "Translating with DeepL..." -ForegroundColor Magenta Write-Host "Translating with DeepL..." -ForegroundColor Magenta
docker compose exec app uv run python manage.py deepl_translate -l ALL -a ALL docker compose exec app uv run manage.py deepl_translate -l ALL -a ALL
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }

View file

@ -22,23 +22,23 @@ if ($LASTEXITCODE -ne 0) {
Write-Host "Services are up and healthy!" -ForegroundColor Green Write-Host "Services are up and healthy!" -ForegroundColor Green
Write-Host "Completing pre-run tasks..." -ForegroundColor Magenta Write-Host "Completing pre-run tasks..." -ForegroundColor Magenta
docker compose exec app uv run python manage.py migrate --no-input docker compose exec app uv run manage.py migrate --no-input
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }
docker compose exec app uv run python manage.py initialize docker compose exec app uv run manage.py initialize
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }
docker compose exec app uv run python manage.py set_default_caches docker compose exec app uv run manage.py set_default_caches
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }
docker compose exec app uv run python manage.py search_index --rebuild -f docker compose exec app uv run manage.py search_index --rebuild -f
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }
docker compose exec app uv run python manage.py collectstatic --clear --no-input docker compose exec app uv run manage.py collectstatic --clear --no-input
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }

View file

@ -38,23 +38,23 @@ if ($LASTEXITCODE -ne 0) {
Write-Host "Services are up and healthy!" -ForegroundColor Green Write-Host "Services are up and healthy!" -ForegroundColor Green
Write-Host "Completing pre-run tasks..." -ForegroundColor Magenta Write-Host "Completing pre-run tasks..." -ForegroundColor Magenta
docker compose exec app uv run python manage.py migrate --no-input docker compose exec app uv run manage.py migrate --no-input
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }
docker compose exec app uv run python manage.py initialize docker compose exec app uv run manage.py initialize
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }
docker compose exec app uv run python manage.py set_default_caches docker compose exec app uv run manage.py set_default_caches
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }
docker compose exec app uv run python manage.py search_index --rebuild -f docker compose exec app uv run manage.py search_index --rebuild -f
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }
docker compose exec app uv run python manage.py collectstatic --clear --no-input docker compose exec app uv run manage.py collectstatic --clear --no-input
if ($LASTEXITCODE -ne 0) { if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE exit $LASTEXITCODE
} }

38
scripts/Windows/test.ps1 Normal file
View file

@ -0,0 +1,38 @@
param(
[Alias('r')]
[string]$Report = ''
)
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
& .\scripts\Windows\starter.ps1
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
}
if (-not $PSBoundParameters.ContainsKey('Report') -or [string]::IsNullOrWhiteSpace($Report)) {
docker compose exec app uv run coverage erase
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
docker compose exec app uv run coverage run --source='.' --omit='storefront/*,monitoring/*,Dockerfiles/*,*/__init__.py,*/tests/*,*/migrations/*,manage.py,evibes/*' manage.py test
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
docker compose exec app uv run coverage report -m
exit $LASTEXITCODE
}
switch ($Report.ToLowerInvariant()) {
'xml' {
docker compose exec app uv run coverage xml
exit $LASTEXITCODE
}
'html' {
docker compose exec app uv run coverage html
exit $LASTEXITCODE
}
default {
Write-Error "Invalid -Report/-r value '$Report'. Expected 'xml' or 'html'."
exit 1
}
}