76fdab4f63
CI/CD Pipeline / Check if frontend-only change (push) Has been skipped
CI/CD Pipeline / Frontend Lint (push) Has been skipped
CI/CD Pipeline / PR Build API Image (push) Has been skipped
CI/CD Pipeline / PR Build Web Image (push) Has been skipped
CI/CD Pipeline / PR Build Worker Image (push) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m2s
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m46s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 2m56s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m27s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 5m17s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 5m33s
CI/CD Pipeline / Integration Tests (push) Successful in 2m51s
CI/CD Pipeline / Unit Tests (push) Successful in 10m13s
CI/CD Pipeline / Build Production API Image (push) Has been skipped
CI/CD Pipeline / Build Production Web Image (push) Has been skipped
CI/CD Pipeline / Build Production Worker Image (push) Has been skipped
CI/CD Pipeline / CI Gate (push) Has been skipped
CI/CD Pipeline / Deploy Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Build Staging API Image (push) Successful in 12m49s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 29s
CI/CD Pipeline / ACR Image Cleanup (push) Failing after 14s
CI/CD Pipeline / Staging E2E Tests (push) Failing after 17s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 5m31s
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
185 lines
5.3 KiB
Python
185 lines
5.3 KiB
Python
"""classification 单测.
|
|
|
|
domain 层素材分类模块纯逻辑,0 外部依赖。
|
|
覆盖:4个枚举 + ClassificationJob 工厂/校验。
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from packages.domain.classification import (
|
|
AssetClassification,
|
|
AssetLibraryKind,
|
|
ClassificationJob,
|
|
ClassificationJobStatus,
|
|
IngestJobStatus,
|
|
)
|
|
|
|
|
|
class TestAssetLibraryKind:
|
|
"""AssetLibraryKind 枚举测试."""
|
|
|
|
def test_three_values(self):
|
|
"""视频/配音/图片三类."""
|
|
assert len(AssetLibraryKind) == 3
|
|
|
|
def test_video(self):
|
|
assert AssetLibraryKind.VIDEO == "video"
|
|
|
|
def test_voice(self):
|
|
assert AssetLibraryKind.VOICE == "voice"
|
|
|
|
def test_image(self):
|
|
assert AssetLibraryKind.IMAGE == "image"
|
|
|
|
def test_str_compatible(self):
|
|
"""StrEnum 字符串兼容."""
|
|
assert AssetLibraryKind.VIDEO == "video"
|
|
|
|
|
|
class TestIngestJobStatus:
|
|
"""IngestJobStatus 枚举测试."""
|
|
|
|
def test_four_statuses(self):
|
|
assert len(IngestJobStatus) == 4
|
|
|
|
def test_pending(self):
|
|
assert IngestJobStatus.PENDING == "pending"
|
|
|
|
def test_processing(self):
|
|
assert IngestJobStatus.PROCESSING == "processing"
|
|
|
|
def test_completed(self):
|
|
assert IngestJobStatus.COMPLETED == "completed"
|
|
|
|
def test_failed(self):
|
|
assert IngestJobStatus.FAILED == "failed"
|
|
|
|
|
|
class TestClassificationJobStatus:
|
|
"""ClassificationJobStatus 枚举测试."""
|
|
|
|
def test_four_statuses(self):
|
|
assert len(ClassificationJobStatus) == 4
|
|
|
|
def test_pending(self):
|
|
assert ClassificationJobStatus.PENDING == "pending"
|
|
|
|
def test_processing(self):
|
|
assert ClassificationJobStatus.PROCESSING == "processing"
|
|
|
|
def test_completed(self):
|
|
assert ClassificationJobStatus.COMPLETED == "completed"
|
|
|
|
def test_failed(self):
|
|
assert ClassificationJobStatus.FAILED == "failed"
|
|
|
|
def test_same_values_as_ingest(self):
|
|
"""两种任务状态值相同."""
|
|
assert set(ClassificationJobStatus) == set(IngestJobStatus)
|
|
|
|
|
|
class TestAssetClassification:
|
|
"""AssetClassification 枚举测试."""
|
|
|
|
def test_nine_categories(self):
|
|
"""9个分类."""
|
|
assert len(AssetClassification) == 9
|
|
|
|
def test_scenic(self):
|
|
assert AssetClassification.SCENIC == "scenic"
|
|
|
|
def test_product(self):
|
|
assert AssetClassification.PRODUCT == "product"
|
|
|
|
def test_person(self):
|
|
assert AssetClassification.PERSON == "person"
|
|
|
|
def test_animal(self):
|
|
assert AssetClassification.ANIMAL == "animal"
|
|
|
|
def test_food(self):
|
|
assert AssetClassification.FOOD == "food"
|
|
|
|
def test_tech(self):
|
|
assert AssetClassification.TECH == "tech"
|
|
|
|
def test_sport(self):
|
|
assert AssetClassification.SPORT == "sport"
|
|
|
|
def test_music(self):
|
|
assert AssetClassification.MUSIC == "music"
|
|
|
|
def test_other(self):
|
|
assert AssetClassification.OTHER == "other"
|
|
|
|
def test_all_values_unique(self):
|
|
"""所有分类值唯一."""
|
|
values = [c.value for c in AssetClassification]
|
|
assert len(values) == len(set(values))
|
|
|
|
|
|
class TestClassificationJobCreate:
|
|
"""ClassificationJob.create 测试."""
|
|
|
|
def test_create_valid(self):
|
|
"""正常创建."""
|
|
job = ClassificationJob.create(project_id="proj1", asset_id="asset1")
|
|
assert job.project_id == "proj1"
|
|
assert job.asset_id == "asset1"
|
|
assert job.status == ClassificationJobStatus.PENDING
|
|
assert job.classification == ""
|
|
assert job.confidence == 0.0
|
|
assert job.error_message == ""
|
|
assert isinstance(job.id, str)
|
|
assert len(job.id) > 0
|
|
|
|
def test_create_strips(self):
|
|
"""project_id 和 asset_id 会 strip."""
|
|
job = ClassificationJob.create(project_id=" proj1 ", asset_id=" asset1 ")
|
|
assert job.project_id == "proj1"
|
|
assert job.asset_id == "asset1"
|
|
|
|
def test_create_empty_project_id(self):
|
|
"""空 project_id 无效."""
|
|
try:
|
|
ClassificationJob.create(project_id="", asset_id="a1")
|
|
assert False
|
|
except ValueError as e:
|
|
assert "project_id" in str(e)
|
|
|
|
def test_create_whitespace_project_id(self):
|
|
"""纯空白 project_id 无效."""
|
|
try:
|
|
ClassificationJob.create(project_id=" ", asset_id="a1")
|
|
assert False
|
|
except ValueError as e:
|
|
assert "project_id" in str(e)
|
|
|
|
def test_create_empty_asset_id(self):
|
|
"""空 asset_id 无效."""
|
|
try:
|
|
ClassificationJob.create(project_id="p1", asset_id="")
|
|
assert False
|
|
except ValueError as e:
|
|
assert "asset_id" in str(e)
|
|
|
|
def test_create_whitespace_asset_id(self):
|
|
"""纯空白 asset_id 无效."""
|
|
try:
|
|
ClassificationJob.create(project_id="p1", asset_id=" ")
|
|
assert False
|
|
except ValueError as e:
|
|
assert "asset_id" in str(e)
|
|
|
|
def test_create_unique_id(self):
|
|
"""不同 job id 不同."""
|
|
j1 = ClassificationJob.create("p", "a")
|
|
j2 = ClassificationJob.create("p", "a")
|
|
assert j1.id != j2.id
|
|
|
|
def test_create_has_timestamps(self):
|
|
"""有创建和更新时间."""
|
|
job = ClassificationJob.create("p", "a")
|
|
assert job.created_at is not None
|
|
assert job.updated_at is not None
|