- Frontend: Next.js 14 with TypeScript - Backend: FastAPI with SQLAlchemy - Agent: Carmodoo sync agent - Deployment: Docker Compose based staging/production setup - Scripts: Automated deployment with rollback support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
217 lines
6.1 KiB
Python
217 lines
6.1 KiB
Python
"""
|
|
Performance Check Access Unit Tests
|
|
|
|
비즈니스 로직:
|
|
- 성능점검표는 항상 0.1 CC 결제 필요 (배너 차량 포함)
|
|
- 1 CC 차량 전체 구매 시 성능점검표 포함
|
|
- 관리자는 무조건 접근 가능
|
|
"""
|
|
|
|
import pytest
|
|
from unittest.mock import MagicMock, patch
|
|
from sqlalchemy.orm import Session
|
|
|
|
|
|
class TestPerformanceCheckAccess:
|
|
"""성능점검표 접근 권한 테스트"""
|
|
|
|
def test_admin_has_access(self):
|
|
"""관리자는 성능점검표에 무조건 접근 가능"""
|
|
# Given
|
|
user = MagicMock()
|
|
user.is_admin = True
|
|
user.id = 1
|
|
|
|
# When
|
|
has_access = self._check_access(user, car_id=1, has_perf_view=False, has_car_view=False)
|
|
|
|
# Then
|
|
assert has_access is True
|
|
|
|
def test_user_with_performance_check_purchase(self):
|
|
"""0.1 CC 결제한 사용자는 접근 가능"""
|
|
# Given
|
|
user = MagicMock()
|
|
user.is_admin = False
|
|
user.id = 1
|
|
|
|
# When
|
|
has_access = self._check_access(user, car_id=1, has_perf_view=True, has_car_view=False)
|
|
|
|
# Then
|
|
assert has_access is True
|
|
|
|
def test_user_with_full_car_view_purchase(self):
|
|
"""1 CC 결제한 사용자는 접근 가능 (성능점검표 포함)"""
|
|
# Given
|
|
user = MagicMock()
|
|
user.is_admin = False
|
|
user.id = 1
|
|
|
|
# When
|
|
has_access = self._check_access(user, car_id=1, has_perf_view=False, has_car_view=True)
|
|
|
|
# Then
|
|
assert has_access is True
|
|
|
|
def test_user_without_purchase(self):
|
|
"""결제하지 않은 사용자는 접근 불가"""
|
|
# Given
|
|
user = MagicMock()
|
|
user.is_admin = False
|
|
user.id = 1
|
|
|
|
# When
|
|
has_access = self._check_access(user, car_id=1, has_perf_view=False, has_car_view=False)
|
|
|
|
# Then
|
|
assert has_access is False
|
|
|
|
def test_anonymous_user(self):
|
|
"""비로그인 사용자는 접근 불가"""
|
|
# Given
|
|
user = None
|
|
|
|
# When
|
|
has_access = self._check_access(user, car_id=1, has_perf_view=False, has_car_view=False)
|
|
|
|
# Then
|
|
assert has_access is False
|
|
|
|
def test_banner_car_still_requires_payment(self):
|
|
"""배너 차량이어도 성능점검표는 결제 필요"""
|
|
# Given
|
|
user = MagicMock()
|
|
user.is_admin = False
|
|
user.id = 1
|
|
is_banner_car = True # 배너 차량
|
|
|
|
# When - 결제하지 않은 경우
|
|
has_access = self._check_access(
|
|
user, car_id=1,
|
|
has_perf_view=False,
|
|
has_car_view=False,
|
|
is_banner_car=is_banner_car
|
|
)
|
|
|
|
# Then - 배너 차량이어도 접근 불가
|
|
assert has_access is False
|
|
|
|
def test_banner_car_with_payment(self):
|
|
"""배너 차량 + 0.1 CC 결제 시 접근 가능"""
|
|
# Given
|
|
user = MagicMock()
|
|
user.is_admin = False
|
|
user.id = 1
|
|
is_banner_car = True
|
|
|
|
# When
|
|
has_access = self._check_access(
|
|
user, car_id=1,
|
|
has_perf_view=True,
|
|
has_car_view=False,
|
|
is_banner_car=is_banner_car
|
|
)
|
|
|
|
# Then
|
|
assert has_access is True
|
|
|
|
def _check_access(
|
|
self,
|
|
user,
|
|
car_id: int,
|
|
has_perf_view: bool,
|
|
has_car_view: bool,
|
|
is_banner_car: bool = False
|
|
) -> bool:
|
|
"""
|
|
성능점검표 접근 권한 확인 로직
|
|
|
|
Note: 이 로직은 backend/app/api/carmodoo.py의
|
|
get_car_performance_check 함수와 동일해야 함
|
|
"""
|
|
has_access = False
|
|
|
|
# 배너 차량 여부는 성능점검표 접근에 영향 없음
|
|
# (이미지와 연락처만 무료, 성능점검표는 유료)
|
|
|
|
if user:
|
|
if user.is_admin:
|
|
has_access = True
|
|
else:
|
|
# 0.1 CC 결제 또는 1 CC 결제
|
|
has_access = has_perf_view or has_car_view
|
|
|
|
return has_access
|
|
|
|
|
|
class TestPerformanceCheckPreview:
|
|
"""성능점검표 미리보기 테스트"""
|
|
|
|
def test_preview_available_without_payment(self):
|
|
"""결제 전에도 미리보기 정보 제공"""
|
|
# 미리보기에 포함되는 정보
|
|
preview_fields = ['check_number', 'check_date', 'mileage']
|
|
|
|
# 미리보기에 포함되지 않는 정보
|
|
full_access_fields = [
|
|
'is_flood_damaged',
|
|
'is_fire_damaged',
|
|
'device_status',
|
|
'body_parts',
|
|
'frame_parts',
|
|
'pdf_path'
|
|
]
|
|
|
|
# 미리보기 응답 구조 확인
|
|
preview_response = {
|
|
"car_id": 1,
|
|
"found": True,
|
|
"has_access": False,
|
|
"preview": {
|
|
"check_number": "A123456",
|
|
"check_date": "2024-01-01",
|
|
"mileage": 50000
|
|
},
|
|
"data": None # 결제 전에는 null
|
|
}
|
|
|
|
assert preview_response["has_access"] is False
|
|
assert preview_response["data"] is None
|
|
for field in preview_fields:
|
|
assert field in preview_response["preview"]
|
|
|
|
|
|
class TestBannerCarImageAccess:
|
|
"""배너 차량 이미지 접근 테스트 (참고용 - 성능점검표와 별개)"""
|
|
|
|
def test_banner_car_images_are_free(self):
|
|
"""배너 차량 이미지는 무료"""
|
|
is_banner_car = True
|
|
user = None # 비로그인
|
|
|
|
# 배너 차량 이미지 접근 가능 여부
|
|
can_view_images = is_banner_car # 배너면 무조건 가능
|
|
|
|
assert can_view_images is True
|
|
|
|
def test_banner_car_contact_is_free(self):
|
|
"""배너 차량 연락처는 무료"""
|
|
is_banner_car = True
|
|
user = None # 비로그인
|
|
|
|
# 배너 차량 연락처 접근 가능 여부
|
|
can_view_contact = is_banner_car # 배너면 무조건 가능
|
|
|
|
assert can_view_contact is True
|
|
|
|
def test_non_banner_car_images_require_payment(self):
|
|
"""비배너 차량 이미지는 유료"""
|
|
is_banner_car = False
|
|
has_paid = False
|
|
|
|
# 비배너 차량 이미지 접근
|
|
can_view_images = has_paid
|
|
|
|
assert can_view_images is False
|