c873bb635f
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 / Check if frontend-only change (pull_request) Successful in 55s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 1m13s
CI/CD Pipeline / Build Staging API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Staging Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Validate - Migration (alembic) (push) Successful in 2m43s
PR Automation / Auto Merge on CI Green + Approved (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (push) Successful in 2m46s
CI/CD Pipeline / Frontend Lint (pull_request) Has been skipped
CI/CD Pipeline / Frontend Unit Tests (pull_request) Has been skipped
CI/CD Pipeline / Validate - Type Check (mypy) (pull_request) Successful in 2m51s
CI/CD Pipeline / Validate - Migration (alembic) (pull_request) Successful in 3m6s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m59s
PR Automation / Auto Approve on CI Green (pull_request) Successful in 4m14s
CI/CD Pipeline / PR Build Web Image (pull_request) Has been skipped
CI/CD Pipeline / PR Build Worker Image (pull_request) Successful in 30s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (pull_request) Has been skipped
CI/CD Pipeline / Staging E2E Tests (pull_request) Has been skipped
CI/CD Pipeline / Staging API Integration Tests (pull_request) Has been skipped
CI/CD Pipeline / ACR Image Cleanup (pull_request) Has been skipped
Preview Deploy / Deploy Preview Environment (pull_request) Successful in 2m53s
CI/CD Pipeline / PR Build API Image (pull_request) Successful in 3m6s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 7m6s
CI/CD Pipeline / Build Staging API Image (push) Successful in 7m12s
AI Code Review / AI Code Review (pull_request) Failing after 6m19s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 39s
CI/CD Pipeline / Validate - Code Quality (push) Successful in 8m57s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 1m2s
CI/CD Pipeline / Validate - Code Quality (pull_request) Successful in 8m55s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 1m9s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m16s
CI/CD Pipeline / Integration Tests (push) Successful in 3m12s
CI/CD Pipeline / Integration Tests (pull_request) Successful in 3m13s
CI/CD Pipeline / Unit Tests (push) Successful in 14m24s
CI/CD Pipeline / CI Gate (push) Has been skipped
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 / Deploy Production (push) Has been skipped
CI/CD Pipeline / Canary Release to Production (push) Has been skipped
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Unit Tests (pull_request) Successful in 12m30s
CI/CD Pipeline / Build Production API Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Web Image (pull_request) Has been skipped
CI/CD Pipeline / Build Production Worker Image (pull_request) Has been skipped
CI/CD Pipeline / Deploy Production (pull_request) Has been skipped
CI/CD Pipeline / Canary Release to Production (pull_request) Has been skipped
CI/CD Pipeline / Production Browser E2E (pull_request) Has been skipped
CI/CD Pipeline / CI Gate (pull_request) Successful in 8s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com> Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
68 lines
2.7 KiB
Python
68 lines
2.7 KiB
Python
"""防回归测试:P1 修复
|
||
- Bug 1: gen_task 过期内存对象 _repo.update() 覆盖 DB status 为 pending
|
||
- Bug 2: 封面模型误用 .metadata(SQLAlchemy 保留属性),应为 .extra_meta
|
||
"""
|
||
|
||
import ast
|
||
from pathlib import Path
|
||
|
||
import pytest
|
||
|
||
GENERATION_FILE = Path(__file__).resolve().parents[2] / "apps" / "worker" / "worker_app" / "tasks" / "generation.py"
|
||
|
||
|
||
def _read_source() -> str:
|
||
return GENERATION_FILE.read_text(encoding="utf-8")
|
||
|
||
|
||
class TestCoverModelUsesExtraMeta:
|
||
"""封面持久化必须使用 ORM 属性 extra_meta,而不是 SQLAlchemy 保留的 .metadata。"""
|
||
|
||
def test_no_metadata_attribute_access_on_cover_model(self):
|
||
source = _read_source()
|
||
# 禁止对 _cover_model.metadata 进行读或写
|
||
assert "_cover_model.metadata" not in source, (
|
||
"_cover_model.metadata is the SQLAlchemy reserved MetaData object, "
|
||
"not the JSON column. Use _cover_model.extra_meta instead."
|
||
)
|
||
|
||
def test_extra_meta_used_for_cover_candidates(self):
|
||
source = _read_source()
|
||
assert "_cover_model.extra_meta" in source
|
||
assert 'meta["cover_candidates"]' in source
|
||
|
||
|
||
class TestAssetAnalysesDoesNotOverwriteStatus:
|
||
"""保存 asset_analyses 时不能用过期的 gen_task 内存对象整体 _repo.update,
|
||
否则会把已被 _update_task_status 改为 running 的 status 覆盖回 pending。"""
|
||
|
||
def test_no_stale_repo_update_with_gen_task(self):
|
||
source = _read_source()
|
||
# 旧代码:gen_task.extra_meta = {...}; _repo.update(gen_task)
|
||
# 这行会把内存中的 pending status 写回 DB
|
||
assert "_repo.update(gen_task)" not in source, (
|
||
"_repo.update(gen_task) writes a stale in-memory object back to DB, "
|
||
"overwriting status set by _update_task_status. "
|
||
"Use an independent session to update only extra_meta."
|
||
)
|
||
|
||
def test_no_stale_repo_update(self):
|
||
"""旧路径的 _repo.update(gen_task) 模式已随 DEPRECATED 代码一起删除。"""
|
||
source = _read_source()
|
||
assert "_repo.update(gen_task)" not in source
|
||
|
||
|
||
class TestGenerationTaskModelOrmAttribute:
|
||
"""确认 ORM 属性映射:Python 属性 extra_meta -> DB 列 metadata。"""
|
||
|
||
def test_orm_attribute_is_extra_meta(self):
|
||
from packages.adapters.sqlalchemy_impl.models import GenerationTaskModel
|
||
|
||
# ORM 属性必须存在
|
||
assert hasattr(GenerationTaskModel, "extra_meta")
|
||
# .metadata 是 SQLAlchemy 声明基类保留的 MetaData,不是列描述符
|
||
# 它不应该是我们的 JSON 字段
|
||
from sqlalchemy import MetaData
|
||
|
||
assert isinstance(GenerationTaskModel.metadata, MetaData)
|