53fb25efcf
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 2s
CI/CD Pipeline / Check push changed paths (push) Successful in 19s
CI/CD Pipeline / Build Staging API Image (push) Successful in 41s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 48s
CI/CD Pipeline / Integration Tests (push) Successful in 3m10s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 3m17s
CI/CD Pipeline / Build Staging Web Image (push) Successful in 3m30s
CI/CD Pipeline / Validate - Style (push) Successful in 4m17s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 59s
CI/CD Pipeline / Frontend Unit Tests (push) Failing after 5m33s
CI/CD Pipeline / Validate - Security (push) Successful in 7m12s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m38s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 3m13s
CI/CD Pipeline / Unit Tests (push) Successful in 10m11s
CI/CD Pipeline / Production Browser E2E (push) Has been skipped
CI/CD Pipeline / Staging E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Production Worker Image (push) Failing after 26h14m3s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 26h24m21s
CI/CD Pipeline / Retag skipped Staging API Image (push) Failing after 26h19m47s
CI/CD Pipeline / PR Build Web Image (push) Failing after 26h23m44s
CI/CD Pipeline / PR Build API Image (push) Failing after 26h23m44s
CI/CD Pipeline / Deploy Production (push) Failing after 26h13m23s
CI/CD Pipeline / Build Production Web Image (push) Failing after 26h13m26s
CI/CD Pipeline / CI Gate (push) Failing after 26h13m25s
CI/CD Pipeline / Build Production API Image (push) Failing after 26h13m26s
CI/CD Pipeline / Canary Release to Production (push) Failing after 26h13m23s
CI/CD Pipeline / Retag skipped Staging Web Image (push) Failing after 26h19m46s
CI/CD Pipeline / Frontend Lint (push) Failing after 26h23m37s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 26h23m45s
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Failing after 26h19m46s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com> Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
99 lines
3.9 KiB
Python
99 lines
3.9 KiB
Python
"""Unit tests for SQLAlchemyAssetRepository - list ordering (created_at DESC)."""
|
|
|
|
import sys
|
|
from datetime import UTC, datetime, timedelta, timezone
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[2] / "apps" / "api"))
|
|
|
|
from sqlalchemy import create_engine, text
|
|
from sqlalchemy.orm import sessionmaker
|
|
|
|
from packages.adapters.sqlalchemy_impl.asset_repository import SQLAlchemyAssetRepository
|
|
from packages.adapters.sqlalchemy_impl.models import AssetModel, Base
|
|
from packages.domain import Asset, AssetStatus
|
|
|
|
|
|
def _repository():
|
|
engine = create_engine("sqlite:///:memory:")
|
|
Base.metadata.create_all(engine)
|
|
session = sessionmaker(bind=engine)()
|
|
return SQLAlchemyAssetRepository(session), session
|
|
|
|
|
|
def _insert_asset_with_created_at(
|
|
session, asset_id: str, library_id: str, project_id: str, created_at: datetime, file_type: str = "video"
|
|
):
|
|
"""直接插入指定created_at的素材,绕过create()方法的时间覆盖。"""
|
|
model = AssetModel(
|
|
id=asset_id,
|
|
project_id=project_id,
|
|
asset_library_id=library_id,
|
|
name=f"{asset_id}.mp4",
|
|
file_type=file_type,
|
|
file_size=102400,
|
|
file_url=f"assets/{asset_id}.mp4",
|
|
storage_key=f"assets/{asset_id}.mp4",
|
|
status="ready",
|
|
classification_status="pending",
|
|
uploaded_by_user_id="user-1",
|
|
created_at=created_at,
|
|
updated_at=created_at,
|
|
)
|
|
session.add(model)
|
|
|
|
|
|
def test_find_by_library_ordered_by_created_at_desc():
|
|
"""find_by_library 返回结果按 created_at 倒序排列,最新的在最前面。"""
|
|
repository, session = _repository()
|
|
base_time = datetime(2026, 7, 18, 10, 0, 0, tzinfo=UTC)
|
|
|
|
_insert_asset_with_created_at(session, "asset-oldest", "lib-1", "proj-1", base_time)
|
|
_insert_asset_with_created_at(session, "asset-middle", "lib-1", "proj-1", base_time + timedelta(hours=1))
|
|
_insert_asset_with_created_at(session, "asset-newest", "lib-1", "proj-1", base_time + timedelta(hours=2))
|
|
session.commit()
|
|
|
|
result = repository.find_by_library("lib-1")
|
|
assert len(result) == 3
|
|
assert [a.id for a in result] == ["asset-newest", "asset-middle", "asset-oldest"]
|
|
|
|
|
|
def test_find_by_project_ordered_by_created_at_desc():
|
|
"""find_by_project 返回结果按 created_at 倒序排列。"""
|
|
repository, session = _repository()
|
|
base_time = datetime(2026, 7, 18, 10, 0, 0, tzinfo=UTC)
|
|
|
|
_insert_asset_with_created_at(session, "asset-1", "lib-1", "proj-1", base_time)
|
|
_insert_asset_with_created_at(session, "asset-2", "lib-2", "proj-1", base_time + timedelta(hours=1))
|
|
_insert_asset_with_created_at(session, "asset-3", "lib-1", "proj-1", base_time + timedelta(hours=2))
|
|
session.commit()
|
|
|
|
result = repository.find_by_project("proj-1")
|
|
assert len(result) == 3
|
|
assert [a.id for a in result] == ["asset-3", "asset-2", "asset-1"]
|
|
|
|
|
|
def test_find_by_library_and_file_type_ordered_by_created_at_desc():
|
|
"""find_by_library_and_file_type 返回结果按 created_at 倒序排列。"""
|
|
repository, session = _repository()
|
|
base_time = datetime(2026, 7, 18, 10, 0, 0, tzinfo=UTC)
|
|
|
|
_insert_asset_with_created_at(session, "video-old", "lib-1", "proj-1", base_time, file_type="video")
|
|
_insert_asset_with_created_at(
|
|
session, "video-new", "lib-1", "proj-1", base_time + timedelta(hours=2), file_type="video"
|
|
)
|
|
_insert_asset_with_created_at(
|
|
session, "audio-new", "lib-1", "proj-1", base_time + timedelta(hours=1), file_type="audio"
|
|
)
|
|
session.commit()
|
|
|
|
# 只查video类型,验证排序和过滤同时生效
|
|
result = repository.find_by_library_and_file_type("lib-1", "video")
|
|
assert len(result) == 2
|
|
assert [a.id for a in result] == ["video-new", "video-old"]
|
|
|
|
# 只查audio类型
|
|
audio_result = repository.find_by_library_and_file_type("lib-1", "audio")
|
|
assert len(audio_result) == 1
|
|
assert audio_result[0].id == "audio-new"
|