style: normalize python formatting gates
This commit is contained in:
+108
-72
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
API 集成测试
|
||||
"""
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
@@ -11,130 +12,165 @@ client = TestClient(app)
|
||||
|
||||
class TestAuthAPI:
|
||||
"""认证 API 集成测试"""
|
||||
|
||||
|
||||
def test_register_success(self):
|
||||
"""测试注册成功"""
|
||||
response = client.post("/api/v1/auth/register", json={
|
||||
"email": "test@example.com",
|
||||
"password": "SecurePass123",
|
||||
"username": "testuser",
|
||||
"display_name": "Test User",
|
||||
})
|
||||
|
||||
response = client.post(
|
||||
"/api/v1/auth/register",
|
||||
json={
|
||||
"email": "test@example.com",
|
||||
"password": "SecurePass123",
|
||||
"username": "testuser",
|
||||
"display_name": "Test User",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
data = response.json()
|
||||
assert data["email"] == "test@example.com"
|
||||
assert data["username"] == "testuser"
|
||||
assert "user_id" in data
|
||||
|
||||
|
||||
def test_register_duplicate_email(self):
|
||||
"""测试重复邮箱注册"""
|
||||
# 先注册一个用户
|
||||
client.post("/api/v1/auth/register", json={
|
||||
"email": "duplicate@example.com",
|
||||
"password": "SecurePass123",
|
||||
"username": "user1",
|
||||
"display_name": "User 1",
|
||||
})
|
||||
|
||||
client.post(
|
||||
"/api/v1/auth/register",
|
||||
json={
|
||||
"email": "duplicate@example.com",
|
||||
"password": "SecurePass123",
|
||||
"username": "user1",
|
||||
"display_name": "User 1",
|
||||
},
|
||||
)
|
||||
|
||||
# 尝试用相同邮箱再次注册
|
||||
response = client.post("/api/v1/auth/register", json={
|
||||
"email": "duplicate@example.com",
|
||||
"password": "SecurePass123",
|
||||
"username": "user2",
|
||||
"display_name": "User 2",
|
||||
})
|
||||
|
||||
response = client.post(
|
||||
"/api/v1/auth/register",
|
||||
json={
|
||||
"email": "duplicate@example.com",
|
||||
"password": "SecurePass123",
|
||||
"username": "user2",
|
||||
"display_name": "User 2",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
assert "already registered" in response.json()["detail"].lower()
|
||||
|
||||
|
||||
def test_login_success(self):
|
||||
"""测试登录成功"""
|
||||
# 先注册
|
||||
client.post("/api/v1/auth/register", json={
|
||||
"email": "login@example.com",
|
||||
"password": "SecurePass123",
|
||||
"username": "loginuser",
|
||||
"display_name": "Login User",
|
||||
})
|
||||
|
||||
client.post(
|
||||
"/api/v1/auth/register",
|
||||
json={
|
||||
"email": "login@example.com",
|
||||
"password": "SecurePass123",
|
||||
"username": "loginuser",
|
||||
"display_name": "Login User",
|
||||
},
|
||||
)
|
||||
|
||||
# 登录
|
||||
response = client.post("/api/v1/auth/login", json={
|
||||
"email": "login@example.com",
|
||||
"password": "SecurePass123",
|
||||
})
|
||||
|
||||
response = client.post(
|
||||
"/api/v1/auth/login",
|
||||
json={
|
||||
"email": "login@example.com",
|
||||
"password": "SecurePass123",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert "access_token" in data
|
||||
assert "refresh_token" in data
|
||||
assert data["token_type"] == "bearer"
|
||||
|
||||
|
||||
def test_login_wrong_password(self):
|
||||
"""测试密码错误"""
|
||||
response = client.post("/api/v1/auth/login", json={
|
||||
"email": "login@example.com",
|
||||
"password": "WrongPassword123",
|
||||
})
|
||||
|
||||
response = client.post(
|
||||
"/api/v1/auth/login",
|
||||
json={
|
||||
"email": "login@example.com",
|
||||
"password": "WrongPassword123",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
class TestWorkspaceAPI:
|
||||
"""工作空间 API 集成测试"""
|
||||
|
||||
|
||||
def setup_method(self):
|
||||
"""每个测试前的准备"""
|
||||
# 注册并登录,获取 token
|
||||
client.post("/api/v1/auth/register", json={
|
||||
"email": "workspace@example.com",
|
||||
"password": "SecurePass123",
|
||||
"username": "workspaceuser",
|
||||
"display_name": "Workspace User",
|
||||
})
|
||||
|
||||
response = client.post("/api/v1/auth/login", json={
|
||||
"email": "workspace@example.com",
|
||||
"password": "SecurePass123",
|
||||
})
|
||||
|
||||
client.post(
|
||||
"/api/v1/auth/register",
|
||||
json={
|
||||
"email": "workspace@example.com",
|
||||
"password": "SecurePass123",
|
||||
"username": "workspaceuser",
|
||||
"display_name": "Workspace User",
|
||||
},
|
||||
)
|
||||
|
||||
response = client.post(
|
||||
"/api/v1/auth/login",
|
||||
json={
|
||||
"email": "workspace@example.com",
|
||||
"password": "SecurePass123",
|
||||
},
|
||||
)
|
||||
|
||||
self.token = response.json()["access_token"]
|
||||
self.headers = {"Authorization": f"Bearer {self.token}"}
|
||||
|
||||
|
||||
def test_create_workspace(self):
|
||||
"""测试创建工作空间"""
|
||||
response = client.post("/api/v1/workspaces", json={
|
||||
"name": "My Workspace",
|
||||
"subscription_plan": "free",
|
||||
}, headers=self.headers)
|
||||
|
||||
response = client.post(
|
||||
"/api/v1/workspaces",
|
||||
json={
|
||||
"name": "My Workspace",
|
||||
"subscription_plan": "free",
|
||||
},
|
||||
headers=self.headers,
|
||||
)
|
||||
|
||||
assert response.status_code == 201
|
||||
data = response.json()
|
||||
assert data["name"] == "My Workspace"
|
||||
assert data["subscription_plan"] == "free"
|
||||
assert data["max_projects"] == 3
|
||||
|
||||
|
||||
def test_list_workspaces(self):
|
||||
"""测试获取工作空间列表"""
|
||||
# 创建工作空间
|
||||
client.post("/api/v1/workspaces", json={
|
||||
"name": "Workspace 1",
|
||||
}, headers=self.headers)
|
||||
|
||||
client.post(
|
||||
"/api/v1/workspaces",
|
||||
json={
|
||||
"name": "Workspace 1",
|
||||
},
|
||||
headers=self.headers,
|
||||
)
|
||||
|
||||
# 获取列表
|
||||
response = client.get("/api/v1/workspaces", headers=self.headers)
|
||||
|
||||
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert len(data["workspaces"]) > 0
|
||||
assert data["workspaces"][0]["name"] == "Workspace 1"
|
||||
|
||||
|
||||
def test_create_workspace_unauthorized(self):
|
||||
"""测试未登录创建工作空间"""
|
||||
response = client.post("/api/v1/workspaces", json={
|
||||
"name": "Unauthorized Workspace",
|
||||
})
|
||||
|
||||
response = client.post(
|
||||
"/api/v1/workspaces",
|
||||
json={
|
||||
"name": "Unauthorized Workspace",
|
||||
},
|
||||
)
|
||||
|
||||
assert response.status_code == 403 # FastAPI HTTPBearer 返回 403
|
||||
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@ def test_add_tag_to_asset():
|
||||
storage_key="uploads/abc/video.mp4",
|
||||
mime_type="video/mp4",
|
||||
)
|
||||
|
||||
|
||||
asset.add_tag("风景")
|
||||
asset.add_tag("自然")
|
||||
|
||||
|
||||
assert len(asset.tags) == 2
|
||||
assert "风景" in asset.tags
|
||||
assert "自然" in asset.tags
|
||||
@@ -32,10 +32,10 @@ def test_add_duplicate_tag_should_ignore():
|
||||
storage_key="uploads/abc/video.mp4",
|
||||
mime_type="video/mp4",
|
||||
)
|
||||
|
||||
|
||||
asset.add_tag("风景")
|
||||
asset.add_tag("风景") # 重复
|
||||
|
||||
|
||||
assert len(asset.tags) == 1
|
||||
assert asset.tags.count("风景") == 1
|
||||
|
||||
@@ -50,10 +50,10 @@ def test_add_empty_tag_should_fail():
|
||||
storage_key="uploads/abc/video.mp4",
|
||||
mime_type="video/mp4",
|
||||
)
|
||||
|
||||
|
||||
with pytest.raises(ValueError, match="标签不能为空"):
|
||||
asset.add_tag("")
|
||||
|
||||
|
||||
with pytest.raises(ValueError, match="标签不能为空"):
|
||||
asset.add_tag(" ") # 仅空格
|
||||
|
||||
@@ -68,12 +68,12 @@ def test_remove_tag_from_asset():
|
||||
storage_key="uploads/abc/video.mp4",
|
||||
mime_type="video/mp4",
|
||||
)
|
||||
|
||||
|
||||
asset.add_tag("风景")
|
||||
asset.add_tag("自然")
|
||||
|
||||
|
||||
asset.remove_tag("风景")
|
||||
|
||||
|
||||
assert len(asset.tags) == 1
|
||||
assert "风景" not in asset.tags
|
||||
assert "自然" in asset.tags
|
||||
@@ -89,11 +89,11 @@ def test_remove_nonexistent_tag_should_be_idempotent():
|
||||
storage_key="uploads/abc/video.mp4",
|
||||
mime_type="video/mp4",
|
||||
)
|
||||
|
||||
|
||||
asset.add_tag("风景")
|
||||
|
||||
|
||||
# 删除不存在的标签,不应报错
|
||||
asset.remove_tag("不存在的标签")
|
||||
|
||||
|
||||
assert len(asset.tags) == 1
|
||||
assert "风景" in asset.tags
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
from packages.application import SubmitClassificationJobCommand, SubmitClassificationJobUseCase
|
||||
from packages.adapters.in_memory import InMemoryClassificationJobRepository
|
||||
from packages.domain import ClassificationJobStatus, AssetClassification
|
||||
from packages.application import (
|
||||
SubmitClassificationJobCommand,
|
||||
SubmitClassificationJobUseCase,
|
||||
)
|
||||
from packages.domain import AssetClassification, ClassificationJobStatus
|
||||
|
||||
|
||||
def simulate_classify_asset(job_id: str, job_repo: InMemoryClassificationJobRepository) -> dict:
|
||||
@@ -8,24 +11,24 @@ def simulate_classify_asset(job_id: str, job_repo: InMemoryClassificationJobRepo
|
||||
job = job_repo.get(job_id)
|
||||
if job is None:
|
||||
return {"status": "failed", "error": "job not found"}
|
||||
|
||||
|
||||
try:
|
||||
# Update job status to PROCESSING
|
||||
job.status = ClassificationJobStatus.PROCESSING
|
||||
job_repo.update(job)
|
||||
|
||||
|
||||
# Mock classification
|
||||
asset_id_hash = sum(ord(c) for c in job.asset_id)
|
||||
classifications = list(AssetClassification)
|
||||
classification = classifications[asset_id_hash % len(classifications)]
|
||||
confidence = 0.85
|
||||
|
||||
|
||||
# Update job status to COMPLETED
|
||||
job.status = ClassificationJobStatus.COMPLETED
|
||||
job.classification = classification.value
|
||||
job.confidence = confidence
|
||||
job_repo.update(job)
|
||||
|
||||
|
||||
return {
|
||||
"status": "completed",
|
||||
"job_id": job.id,
|
||||
@@ -37,7 +40,7 @@ def simulate_classify_asset(job_id: str, job_repo: InMemoryClassificationJobRepo
|
||||
job.status = ClassificationJobStatus.FAILED
|
||||
job.error_message = str(e)
|
||||
job_repo.update(job)
|
||||
|
||||
|
||||
return {
|
||||
"status": "failed",
|
||||
"job_id": job.id,
|
||||
@@ -48,7 +51,7 @@ def simulate_classify_asset(job_id: str, job_repo: InMemoryClassificationJobRepo
|
||||
def test_classification_pipeline():
|
||||
"""Test the full classification pipeline: submit job -> worker processes -> result."""
|
||||
job_repo = InMemoryClassificationJobRepository()
|
||||
|
||||
|
||||
# Submit classification job
|
||||
use_case = SubmitClassificationJobUseCase(job_repo)
|
||||
job = use_case.execute(
|
||||
@@ -58,18 +61,18 @@ def test_classification_pipeline():
|
||||
asset_id="asset-123",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
assert job.status == ClassificationJobStatus.PENDING
|
||||
assert job.classification == ""
|
||||
assert job.confidence == 0.0
|
||||
|
||||
|
||||
# Simulate worker task execution
|
||||
result = simulate_classify_asset(job.id, job_repo)
|
||||
|
||||
|
||||
assert result["status"] == "completed"
|
||||
assert "classification" in result
|
||||
assert "confidence" in result
|
||||
|
||||
|
||||
# Verify job was updated
|
||||
updated_job = job_repo.get(job.id)
|
||||
assert updated_job is not None
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from packages.application import CreateGenerationTaskCommand, CreateGenerationTaskUseCase, GetGeneratedVideoDownloadUrlUseCase
|
||||
from packages.application import (
|
||||
CreateGenerationTaskCommand,
|
||||
CreateGenerationTaskUseCase,
|
||||
GetGeneratedVideoDownloadUrlUseCase,
|
||||
)
|
||||
from packages.domain import GeneratedVideo, GenerationTaskStatus
|
||||
|
||||
|
||||
@@ -41,7 +45,11 @@ class DummyGeneratedVideoRepository:
|
||||
return [video for video in self.items.values() if video.generation_task_id == generation_task_id]
|
||||
|
||||
|
||||
def simulate_generate_video(task_id: str, task_repo: DummyGenerationTaskRepository, video_repo: DummyGeneratedVideoRepository) -> dict:
|
||||
def simulate_generate_video(
|
||||
task_id: str,
|
||||
task_repo: DummyGenerationTaskRepository,
|
||||
video_repo: DummyGeneratedVideoRepository,
|
||||
) -> dict:
|
||||
task = task_repo.get(task_id)
|
||||
if task is None:
|
||||
return {"status": "failed", "error": "task not found"}
|
||||
@@ -75,7 +83,12 @@ def simulate_generate_video(task_id: str, task_repo: DummyGenerationTaskReposito
|
||||
task.completed_at = datetime.now(timezone.utc)
|
||||
task_repo.update(task)
|
||||
|
||||
return {"status": "completed", "task_id": task.id, "video_id": video.id, "file_url": file_url}
|
||||
return {
|
||||
"status": "completed",
|
||||
"task_id": task.id,
|
||||
"video_id": video.id,
|
||||
"file_url": file_url,
|
||||
}
|
||||
|
||||
|
||||
def test_create_generation_task_smoke():
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
from packages.adapters.in_memory import (
|
||||
InMemoryAssetRepository,
|
||||
InMemoryIngestJobRepository,
|
||||
)
|
||||
from packages.application import SubmitIngestJobCommand, SubmitIngestJobUseCase
|
||||
from packages.adapters.in_memory import InMemoryAssetRepository, InMemoryIngestJobRepository
|
||||
from packages.domain import Asset, IngestJob, IngestJobStatus
|
||||
|
||||
|
||||
def simulate_ingest_asset(job_id: str, job_repo: InMemoryIngestJobRepository, asset_repo: InMemoryAssetRepository) -> dict:
|
||||
def simulate_ingest_asset(
|
||||
job_id: str,
|
||||
job_repo: InMemoryIngestJobRepository,
|
||||
asset_repo: InMemoryAssetRepository,
|
||||
) -> dict:
|
||||
"""
|
||||
Simulate ingest asset logic without Celery.
|
||||
This is the core business logic that would run inside the worker task.
|
||||
@@ -11,12 +18,12 @@ def simulate_ingest_asset(job_id: str, job_repo: InMemoryIngestJobRepository, as
|
||||
job = job_repo.get(job_id)
|
||||
if job is None:
|
||||
return {"status": "failed", "error": "job not found"}
|
||||
|
||||
|
||||
try:
|
||||
# Update job status to PROCESSING
|
||||
job.status = IngestJobStatus.PROCESSING
|
||||
job_repo.update(job)
|
||||
|
||||
|
||||
# Mock metadata extraction
|
||||
mime_type = "video/mp4" if job.storage_key.endswith(".mp4") else "image/jpeg"
|
||||
metadata = {
|
||||
@@ -25,10 +32,10 @@ def simulate_ingest_asset(job_id: str, job_repo: InMemoryIngestJobRepository, as
|
||||
"height": 1080,
|
||||
"size_bytes": 1024000,
|
||||
}
|
||||
|
||||
|
||||
# Extract filename from storage_key
|
||||
filename = job.storage_key.split("/")[-1]
|
||||
|
||||
|
||||
# Create Asset
|
||||
asset = Asset.create(
|
||||
workspace_id=job.workspace_id,
|
||||
@@ -40,12 +47,12 @@ def simulate_ingest_asset(job_id: str, job_repo: InMemoryIngestJobRepository, as
|
||||
metadata=metadata,
|
||||
)
|
||||
asset_repo.create(asset)
|
||||
|
||||
|
||||
# Update job status to COMPLETED
|
||||
job.status = IngestJobStatus.COMPLETED
|
||||
job.result_asset_id = asset.id
|
||||
job_repo.update(job)
|
||||
|
||||
|
||||
return {
|
||||
"status": "completed",
|
||||
"job_id": job.id,
|
||||
@@ -56,7 +63,7 @@ def simulate_ingest_asset(job_id: str, job_repo: InMemoryIngestJobRepository, as
|
||||
job.status = IngestJobStatus.FAILED
|
||||
job.error_message = str(e)
|
||||
job_repo.update(job)
|
||||
|
||||
|
||||
return {
|
||||
"status": "failed",
|
||||
"job_id": job.id,
|
||||
@@ -68,7 +75,7 @@ def test_ingest_asset_pipeline():
|
||||
"""Test the full ingest pipeline: submit job -> worker processes -> asset created."""
|
||||
job_repo = InMemoryIngestJobRepository()
|
||||
asset_repo = InMemoryAssetRepository()
|
||||
|
||||
|
||||
# Submit ingest job
|
||||
use_case = SubmitIngestJobUseCase(job_repo)
|
||||
job = use_case.execute(
|
||||
@@ -79,22 +86,22 @@ def test_ingest_asset_pipeline():
|
||||
storage_key="uploads/test-video.mp4",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
assert job.status == IngestJobStatus.PENDING
|
||||
assert job.result_asset_id == ""
|
||||
|
||||
|
||||
# Simulate worker task execution
|
||||
result = simulate_ingest_asset(job.id, job_repo, asset_repo)
|
||||
|
||||
|
||||
assert result["status"] == "completed"
|
||||
assert "asset_id" in result
|
||||
|
||||
|
||||
# Verify job was updated
|
||||
updated_job = job_repo.get(job.id)
|
||||
assert updated_job is not None
|
||||
assert updated_job.status == IngestJobStatus.COMPLETED
|
||||
assert updated_job.result_asset_id != ""
|
||||
|
||||
|
||||
# Verify asset was created
|
||||
assets = asset_repo.list_by_library("lib-1")
|
||||
assert len(assets) == 1
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
"""项目管理功能集成测试"""
|
||||
|
||||
import pytest
|
||||
|
||||
from packages.adapters.in_memory.project_management_repositories import (
|
||||
@@ -23,7 +24,7 @@ def test_create_task():
|
||||
"""测试创建任务"""
|
||||
repo = InMemoryTaskRepository()
|
||||
use_case = CreateTaskUseCase(repo)
|
||||
|
||||
|
||||
task = use_case.execute(
|
||||
project_id="proj_1",
|
||||
workspace_id="ws_1",
|
||||
@@ -31,7 +32,7 @@ def test_create_task():
|
||||
description="实现用户登录功能",
|
||||
priority=TaskPriority.HIGH,
|
||||
)
|
||||
|
||||
|
||||
assert task.id is not None
|
||||
assert task.name == "开发登录功能"
|
||||
assert task.status == TaskStatus.PENDING
|
||||
@@ -43,7 +44,7 @@ def test_list_tasks():
|
||||
"""测试获取任务列表"""
|
||||
repo = InMemoryTaskRepository()
|
||||
create_use_case = CreateTaskUseCase(repo)
|
||||
|
||||
|
||||
# 创建两个任务
|
||||
create_use_case.execute(
|
||||
project_id="proj_1",
|
||||
@@ -55,11 +56,11 @@ def test_list_tasks():
|
||||
workspace_id="ws_1",
|
||||
name="任务2",
|
||||
)
|
||||
|
||||
|
||||
# 查询任务列表
|
||||
list_use_case = ListProjectTasksUseCase(repo)
|
||||
tasks = list_use_case.execute("proj_1")
|
||||
|
||||
|
||||
assert len(tasks) == 2
|
||||
assert tasks[0].name == "任务1"
|
||||
assert tasks[1].name == "任务2"
|
||||
@@ -70,17 +71,17 @@ def test_update_task_status():
|
||||
repo = InMemoryTaskRepository()
|
||||
create_use_case = CreateTaskUseCase(repo)
|
||||
update_use_case = UpdateTaskStatusUseCase(repo)
|
||||
|
||||
|
||||
# 创建任务
|
||||
task = create_use_case.execute(
|
||||
project_id="proj_1",
|
||||
workspace_id="ws_1",
|
||||
name="测试任务",
|
||||
)
|
||||
|
||||
|
||||
# 更新状态为进行中
|
||||
updated_task = update_use_case.execute(task.id, TaskStatus.IN_PROGRESS)
|
||||
|
||||
|
||||
assert updated_task.status == TaskStatus.IN_PROGRESS
|
||||
assert updated_task.actual_start_date is not None
|
||||
|
||||
@@ -90,23 +91,23 @@ def test_update_task_progress():
|
||||
repo = InMemoryTaskRepository()
|
||||
create_use_case = CreateTaskUseCase(repo)
|
||||
progress_use_case = UpdateTaskProgressUseCase(repo)
|
||||
|
||||
|
||||
# 创建任务
|
||||
task = create_use_case.execute(
|
||||
project_id="proj_1",
|
||||
workspace_id="ws_1",
|
||||
name="测试任务",
|
||||
)
|
||||
|
||||
|
||||
# 更新进度到 50%
|
||||
updated_task = progress_use_case.execute(task.id, 50.0)
|
||||
|
||||
|
||||
assert updated_task.progress == 50.0
|
||||
assert updated_task.status == TaskStatus.IN_PROGRESS
|
||||
|
||||
|
||||
# 更新进度到 100%
|
||||
completed_task = progress_use_case.execute(task.id, 100.0)
|
||||
|
||||
|
||||
assert completed_task.progress == 100.0
|
||||
assert completed_task.status == TaskStatus.COMPLETED
|
||||
assert completed_task.actual_end_date is not None
|
||||
@@ -116,14 +117,14 @@ def test_create_milestone():
|
||||
"""测试创建里程碑"""
|
||||
repo = InMemoryMilestoneRepository()
|
||||
use_case = CreateMilestoneUseCase(repo)
|
||||
|
||||
|
||||
milestone = use_case.execute(
|
||||
project_id="proj_1",
|
||||
workspace_id="ws_1",
|
||||
name="V1.0 发布",
|
||||
description="第一个正式版本",
|
||||
)
|
||||
|
||||
|
||||
assert milestone.id is not None
|
||||
assert milestone.name == "V1.0 发布"
|
||||
assert milestone.completed is False
|
||||
@@ -135,7 +136,7 @@ def test_create_and_resolve_issue():
|
||||
create_use_case = CreateTaskIssueUseCase(repo)
|
||||
resolve_use_case = ResolveTaskIssueUseCase(repo)
|
||||
list_use_case = ListTaskIssuesUseCase(repo)
|
||||
|
||||
|
||||
# 创建问题
|
||||
issue = create_use_case.execute(
|
||||
task_id="task_1",
|
||||
@@ -144,17 +145,17 @@ def test_create_and_resolve_issue():
|
||||
title="接口报错",
|
||||
description="调用登录接口返回 500",
|
||||
)
|
||||
|
||||
|
||||
assert issue.id is not None
|
||||
assert issue.title == "接口报错"
|
||||
assert issue.resolved is False
|
||||
|
||||
|
||||
# 解决问题
|
||||
resolved_issue = resolve_use_case.execute(issue.id)
|
||||
|
||||
|
||||
assert resolved_issue.resolved is True
|
||||
assert resolved_issue.resolved_at is not None
|
||||
|
||||
|
||||
# 查询任务问题列表
|
||||
issues = list_use_case.execute("task_1")
|
||||
assert len(issues) == 1
|
||||
@@ -165,14 +166,14 @@ def test_task_hierarchy():
|
||||
"""测试任务层级关系"""
|
||||
repo = InMemoryTaskRepository()
|
||||
create_use_case = CreateTaskUseCase(repo)
|
||||
|
||||
|
||||
# 创建父任务
|
||||
parent_task = create_use_case.execute(
|
||||
project_id="proj_1",
|
||||
workspace_id="ws_1",
|
||||
name="开发用户模块",
|
||||
)
|
||||
|
||||
|
||||
# 创建子任务
|
||||
child_task_1 = create_use_case.execute(
|
||||
project_id="proj_1",
|
||||
@@ -180,17 +181,17 @@ def test_task_hierarchy():
|
||||
name="登录功能",
|
||||
parent_task_id=parent_task.id,
|
||||
)
|
||||
|
||||
|
||||
child_task_2 = create_use_case.execute(
|
||||
project_id="proj_1",
|
||||
workspace_id="ws_1",
|
||||
name="注册功能",
|
||||
parent_task_id=parent_task.id,
|
||||
)
|
||||
|
||||
|
||||
# 查询子任务
|
||||
children = repo.list_by_parent(parent_task.id)
|
||||
|
||||
|
||||
assert len(children) == 2
|
||||
assert children[0].parent_task_id == parent_task.id
|
||||
assert children[1].parent_task_id == parent_task.id
|
||||
@@ -199,11 +200,11 @@ def test_task_hierarchy():
|
||||
def test_get_task_detail():
|
||||
"""测试获取任务详情"""
|
||||
from packages.application.get_task_detail_use_case import GetTaskDetailUseCase
|
||||
|
||||
|
||||
repo = InMemoryTaskRepository()
|
||||
create_use_case = CreateTaskUseCase(repo)
|
||||
get_use_case = GetTaskDetailUseCase(repo)
|
||||
|
||||
|
||||
# 创建任务
|
||||
task = create_use_case.execute(
|
||||
project_id="proj_1",
|
||||
@@ -211,14 +212,14 @@ def test_get_task_detail():
|
||||
name="测试任务",
|
||||
description="这是一个测试任务",
|
||||
)
|
||||
|
||||
|
||||
# 获取详情
|
||||
retrieved_task = get_use_case.execute(task.id)
|
||||
|
||||
|
||||
assert retrieved_task.id == task.id
|
||||
assert retrieved_task.name == "测试任务"
|
||||
assert retrieved_task.description == "这是一个测试任务"
|
||||
|
||||
|
||||
# 测试不存在的任务
|
||||
try:
|
||||
get_use_case.execute("nonexistent_id")
|
||||
@@ -230,11 +231,11 @@ def test_get_task_detail():
|
||||
def test_update_task():
|
||||
"""测试任务基本信息更新"""
|
||||
from packages.application.update_task_use_case import UpdateTaskUseCase
|
||||
|
||||
|
||||
repo = InMemoryTaskRepository()
|
||||
create_use_case = CreateTaskUseCase(repo)
|
||||
update_use_case = UpdateTaskUseCase(repo)
|
||||
|
||||
|
||||
# 创建任务
|
||||
task = create_use_case.execute(
|
||||
project_id="proj_1",
|
||||
@@ -243,7 +244,7 @@ def test_update_task():
|
||||
description="原始描述",
|
||||
priority="low",
|
||||
)
|
||||
|
||||
|
||||
# 更新任务
|
||||
updated_task = update_use_case.execute(
|
||||
task_id=task.id,
|
||||
@@ -251,17 +252,17 @@ def test_update_task():
|
||||
description="更新后的描述",
|
||||
priority="high",
|
||||
)
|
||||
|
||||
|
||||
assert updated_task.name == "更新后的任务"
|
||||
assert updated_task.description == "更新后的描述"
|
||||
assert updated_task.priority == "high"
|
||||
|
||||
|
||||
# 部分更新
|
||||
partial_updated = update_use_case.execute(
|
||||
task_id=task.id,
|
||||
name="又更新了",
|
||||
)
|
||||
|
||||
|
||||
assert partial_updated.name == "又更新了"
|
||||
assert partial_updated.description == "更新后的描述" # 保持不变
|
||||
assert partial_updated.priority == "high" # 保持不变
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
from packages.adapters.in_memory import (
|
||||
InMemoryAssetLibraryRepository,
|
||||
InMemoryAssetRepository,
|
||||
InMemoryIngestJobRepository,
|
||||
InMemoryProjectRepository,
|
||||
)
|
||||
from packages.application import (
|
||||
CreateAssetCommand,
|
||||
CreateAssetLibraryCommand,
|
||||
@@ -11,12 +17,6 @@ from packages.application import (
|
||||
SubmitIngestJobCommand,
|
||||
SubmitIngestJobUseCase,
|
||||
)
|
||||
from packages.adapters.in_memory import (
|
||||
InMemoryAssetLibraryRepository,
|
||||
InMemoryAssetRepository,
|
||||
InMemoryIngestJobRepository,
|
||||
InMemoryProjectRepository,
|
||||
)
|
||||
from packages.domain import AssetLibraryKind, IngestJobStatus
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ from sqlalchemy import create_engine
|
||||
from sqlalchemy.orm import Session, sessionmaker
|
||||
|
||||
from packages.adapters.sqlalchemy_impl.models import Base
|
||||
from packages.adapters.sqlalchemy_impl.project_repository import SQLAlchemyProjectRepository
|
||||
from packages.adapters.sqlalchemy_impl.project_repository import (
|
||||
SQLAlchemyProjectRepository,
|
||||
)
|
||||
from packages.application import CreateProjectCommand, CreateProjectUseCase
|
||||
|
||||
|
||||
@@ -13,12 +15,12 @@ def test_sqlalchemy_project_repository():
|
||||
Base.metadata.create_all(engine)
|
||||
SessionLocal = sessionmaker(bind=engine)
|
||||
session: Session = SessionLocal()
|
||||
|
||||
|
||||
try:
|
||||
# Create repository and use case
|
||||
repository = SQLAlchemyProjectRepository(session)
|
||||
use_case = CreateProjectUseCase(repository)
|
||||
|
||||
|
||||
# Create project
|
||||
project = use_case.execute(
|
||||
CreateProjectCommand(
|
||||
@@ -27,10 +29,10 @@ def test_sqlalchemy_project_repository():
|
||||
description="Test description",
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
assert project.name == "Test Project"
|
||||
assert project.workspace_id == "ws-1"
|
||||
|
||||
|
||||
# List projects
|
||||
projects = repository.list_by_workspace("ws-1")
|
||||
assert len(projects) == 1
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
from packages.adapters.in_memory import (
|
||||
InMemoryAssetRepository,
|
||||
InMemoryIngestJobRepository,
|
||||
)
|
||||
from packages.application import SubmitIngestJobCommand, SubmitIngestJobUseCase
|
||||
from packages.adapters.in_memory import InMemoryAssetRepository, InMemoryIngestJobRepository
|
||||
from packages.domain import IngestJobStatus
|
||||
|
||||
|
||||
@@ -13,11 +16,12 @@ def simulate_upload_and_ingest(
|
||||
) -> dict:
|
||||
"""Simulate full upload → ingest pipeline."""
|
||||
from uuid import uuid4
|
||||
|
||||
from tests.integration.test_ingest_pipeline import simulate_ingest_asset
|
||||
|
||||
|
||||
# Mock storage: generate storage_key
|
||||
storage_key = f"uploads/{uuid4().hex[:8]}/{filename}"
|
||||
|
||||
|
||||
# Submit ingest job
|
||||
use_case = SubmitIngestJobUseCase(job_repo)
|
||||
job = use_case.execute(
|
||||
@@ -28,10 +32,10 @@ def simulate_upload_and_ingest(
|
||||
storage_key=storage_key,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
# Simulate worker task
|
||||
result = simulate_ingest_asset(job.id, job_repo, asset_repo)
|
||||
|
||||
|
||||
return {
|
||||
"storage_key": storage_key,
|
||||
"job_id": job.id,
|
||||
@@ -43,7 +47,7 @@ def test_upload_to_asset_full_pipeline():
|
||||
"""Test full pipeline: upload → storage → ingest job → worker → asset created."""
|
||||
job_repo = InMemoryIngestJobRepository()
|
||||
asset_repo = InMemoryAssetRepository()
|
||||
|
||||
|
||||
# Simulate upload
|
||||
result = simulate_upload_and_ingest(
|
||||
workspace_id="ws-1",
|
||||
@@ -53,17 +57,17 @@ def test_upload_to_asset_full_pipeline():
|
||||
job_repo=job_repo,
|
||||
asset_repo=asset_repo,
|
||||
)
|
||||
|
||||
|
||||
assert "storage_key" in result
|
||||
assert result["storage_key"].endswith("demo-video.mp4")
|
||||
assert result["worker_result"]["status"] == "completed"
|
||||
|
||||
|
||||
# Verify job was completed
|
||||
job = job_repo.get(result["job_id"])
|
||||
assert job is not None
|
||||
assert job.status == IngestJobStatus.COMPLETED
|
||||
assert job.result_asset_id != ""
|
||||
|
||||
|
||||
# Verify asset was created
|
||||
assets = asset_repo.list_by_library("lib-1")
|
||||
assert len(assets) == 1
|
||||
|
||||
Reference in New Issue
Block a user