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

@@ -263,6 +263,13 @@ from .onboarding import (
OnboardingSyncNotCompleteException,
)
# Feature management exceptions
from .feature import (
FeatureNotFoundError,
InvalidFeatureCodesError,
TierNotFoundError,
)
__all__ = [
# Base exceptions
"WizamartException",
@@ -456,4 +463,8 @@ __all__ = [
"OnboardingCsvUrlRequiredException",
"OnboardingSyncJobNotFoundException",
"OnboardingSyncNotCompleteException",
# Feature exceptions
"FeatureNotFoundError",
"TierNotFoundError",
"InvalidFeatureCodesError",
]

42
app/exceptions/feature.py Normal file
View File

@@ -0,0 +1,42 @@
# app/exceptions/feature.py
"""
Feature management exceptions.
"""
from app.exceptions.base import ResourceNotFoundException, ValidationException
class FeatureNotFoundError(ResourceNotFoundException):
"""Feature not found."""
def __init__(self, feature_code: str):
super().__init__(
resource_type="Feature",
identifier=feature_code,
message=f"Feature '{feature_code}' not found",
)
self.feature_code = feature_code
class TierNotFoundError(ResourceNotFoundException):
"""Subscription tier not found."""
def __init__(self, tier_code: str):
super().__init__(
resource_type="SubscriptionTier",
identifier=tier_code,
message=f"Tier '{tier_code}' not found",
)
self.tier_code = tier_code
class InvalidFeatureCodesError(ValidationException):
"""Invalid feature codes provided."""
def __init__(self, invalid_codes: set[str]):
codes_str = ", ".join(sorted(invalid_codes))
super().__init__(
message=f"Invalid feature codes: {codes_str}",
details={"invalid_codes": list(invalid_codes)},
)
self.invalid_codes = invalid_codes