test: add service tests and fix architecture violations

- Add comprehensive unit tests for FeatureService (24 tests)
- Add comprehensive unit tests for UsageService (11 tests)
- Fix API-002/API-003 architecture violations in feature/usage APIs
- Move database queries from API layer to service layer
- Create UsageService for usage and limits management
- Create custom exceptions (FeatureNotFoundError, TierNotFoundError)
- Fix ValidationException usage in content_pages.py
- Refactor vendor features API to use proper response models
- All 35 new tests passing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-31 18:48:59 +01:00
parent 7d1a421826
commit aa4b5a4c63
10 changed files with 1474 additions and 408 deletions

View File

@@ -16,12 +16,13 @@ Endpoints:
import logging
from fastapi import APIRouter, Depends, HTTPException, Query
from fastapi import APIRouter, Depends, Query
from pydantic import BaseModel
from sqlalchemy.orm import Session
from app.api.deps import get_current_vendor_api
from app.core.database import get_db
from app.exceptions import FeatureNotFoundError
from app.services.feature_service import feature_service
from models.database.user import User
@@ -99,6 +100,13 @@ class FeatureGroupedResponse(BaseModel):
total_count: int
class FeatureCheckResponse(BaseModel):
"""Quick feature availability check response."""
has_feature: bool
feature_code: str
# ============================================================================
# Endpoints
# ============================================================================
@@ -285,7 +293,7 @@ def get_feature_detail(
# Get feature
feature = feature_service.get_feature_by_code(db, feature_code)
if not feature:
raise HTTPException(status_code=404, detail=f"Feature '{feature_code}' not found")
raise FeatureNotFoundError(feature_code)
# Check availability
is_available = feature_service.has_feature(db, vendor_id, feature_code)
@@ -317,7 +325,7 @@ def get_feature_detail(
)
@router.get("/check/{feature_code}")
@router.get("/check/{feature_code}", response_model=FeatureCheckResponse)
def check_feature(
feature_code: str,
current_user: User = Depends(get_current_vendor_api),
@@ -332,9 +340,9 @@ def check_feature(
feature_code: The feature code
Returns:
{"has_feature": true/false}
has_feature and feature_code
"""
vendor_id = current_user.token_vendor_id
has_feature = feature_service.has_feature(db, vendor_id, feature_code)
return {"has_feature": has_feature, "feature_code": feature_code}
return FeatureCheckResponse(has_feature=has_feature, feature_code=feature_code)