""" In-Memory 项目仓储 + 小仓储测试. """ from __future__ import annotations from datetime import datetime import pytest from packages.adapters.in_memory.classification_job_repository import InMemoryClassificationJobRepository from packages.adapters.in_memory.ingest_job_repository import InMemoryIngestJobRepository from packages.adapters.in_memory.project_repository import InMemoryProjectRepository from packages.domain import ClassificationJob, IngestJob, Project # ── Project Repository ────────────────────────────────────────────────────── @pytest.fixture def project_repo(): return InMemoryProjectRepository() @pytest.fixture def make_project(): counter = 0 def _make(owner_id: str = "user_1", name: str = "测试项目"): nonlocal counter counter += 1 return Project( id=f"proj_{counter}", owner_user_id=owner_id, name=name, ) return _make class TestInMemoryProjectRepository: """项目仓储.""" def test_save_and_find_by_id(self, project_repo, make_project): proj = make_project() project_repo.save(proj) found = project_repo.find_by_id(proj.id) assert found is not None assert found.id == proj.id assert found.name == "测试项目" def test_find_by_id_not_found(self, project_repo): assert project_repo.find_by_id("nonexistent") is None def test_find_by_owner(self, project_repo, make_project): for i in range(3): project_repo.save(make_project(owner_id="user_1", name=f"p{i}")) project_repo.save(make_project(owner_id="user_2", name="other")) result = project_repo.find_by_owner_user_id("user_1") assert len(result) == 3 assert all(p.owner_user_id == "user_1" for p in result) def test_count_by_owner(self, project_repo, make_project): for i in range(5): project_repo.save(make_project(owner_id="user_1", name=f"p{i}")) project_repo.save(make_project(owner_id="user_2", name="other")) assert project_repo.count_by_owner("user_1") == 5 assert project_repo.count_by_owner("user_2") == 1 assert project_repo.count_by_owner("user_3") == 0 def test_delete_existing(self, project_repo, make_project): proj = make_project() project_repo.save(proj) result = project_repo.delete(proj.id) assert result is True assert project_repo.find_by_id(proj.id) is None def test_delete_nonexistent(self, project_repo): assert project_repo.delete("nonexistent") is False def test_save_updates(self, project_repo, make_project): proj = make_project(name="v1") project_repo.save(proj) proj.name = "v2" project_repo.save(proj) found = project_repo.find_by_id(proj.id) assert found.name == "v2" def test_find_accessible_projects(self, project_repo, make_project): p1 = make_project(owner_id="user_1", name="owned") project_repo.save(p1) # 自己拥有的项目可访问 result = project_repo.find_accessible_projects("user_1") assert len(result) >= 1 assert any(p.id == p1.id for p in result) # ── Classification Job Repository ────────────────────────────────────────── @pytest.fixture def classif_repo(): return InMemoryClassificationJobRepository() class TestInMemoryClassificationJobRepository: """分类任务仓储.""" def test_create_and_get(self, classif_repo): job = ClassificationJob( id="job_1", project_id="p1", asset_id="a1", status="pending", ) classif_repo.create(job) found = classif_repo.get("job_1") assert found is not None assert found.id == "job_1" assert found.status == "pending" def test_get_not_found(self, classif_repo): assert classif_repo.get("nonexistent") is None def test_update(self, classif_repo): job = ClassificationJob( id="job_1", project_id="p1", asset_id="a1", status="pending", ) classif_repo.create(job) job.status = "completed" classif_repo.update(job) found = classif_repo.get("job_1") assert found.status == "completed" def test_update_nonexistent_creates(self, classif_repo): """update 对不存在的也会写入(dict 赋值)""" job = ClassificationJob( id="new_job", project_id="p1", asset_id="a1", status="running", ) classif_repo.update(job) found = classif_repo.get("new_job") assert found is not None # ── Ingest Job Repository ────────────────────────────────────────────────── @pytest.fixture def ingest_repo(): return InMemoryIngestJobRepository() class TestInMemoryIngestJobRepository: """导入任务仓储.""" def test_create_and_get(self, ingest_repo): job = IngestJob( id="ingest_1", project_id="p1", library_id="lib1", storage_key="key1", status="pending", ) ingest_repo.create(job) found = ingest_repo.get("ingest_1") assert found is not None assert found.id == "ingest_1" assert found.status == "pending" def test_get_not_found(self, ingest_repo): assert ingest_repo.get("nonexistent") is None def test_update(self, ingest_repo): job = IngestJob( id="ingest_1", project_id="p1", library_id="lib1", storage_key="key1", status="pending", ) ingest_repo.create(job) job.status = "completed" ingest_repo.update(job) found = ingest_repo.get("ingest_1") assert found.status == "completed" def test_update_nonexistent_creates(self, ingest_repo): job = IngestJob( id="new_ingest", project_id="p1", library_id="lib1", storage_key="key1", status="running", ) ingest_repo.update(job) found = ingest_repo.get("new_ingest") assert found is not None