Skip to content

test: improve app/core module test coverage to 100%

Merge Request

Overview

Improve unit test coverage for app/core/ modules (auth.py, database_triggers.py, logger.py, rbac.py) from 81–90% to 100%, and fix CI pipeline failure caused by missing curl in the python:3.13-slim Docker image.

Linked Issue

This MR is linked to the issue #63 (closed) and now closes it.

What does this MR do and why?

%{first_multiline_commit}

The app/core/ modules had significant test coverage gaps across error handling branches, optional parameter logic, convenience function delegation, and defensive checks. This MR adds targeted unit tests to cover every uncovered code path legitimately — no pragma: no cover or mock bypasses.

Additionally, all 6 CI pipeline jobs were failing because the python:3.13-slim base image does not include curl, which is required to download the uv installer. This MR fixes the CI configuration to install curl before the setup step.

Changes Made

  • tests/test_core/test_auth.py — 4 new tests: custom expires_delta, missing sub claim, invalid UUID in token, user not found in DB
  • tests/test_core/test_logger.py — Tests for all 20+ instance methods, all convenience functions, warning method, and logbull import failure branch
  • tests/test_core/test_rbac.py — 5 new tests: invalid role handling, permission rejection, authentication guard, get_user_role_summary, convenience function callability
  • tests/test_core/test_database_triggers.py — 1 new test covering extracted main() function + __main__ guard via runpy
  • app/core/database_triggers.py — Extracted main() from __main__ block for testability (no behavior change)
  • .gitlab-ci.yml — Added apt-get install curl ca-certificates to before_script

Technical Details

Test coverage fix:

  • Each uncovered line was analysed from --cov-report=term-missing output
  • Tests exercise real code paths — no pragma: no cover, no mocking away the logic under test
  • The logbull import failure branch (module-level except ImportError) is covered via importlib.reload with sys.modules manipulation
  • The __main__ guard is covered via runpy.run_module with run_name="__main__"

CI fix:

  • Root cause: python:3.13-slim does not ship curl
  • All 6 jobs (ruff-lint, ruff-format, type-check, pytest, pyupgrade, schemathesis) failed at curl -LsSf https://astral.sh/uv/install.sh | sh
  • Fix: install curl and ca-certificates via apt-get before the uv installer runs

Coverage before → after:

Module Before After
auth.py 89% 100%
database_triggers.py 90% 100%
logger.py 81% 100%
rbac.py 87% 100%

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to change)
  • 📝 Documentation update
  • ️ Refactor (no functional changes)
  • Performance improvement
  • 🧪 Test update
  • 🔧 Configuration change
  • 🚨 Security fix
  • 🗑️ Deprecation (removing deprecated code)

Related Issues / References

N/A

Screenshots or Screen Recordings

N/A — no UI or API changes.

How to Validate Locally

  1. Previous behaviour: uv run pytest tests/test_core/ --cov=app.core.auth --cov=app.core.database_triggers --cov=app.core.logger --cov=app.core.rbac --cov-report=term-missing showed 81–90% coverage with multiple missing lines
  2. Changes made: Added targeted tests for every uncovered branch/line, extracted main() in database_triggers.py, fixed .gitlab-ci.yml
  3. New behaviour: Same command now reports 100% coverage across all 4 modules, 70 tests passing, 0 missing lines

Testing Done

  • Unit tests added/updated
  • API endpoint tests passing

Test Cases Covered:

Scenario Expected Result Status
auth.py — token with custom expires_delta Token created with correct expiry
auth.py — token missing sub claim 401 HTTPException raised
auth.py — token with invalid UUID in sub 401 HTTPException raised
auth.py — valid token but user not in DB 401 HTTPException raised
database_triggers.pymain() function Calls initialize_database_triggers and prints success
database_triggers.py__main__ guard via runpy Executes main() when run as script
logger.py — all instance methods (login, register, vitals, etc.) Log entries written without error
logger.py — all convenience functions Delegate to global multi_logger instance
logger.pylogbull import failure LOGBULL_AVAILABLE set to False, fallback to mock
rbac.py — invalid role in get_user_permissions_cached Returns empty tuple, no crash
rbac.pyrequire_any_permission with no match 403 HTTPException raised
rbac.pyrequire_authentication with falsy user 401 HTTPException raised
rbac.pyget_user_role_summary Returns correct summary dict

Test Commands Run:

# Run core tests with full coverage
uv run pytest tests/test_core/ --cov=app.core.auth --cov=app.core.database_triggers --cov=app.core.logger --cov=app.core.rbac --cov-report=term-missing -v

# Result: 70 passed, 100% coverage across all 4 modules

Code Quality Checklist Code Standards

  • Code follows project conventions (naming, structure, formatting)
  • No debug statements or commented-out code left (unless necessary and intended)
  • No unused imports, variables, or functions
  • No duplicate code (DRY principle followed)
  • Type hints are properly defined (no Any unless justified and no mypy type check errors)

Ruff checks pass: ruff check . ruff format . --check

Python & FastAPI Best Practices

  • Functions follow single-responsibility principle
  • Async/await used correctly (no blocking calls in async functions)
  • Dependency injection used appropriately
  • Pydantic models used for request/response validation
  • SQLAlchemy queries are optimized (no N+1 queries)
  • Error handling is comprehensive (try/except with proper logging)

API Design N/A — no API changes in this MR.

Database & Migrations N/A — no database or schema changes in this MR.

Security No sensitive data logged (passwords, tokens, PII) SQL injection prevention verified (ORM used) Input sanitization implemented Authentication tokens handled securely CORS settings appropriate Security scan passes: bandit -r app/

Error Handling Errors are caught and handled gracefully User-friendly error messages returned Errors are logged appropriately HTTP error responses follow API standards

Documentation Code comments explain complex logic (not what, but why)

Known Limitations / Technical Debt None introduced.

Additional Notes The database_triggers.py change (extracting main()) is a minimal refactor with zero behavior change — it simply makes the main entry point testable All pre-commit hooks pass: ruff, ruff-format, bandit, mypy, vulture, pytest coverage The CI fix (apt-get install curl) adds ~2-3 seconds to job startup but is required for python:3.13-slim

MR Acceptance Checklist

Quality & Correctness

  • [*] Code works as intended and solves the stated problem
  • [*] No bugs introduced (existing functionality not broken)
  • [*] Edge cases handled appropriately

Maintainability

  • [*] Code is readable and well-organized
  • [*] Code is testable and well-tested
  • [*] Follows project patterns and conventions

Acceptance Review

  • Reviewed by at least 1 teammate
  • Reviewed by product owner
Edited by Madavarapu Sai Harshavardhan

Merge request reports

Loading