"""UUID 字段长度单元测试 — 验证标准 UUID(带横杠,36字符)可正常插入. 覆盖: - 所有从 varchar(32) 扩到 varchar(36) 的表 - 插入标准 UUID 格式(带横杠)不报 StringDataRightTruncation - 字段长度从 32 扩到 36 后 ORM 模型定义正确 """ from __future__ import annotations import uuid import pytest from packages.adapters.sqlalchemy_impl.models import ( ClassificationJobModel, EditPlanClipModel, EditPlanModel, EditTemplateModel, GeneratedVideoModel, GenerationTaskModel, IngestJobModel, JobModel, ProjectModel, TemplateClipConfigModel, ) def _uuid() -> str: """生成标准 UUID 字符串(带横杠,36 字符).""" return str(uuid.uuid4()) class TestUUIDFieldLengthModels: """验证 ORM 模型中 UUID 字段定义为 String(36).""" def _get_column_type_length(self, model_cls, column_name: str) -> int: """获取模型列的 String 长度.""" col = model_cls.__table__.columns[column_name] return col.type.length # ── ProjectModel ────────────────────────────────────────────────────────── def test_project_id_is_36(self): assert self._get_column_type_length(ProjectModel, "id") == 36 def test_project_owner_user_id_is_36(self): assert self._get_column_type_length(ProjectModel, "owner_user_id") == 36 # ── EditTemplateModel ───────────────────────────────────────────────────── def test_edit_template_id_is_36(self): assert self._get_column_type_length(EditTemplateModel, "id") == 36 # ── EditPlanModel ───────────────────────────────────────────────────────── @pytest.mark.parametrize( "col", ["id", "template_id", "source_edit_plan_id", "project_id", "created_by_user_id"], ) def test_edit_plan_uuid_fields_are_36(self, col): assert self._get_column_type_length(EditPlanModel, col) == 36 # ── TemplateClipConfigModel ─────────────────────────────────────────────── @pytest.mark.parametrize("col", ["id", "template_id"]) def test_template_clip_config_uuid_fields_are_36(self, col): assert self._get_column_type_length(TemplateClipConfigModel, col) == 36 # ── EditPlanClipModel ───────────────────────────────────────────────────── @pytest.mark.parametrize( "col", ["id", "plan_id", "template_clip_config_id", "asset_id"], ) def test_edit_plan_clip_uuid_fields_are_36(self, col): assert self._get_column_type_length(EditPlanClipModel, col) == 36 # ── IngestJobModel(P0 bug 所在表)───────────────────────────────────────── @pytest.mark.parametrize( "col", ["id", "project_id", "library_id", "result_asset_id"], ) def test_ingest_job_uuid_fields_are_36(self, col): assert self._get_column_type_length(IngestJobModel, col) == 36 def test_ingest_job_library_id_accepts_standard_uuid(self): """P0 回归:library_id 必须能容纳标准 UUID(36 字符带横杠).""" standard_uuid = "550e8400-e29b-41d4-a716-446655440000" assert len(standard_uuid) == 36 col = IngestJobModel.__table__.columns["library_id"] assert col.type.length >= 36 # ── ClassificationJobModel ──────────────────────────────────────────────── @pytest.mark.parametrize("col", ["id", "project_id", "asset_id"]) def test_classification_job_uuid_fields_are_36(self, col): assert self._get_column_type_length(ClassificationJobModel, col) == 36 # ── GenerationTaskModel ─────────────────────────────────────────────────── @pytest.mark.parametrize( "col", [ "id", "project_id", "strategy_id", "asset_library_id", "voice_library_id", "created_by_user_id", "source_edit_plan_id", "batch_id", ], ) def test_generation_task_uuid_fields_are_36(self, col): assert self._get_column_type_length(GenerationTaskModel, col) == 36 # ── GeneratedVideoModel ─────────────────────────────────────────────────── @pytest.mark.parametrize( "col", ["id", "project_id", "generation_task_id", "duplicate_of"], ) def test_generated_video_uuid_fields_are_36(self, col): assert self._get_column_type_length(GeneratedVideoModel, col) == 36 # ── JobModel ────────────────────────────────────────────────────────────── @pytest.mark.parametrize( "col", ["id", "project_id", "source_id", "created_by_user_id"], ) def test_job_uuid_fields_are_36(self, col): assert self._get_column_type_length(JobModel, col) == 36 class TestUUIDInsertWithHyphens: """验证标准 UUID(带横杠)可构造 ORM 对象,字段长度足够.""" def test_ingest_job_model_construct_with_standard_uuid(self): """P0 回归测试:用标准 UUID 构造 IngestJobModel 不报错.""" std_uuid = _uuid() assert len(std_uuid) == 36 job = IngestJobModel( id=_uuid(), project_id=_uuid(), library_id=std_uuid, # ← 关键:标准 UUID 带横杠 storage_key="test/file.mp4", result_asset_id=_uuid(), ) assert job.library_id == std_uuid assert len(job.library_id) == 36 def test_project_model_construct_with_standard_uuid(self): project = ProjectModel( id=_uuid(), owner_user_id=_uuid(), name="test", ) assert len(project.id) == 36 assert len(project.owner_user_id) == 36 def test_generation_task_model_construct_with_standard_uuid(self): task = GenerationTaskModel( id=_uuid(), project_id=_uuid(), asset_library_id=_uuid(), created_by_user_id=_uuid(), source_edit_plan_id=_uuid(), batch_id=_uuid(), ) assert len(task.id) == 36 assert len(task.asset_library_id) == 36 def test_edit_plan_model_construct_with_standard_uuid(self): plan = EditPlanModel( id=_uuid(), template_id=_uuid(), source_edit_plan_id=_uuid(), project_id=_uuid(), created_by_user_id=_uuid(), ) assert len(plan.id) == 36 assert len(plan.template_id) == 36 def test_generated_video_model_construct_with_standard_uuid(self): video = GeneratedVideoModel( id=_uuid(), project_id=_uuid(), generation_task_id=_uuid(), duplicate_of=_uuid(), name="test.mp4", file_url="https://example.com/test.mp4", file_size=1000, duration=10.0, width=1280, height=720, fps=25.0, ) assert len(video.id) == 36 assert len(video.duplicate_of) == 36