1a57878f76
CI/CD Pipeline / Validate Code Quality And Tests (pull_request) Failing after 1m12s
CI/CD Pipeline / Unit Tests (pull_request) Failing after 2m17s
CI/CD Pipeline / Integration Tests (pull_request) Failing after 1m33s
CI/CD Pipeline / Frontend Lint (pull_request) Successful in 3m14s
CI/CD Pipeline / Build & Push Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Build Production Runtime Images (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
1. 未使用依赖清理:
- 从 requirements-base.txt 移除 cryptography 和 pyOpenSSL
2. pyflakes 警告清零 (apps/ + packages/ + tests/):
- 移除 17 处未使用的 import (F401)
- 修复 26 处未使用的局部变量 (F841):
* 有副作用的赋值转为裸调用
* 无副作用的赋值直接删除
- 修复 1 处未使用的异常变量 (F841)
- 修复 1 处空 except 块
3. 测试文件冗余清理:
- 删除 tests/integration/test_project_management.py (模块级 skip,测试不存在的模块)
- 删除 tests/integration/fixtures/duplication_routes_fixed.py (未被引用)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
233 lines
7.3 KiB
Python
233 lines
7.3 KiB
Python
"""查重应用层用例单元测试。
|
|
|
|
覆盖:
|
|
- UploadForDuplicationUseCase — 创建查重记录
|
|
- ListDuplicationRecordsUseCase — 列表查询(含分页)
|
|
- GetDuplicationDetailUseCase — 详情查询
|
|
- DeleteDuplicationRecordUseCase — 删除记录
|
|
- RetryDuplicationUseCase — 重试查重(含状态校验)
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
|
|
from packages.application.duplication import (
|
|
DeleteDuplicationRecordUseCase,
|
|
GetDuplicationDetailUseCase,
|
|
ListDuplicationRecordsUseCase,
|
|
RetryDuplicationUseCase,
|
|
UploadForDuplicationCommand,
|
|
UploadForDuplicationUseCase,
|
|
)
|
|
from packages.domain.duplication import DuplicationRecord
|
|
|
|
|
|
def _make_record(status="pending", **kwargs):
|
|
"""创建测试用 DuplicationRecord。"""
|
|
record = DuplicationRecord.create(
|
|
user_id=kwargs.get("user_id", "user-1"),
|
|
filename=kwargs.get("filename", "test.mp4"),
|
|
file_size=kwargs.get("file_size", 1024),
|
|
storage_key=kwargs.get("storage_key", "oss/key"),
|
|
duration_seconds=kwargs.get("duration", 30.0),
|
|
)
|
|
if status != "pending":
|
|
record.mark_processing()
|
|
if status == "completed":
|
|
record.mark_completed(duplicate_rate=15.0, duplicate_count=1, segments=[])
|
|
elif status == "failed":
|
|
record.mark_failed("处理失败")
|
|
return record
|
|
|
|
|
|
class TestUploadForDuplicationUseCase:
|
|
"""上传查重用例测试。"""
|
|
|
|
def test_execute_creates_and_persists_record(self):
|
|
mock_repo = MagicMock()
|
|
mock_repo.create.side_effect = lambda r: r
|
|
|
|
use_case = UploadForDuplicationUseCase(mock_repo)
|
|
command = UploadForDuplicationCommand(
|
|
user_id="user-1",
|
|
filename="video.mp4",
|
|
file_size=2048,
|
|
storage_key="oss/video.mp4",
|
|
duration_seconds=60.0,
|
|
)
|
|
result = use_case.execute(command)
|
|
|
|
assert result.user_id == "user-1"
|
|
assert result.filename == "video.mp4"
|
|
assert result.file_size == 2048
|
|
assert result.status == "pending"
|
|
mock_repo.create.assert_called_once()
|
|
|
|
def test_execute_with_default_duration(self):
|
|
mock_repo = MagicMock()
|
|
mock_repo.create.side_effect = lambda r: r
|
|
|
|
use_case = UploadForDuplicationUseCase(mock_repo)
|
|
command = UploadForDuplicationCommand(
|
|
user_id="user-1",
|
|
filename="video.mp4",
|
|
file_size=1024,
|
|
storage_key="oss/key",
|
|
)
|
|
result = use_case.execute(command)
|
|
assert result.duration_seconds == 0.0
|
|
|
|
def test_execute_invalid_user_id_raises(self):
|
|
mock_repo = MagicMock()
|
|
use_case = UploadForDuplicationUseCase(mock_repo)
|
|
command = UploadForDuplicationCommand(
|
|
user_id="",
|
|
filename="video.mp4",
|
|
file_size=1024,
|
|
storage_key="oss/key",
|
|
)
|
|
with pytest.raises(ValueError, match="user_id"):
|
|
use_case.execute(command)
|
|
mock_repo.create.assert_not_called()
|
|
|
|
|
|
class TestListDuplicationRecordsUseCase:
|
|
"""列表查询用例测试。"""
|
|
|
|
def test_execute_returns_records(self):
|
|
records = [_make_record(), _make_record(filename="b.mp4")]
|
|
mock_repo = MagicMock()
|
|
mock_repo.list_by_user.return_value = records
|
|
|
|
use_case = ListDuplicationRecordsUseCase(mock_repo)
|
|
result = use_case.execute("user-1")
|
|
|
|
assert len(result) == 2
|
|
mock_repo.list_by_user.assert_called_once_with("user-1", offset=0, limit=50)
|
|
|
|
def test_execute_with_pagination(self):
|
|
mock_repo = MagicMock()
|
|
mock_repo.list_by_user.return_value = []
|
|
|
|
use_case = ListDuplicationRecordsUseCase(mock_repo)
|
|
use_case.execute("user-1", offset=10, limit=20)
|
|
|
|
mock_repo.list_by_user.assert_called_once_with("user-1", offset=10, limit=20)
|
|
|
|
def test_execute_empty_user_id_raises(self):
|
|
mock_repo = MagicMock()
|
|
use_case = ListDuplicationRecordsUseCase(mock_repo)
|
|
|
|
with pytest.raises(ValueError):
|
|
use_case.execute("")
|
|
mock_repo.list_by_user.assert_not_called()
|
|
|
|
def test_execute_whitespace_user_id_raises(self):
|
|
mock_repo = MagicMock()
|
|
use_case = ListDuplicationRecordsUseCase(mock_repo)
|
|
|
|
with pytest.raises(ValueError):
|
|
use_case.execute(" ")
|
|
|
|
def test_execute_strips_user_id(self):
|
|
mock_repo = MagicMock()
|
|
mock_repo.list_by_user.return_value = []
|
|
|
|
use_case = ListDuplicationRecordsUseCase(mock_repo)
|
|
use_case.execute(" user-1 ")
|
|
|
|
mock_repo.list_by_user.assert_called_once_with("user-1", offset=0, limit=50)
|
|
|
|
|
|
class TestGetDuplicationDetailUseCase:
|
|
"""详情查询用例测试。"""
|
|
|
|
def test_execute_returns_record(self):
|
|
record = _make_record()
|
|
mock_repo = MagicMock()
|
|
mock_repo.get.return_value = record
|
|
|
|
use_case = GetDuplicationDetailUseCase(mock_repo)
|
|
result = use_case.execute(record.id)
|
|
|
|
assert result is record
|
|
mock_repo.get.assert_called_once_with(record.id)
|
|
|
|
def test_execute_returns_none_for_missing(self):
|
|
mock_repo = MagicMock()
|
|
mock_repo.get.return_value = None
|
|
|
|
use_case = GetDuplicationDetailUseCase(mock_repo)
|
|
result = use_case.execute("nonexistent")
|
|
|
|
assert result is None
|
|
|
|
|
|
class TestDeleteDuplicationRecordUseCase:
|
|
"""删除用例测试。"""
|
|
|
|
def test_execute_deletes_record(self):
|
|
mock_repo = MagicMock()
|
|
mock_repo.delete.return_value = True
|
|
|
|
use_case = DeleteDuplicationRecordUseCase(mock_repo)
|
|
result = use_case.execute("record-1")
|
|
|
|
assert result is True
|
|
mock_repo.delete.assert_called_once_with("record-1")
|
|
|
|
def test_execute_returns_false_for_missing(self):
|
|
mock_repo = MagicMock()
|
|
mock_repo.delete.return_value = False
|
|
|
|
use_case = DeleteDuplicationRecordUseCase(mock_repo)
|
|
result = use_case.execute("nonexistent")
|
|
|
|
assert result is False
|
|
|
|
|
|
class TestRetryDuplicationUseCase:
|
|
"""重试用例测试。"""
|
|
|
|
def test_execute_resets_failed_record(self):
|
|
record = _make_record(status="failed")
|
|
mock_repo = MagicMock()
|
|
mock_repo.get.return_value = record
|
|
mock_repo.update.side_effect = lambda r: r
|
|
|
|
use_case = RetryDuplicationUseCase(mock_repo)
|
|
result = use_case.execute(record.id)
|
|
|
|
assert result is not None
|
|
assert result.status == "pending"
|
|
assert result.error_message == ""
|
|
assert result.duplicate_rate is None
|
|
assert result.duplicate_count == 0
|
|
assert result.segments == []
|
|
mock_repo.update.assert_called_once()
|
|
|
|
def test_execute_returns_none_for_missing(self):
|
|
mock_repo = MagicMock()
|
|
mock_repo.get.return_value = None
|
|
|
|
use_case = RetryDuplicationUseCase(mock_repo)
|
|
result = use_case.execute("nonexistent")
|
|
|
|
assert result is None
|
|
mock_repo.update.assert_not_called()
|
|
|
|
def test_execute_calls_repo_get_and_update(self):
|
|
record = _make_record(status="failed")
|
|
mock_repo = MagicMock()
|
|
mock_repo.get.return_value = record
|
|
mock_repo.update.side_effect = lambda r: r
|
|
|
|
use_case = RetryDuplicationUseCase(mock_repo)
|
|
use_case.execute(record.id)
|
|
|
|
mock_repo.get.assert_called_once_with(record.id)
|
|
mock_repo.update.assert_called_once()
|