chore: enhance API test coverage reporting and update dependencies

This commit is contained in:
swve 2025-07-27 20:12:23 +02:00
parent 7b220e8883
commit fa3a3be151
9 changed files with 48 additions and 46 deletions

View file

@ -42,6 +42,13 @@ jobs:
- name: Run security tests with coverage - name: Run security tests with coverage
run: | run: |
cd apps/api cd apps/api
uv run pytest src/tests/security/ --cov=src.security --cov-report=xml --cov-report=term-missing uv run pytest src/tests/security/ --cov=src.security --cov-report=html --cov-report=term-missing
env: env:
TESTING: "true" TESTING: "true"
- name: Upload coverage report to GitHub
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: apps/api/htmlcov/
retention-days: 30

View file

@ -21,6 +21,7 @@ dependencies = [
"psycopg2-binary>=2.9.9", "psycopg2-binary>=2.9.9",
"pydantic[email]>=1.8.0,<2.0.0", "pydantic[email]>=1.8.0,<2.0.0",
"pytest>=8.2.2", "pytest>=8.2.2",
"pytest-cov>=4.1.0",
"python-dotenv>=1.0.0", "python-dotenv>=1.0.0",
"python-multipart>=0.0.9", "python-multipart>=0.0.9",
"pyyaml>=6.0.1", "pyyaml>=6.0.1",

View file

@ -11,7 +11,6 @@ from src.security.auth import (
Token, Token,
TokenData, TokenData,
Settings, Settings,
get_config,
) )
from src.db.users import User, AnonymousUser, PublicUser from src.db.users import User, AnonymousUser, PublicUser
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone

View file

@ -1,12 +1,11 @@
import pytest import pytest
from unittest.mock import Mock, patch, MagicMock from unittest.mock import Mock, patch
from fastapi import HTTPException from fastapi import HTTPException
from sqlmodel import Session, select from sqlmodel import Session
from src.security.features_utils.usage import ( from src.security.features_utils.usage import (
check_limits_with_usage, check_limits_with_usage,
increase_feature_usage, increase_feature_usage,
decrease_feature_usage, decrease_feature_usage,
FeatureSet,
) )
from src.db.organization_config import OrganizationConfig from src.db.organization_config import OrganizationConfig

View file

@ -1,7 +1,7 @@
import pytest import pytest
from unittest.mock import Mock, AsyncMock, patch from unittest.mock import Mock, AsyncMock, patch
from fastapi import HTTPException, Request from fastapi import HTTPException, Request
from sqlmodel import Session, select from sqlmodel import Session
from src.security.rbac.rbac import ( from src.security.rbac.rbac import (
authorization_verify_if_element_is_public, authorization_verify_if_element_is_public,
authorization_verify_if_user_is_author, authorization_verify_if_user_is_author,
@ -14,7 +14,6 @@ from src.db.courses.courses import Course
from src.db.collections import Collection from src.db.collections import Collection
from src.db.resource_authors import ResourceAuthor, ResourceAuthorshipEnum, ResourceAuthorshipStatusEnum from src.db.resource_authors import ResourceAuthor, ResourceAuthorshipEnum, ResourceAuthorshipStatusEnum
from src.db.roles import Role from src.db.roles import Role
from src.db.user_organizations import UserOrganization
class TestRBAC: class TestRBAC:

View file

@ -1,5 +1,4 @@
import pytest import pytest
from unittest.mock import AsyncMock, patch
from fastapi import HTTPException from fastapi import HTTPException
from src.security.rbac.utils import ( from src.security.rbac.utils import (
check_element_type, check_element_type,

View file

@ -1,4 +1,3 @@
import pytest
from src.security.security import ( from src.security.security import (
security_hash_password, security_hash_password,
security_verify_password, security_verify_password,

View file

@ -10,7 +10,6 @@ of the security functionality including:
- Authorization utilities - Authorization utilities
""" """
import pytest
from src.tests.security.test_security import TestSecurity from src.tests.security.test_security import TestSecurity
from src.tests.security.test_auth import TestAuth from src.tests.security.test_auth import TestAuth
from src.tests.security.test_rbac import TestRBAC from src.tests.security.test_rbac import TestRBAC
@ -24,49 +23,14 @@ class TestSecurityComprehensive:
def test_security_module_imports(self): def test_security_module_imports(self):
"""Test that all security modules can be imported successfully""" """Test that all security modules can be imported successfully"""
# Test core security imports # Test core security imports
from src.security.security import (
security_hash_password,
security_verify_password,
ACCESS_TOKEN_EXPIRE_MINUTES,
SECRET_KEY,
ALGORITHM,
)
# Test auth imports # Test auth imports
from src.security.auth import (
authenticate_user,
create_access_token,
get_current_user,
non_public_endpoint,
Token,
TokenData,
Settings,
)
# Test RBAC imports # Test RBAC imports
from src.security.rbac.rbac import (
authorization_verify_if_element_is_public,
authorization_verify_if_user_is_author,
authorization_verify_based_on_roles,
authorization_verify_based_on_org_admin_status,
authorization_verify_based_on_roles_and_authorship,
authorization_verify_if_user_is_anon,
)
# Test RBAC utils imports # Test RBAC utils imports
from src.security.rbac.utils import (
check_element_type,
get_singular_form_of_element,
get_id_identifier_of_element,
)
# Test features utils imports # Test features utils imports
from src.security.features_utils.usage import (
check_limits_with_usage,
increase_feature_usage,
decrease_feature_usage,
FeatureSet,
)
# Verify all imports succeeded # Verify all imports succeeded
assert True assert True
@ -83,7 +47,6 @@ class TestSecurityComprehensive:
def test_feature_set_definition(self): def test_feature_set_definition(self):
"""Test that FeatureSet includes all expected features""" """Test that FeatureSet includes all expected features"""
from src.security.features_utils.usage import FeatureSet
expected_features = [ expected_features = [
"ai", "analytics", "api", "assignments", "collaboration", "ai", "analytics", "api", "assignments", "collaboration",

36
apps/api/uv.lock generated
View file

@ -339,6 +339,26 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/a7/06/3d6badcf13db419e25b07041d9c7b4a2c331d3f4e7134445ec5df57714cd/coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934", size = 46018 }, { url = "https://files.pythonhosted.org/packages/a7/06/3d6badcf13db419e25b07041d9c7b4a2c331d3f4e7134445ec5df57714cd/coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934", size = 46018 },
] ]
[[package]]
name = "coverage"
version = "7.10.1"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/87/0e/66dbd4c6a7f0758a8d18044c048779ba21fb94856e1edcf764bd5403e710/coverage-7.10.1.tar.gz", hash = "sha256:ae2b4856f29ddfe827106794f3589949a57da6f0d38ab01e24ec35107979ba57", size = 819938 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/a5/3f/b051feeb292400bd22d071fdf933b3ad389a8cef5c80c7866ed0c7414b9e/coverage-7.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6b7dc7f0a75a7eaa4584e5843c873c561b12602439d2351ee28c7478186c4da4", size = 214934 },
{ url = "https://files.pythonhosted.org/packages/f8/e4/a61b27d5c4c2d185bdfb0bfe9d15ab4ac4f0073032665544507429ae60eb/coverage-7.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:607f82389f0ecafc565813aa201a5cade04f897603750028dd660fb01797265e", size = 215173 },
{ url = "https://files.pythonhosted.org/packages/8a/01/40a6ee05b60d02d0bc53742ad4966e39dccd450aafb48c535a64390a3552/coverage-7.10.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f7da31a1ba31f1c1d4d5044b7c5813878adae1f3af8f4052d679cc493c7328f4", size = 246190 },
{ url = "https://files.pythonhosted.org/packages/11/ef/a28d64d702eb583c377255047281305dc5a5cfbfb0ee36e721f78255adb6/coverage-7.10.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:51fe93f3fe4f5d8483d51072fddc65e717a175490804e1942c975a68e04bf97a", size = 248618 },
{ url = "https://files.pythonhosted.org/packages/6a/ad/73d018bb0c8317725370c79d69b5c6e0257df84a3b9b781bda27a438a3be/coverage-7.10.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3e59d00830da411a1feef6ac828b90bbf74c9b6a8e87b8ca37964925bba76dbe", size = 250081 },
{ url = "https://files.pythonhosted.org/packages/2d/dd/496adfbbb4503ebca5d5b2de8bed5ec00c0a76558ffc5b834fd404166bc9/coverage-7.10.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:924563481c27941229cb4e16eefacc35da28563e80791b3ddc5597b062a5c386", size = 247990 },
{ url = "https://files.pythonhosted.org/packages/18/3c/a9331a7982facfac0d98a4a87b36ae666fe4257d0f00961a3a9ef73e015d/coverage-7.10.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ca79146ee421b259f8131f153102220b84d1a5e6fb9c8aed13b3badfd1796de6", size = 246191 },
{ url = "https://files.pythonhosted.org/packages/62/0c/75345895013b83f7afe92ec595e15a9a525ede17491677ceebb2ba5c3d85/coverage-7.10.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2b225a06d227f23f386fdc0eab471506d9e644be699424814acc7d114595495f", size = 247400 },
{ url = "https://files.pythonhosted.org/packages/e2/a9/98b268cfc5619ef9df1d5d34fee408ecb1542d9fd43d467e5c2f28668cd4/coverage-7.10.1-cp312-cp312-win32.whl", hash = "sha256:5ba9a8770effec5baaaab1567be916c87d8eea0c9ad11253722d86874d885eca", size = 217338 },
{ url = "https://files.pythonhosted.org/packages/fe/31/22a5440e4d1451f253c5cd69fdcead65e92ef08cd4ec237b8756dc0b20a7/coverage-7.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:9eb245a8d8dd0ad73b4062135a251ec55086fbc2c42e0eb9725a9b553fba18a3", size = 218125 },
{ url = "https://files.pythonhosted.org/packages/d6/2b/40d9f0ce7ee839f08a43c5bfc9d05cec28aaa7c9785837247f96cbe490b9/coverage-7.10.1-cp312-cp312-win_arm64.whl", hash = "sha256:7718060dd4434cc719803a5e526838a5d66e4efa5dc46d2b25c21965a9c6fcc4", size = 216523 },
{ url = "https://files.pythonhosted.org/packages/0f/64/922899cff2c0fd3496be83fa8b81230f5a8d82a2ad30f98370b133c2c83b/coverage-7.10.1-py3-none-any.whl", hash = "sha256:fa2a258aa6bf188eb9a8948f7102a83da7c430a0dce918dbd8b60ef8fcb772d7", size = 206597 },
]
[[package]] [[package]]
name = "dataclasses-json" name = "dataclasses-json"
version = "0.6.7" version = "0.6.7"
@ -1033,6 +1053,7 @@ dependencies = [
{ name = "pydantic", extra = ["email"] }, { name = "pydantic", extra = ["email"] },
{ name = "pytest" }, { name = "pytest" },
{ name = "pytest-asyncio" }, { name = "pytest-asyncio" },
{ name = "pytest-cov" },
{ name = "python-dotenv" }, { name = "python-dotenv" },
{ name = "python-jose" }, { name = "python-jose" },
{ name = "python-multipart" }, { name = "python-multipart" },
@ -1070,6 +1091,7 @@ requires-dist = [
{ name = "pydantic", extras = ["email"], specifier = ">=1.8.0,<2.0.0" }, { name = "pydantic", extras = ["email"], specifier = ">=1.8.0,<2.0.0" },
{ name = "pytest", specifier = ">=8.2.2" }, { name = "pytest", specifier = ">=8.2.2" },
{ name = "pytest-asyncio", specifier = ">=1.1.0" }, { name = "pytest-asyncio", specifier = ">=1.1.0" },
{ name = "pytest-cov", specifier = ">=4.1.0" },
{ name = "python-dotenv", specifier = ">=1.0.0" }, { name = "python-dotenv", specifier = ">=1.0.0" },
{ name = "python-jose", specifier = ">=3.3.0" }, { name = "python-jose", specifier = ">=3.3.0" },
{ name = "python-multipart", specifier = ">=0.0.9" }, { name = "python-multipart", specifier = ">=0.0.9" },
@ -1728,6 +1750,20 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/c7/9d/bf86eddabf8c6c9cb1ea9a869d6873b46f105a5d292d3a6f7071f5b07935/pytest_asyncio-1.1.0-py3-none-any.whl", hash = "sha256:5fe2d69607b0bd75c656d1211f969cadba035030156745ee09e7d71740e58ecf", size = 15157 }, { url = "https://files.pythonhosted.org/packages/c7/9d/bf86eddabf8c6c9cb1ea9a869d6873b46f105a5d292d3a6f7071f5b07935/pytest_asyncio-1.1.0-py3-none-any.whl", hash = "sha256:5fe2d69607b0bd75c656d1211f969cadba035030156745ee09e7d71740e58ecf", size = 15157 },
] ]
[[package]]
name = "pytest-cov"
version = "6.2.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "coverage" },
{ name = "pluggy" },
{ name = "pytest" },
]
sdist = { url = "https://files.pythonhosted.org/packages/18/99/668cade231f434aaa59bbfbf49469068d2ddd945000621d3d165d2e7dd7b/pytest_cov-6.2.1.tar.gz", hash = "sha256:25cc6cc0a5358204b8108ecedc51a9b57b34cc6b8c967cc2c01a4e00d8a67da2", size = 69432 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/bc/16/4ea354101abb1287856baa4af2732be351c7bee728065aed451b678153fd/pytest_cov-6.2.1-py3-none-any.whl", hash = "sha256:f5bc4c23f42f1cdd23c70b1dab1bbaef4fc505ba950d53e0081d0730dd7e86d5", size = 24644 },
]
[[package]] [[package]]
name = "python-dateutil" name = "python-dateutil"
version = "2.9.0.post0" version = "2.9.0.post0"