from datetime import datetime, timezone from packages.application import ( CreateGenerationTaskCommand, CreateGenerationTaskUseCase, GetGeneratedVideoDownloadUrlUseCase, ) from packages.domain import GeneratedVideo, GenerationTaskStatus class DummyGenerationTaskRepository: def __init__(self): self.items = {} def create(self, task): self.items[task.id] = task return task def get(self, task_id): return self.items.get(task_id) def list_by_project(self, project_id): return [task for task in self.items.values() if task.project_id == project_id] def update(self, task): self.items[task.id] = task return task class DummyGeneratedVideoRepository: def __init__(self): self.items = {} def create(self, video): self.items[video.id] = video return video def get(self, video_id): return self.items.get(video_id) def list_by_project(self, project_id): return [video for video in self.items.values() if video.project_id == project_id] def list_by_generation_task(self, generation_task_id): 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: task = task_repo.get(task_id) if task is None: return {"status": "failed", "error": "task not found"} task.status = GenerationTaskStatus.RUNNING task.progress = 20.0 task.started_at = task.started_at or datetime.now(timezone.utc) task_repo.update(task) file_url = f"/projects/{task.project_id}/generated/{task.id}/{task.id}.mp4" video = GeneratedVideo.create( project_id=task.project_id, generation_task_id=task.id, name=f"{task.id}.mp4", file_url=file_url, file_size=2048, duration=12.5, width=1920, height=1080, fps=25.0, ) video_repo.create(video) task.status = GenerationTaskStatus.COMPLETED task.progress = 100.0 task.result_count = 1 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, } def test_create_generation_task_smoke(): repo = DummyGenerationTaskRepository() use_case = CreateGenerationTaskUseCase(repo) task = use_case.execute( CreateGenerationTaskCommand( project_id="proj-1", asset_library_id="lib-1", strategy_id="str-1", voice_library_id="voice-1", created_by_user_id="user-1", ) ) assert task.project_id == "proj-1" assert task.asset_library_id == "lib-1" assert task.status == GenerationTaskStatus.PENDING assert repo.get(task.id) is not None def test_generation_pipeline_smoke(): task_repo = DummyGenerationTaskRepository() video_repo = DummyGeneratedVideoRepository() use_case = CreateGenerationTaskUseCase(task_repo) task = use_case.execute( CreateGenerationTaskCommand( project_id="proj-1", asset_library_id="lib-1", strategy_id="str-1", voice_library_id="voice-1", created_by_user_id="user-1", ) ) result = simulate_generate_video(task.id, task_repo, video_repo) assert result["status"] == "completed" assert "/projects/proj-1/generated/" in result["file_url"] updated_task = task_repo.get(task.id) assert updated_task is not None assert updated_task.status == GenerationTaskStatus.COMPLETED assert updated_task.result_count == 1 videos = video_repo.list_by_generation_task(task.id) assert len(videos) == 1 assert videos[0].project_id == "proj-1" assert videos[0].generation_task_id == task.id def test_get_generated_video_download_url(): video_repo = DummyGeneratedVideoRepository() video = GeneratedVideo.create( project_id="proj-1", generation_task_id="task-1", name="task-1.mp4", file_url="https://example.invalid/generated/task-1.mp4", file_size=2048, duration=12.5, width=1920, height=1080, fps=25.0, ) video_repo.create(video) use_case = GetGeneratedVideoDownloadUrlUseCase(video_repo) assert use_case.execute(video.id) == "https://example.invalid/generated/task-1.mp4" assert use_case.execute("missing") is None def test_generated_video_download_source_url_is_stable(): video_repo = DummyGeneratedVideoRepository() video = GeneratedVideo.create( project_id="proj-1", generation_task_id="task-2", name="task-2.mp4", file_url="http://localhost:9000/xiaoxia-assets/generated/task-2.mp4", file_size=1024, duration=8.0, width=1280, height=720, fps=25.0, ) video_repo.create(video) use_case = GetGeneratedVideoDownloadUrlUseCase(video_repo) assert use_case.execute(video.id).endswith("/generated/task-2.mp4")