feat: package docker deployment and publish flow
This commit is contained in:
103
tests/test_song_detect_retry_policy.py
Normal file
103
tests/test_song_detect_retry_policy.py
Normal file
@ -0,0 +1,103 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import unittest
|
||||
from types import SimpleNamespace
|
||||
|
||||
from biliup_next.app.retry_meta import retry_meta_for_step
|
||||
from biliup_next.app.task_engine import next_runnable_step
|
||||
from biliup_next.app.task_policies import resolve_failure
|
||||
from biliup_next.core.errors import ModuleError
|
||||
from biliup_next.core.models import TaskStep
|
||||
from biliup_next.modules.song_detect.providers.qwen_cli import QwenCliSongDetector
|
||||
|
||||
|
||||
class _Repo:
|
||||
def __init__(self) -> None:
|
||||
self.steps = [TaskStep(None, "task-1", "song_detect", "running", None, None, 0, None, None)]
|
||||
self.step_updates: list[tuple] = []
|
||||
self.task_updates: list[tuple] = []
|
||||
|
||||
def list_steps(self, task_id: str): # noqa: ANN001
|
||||
return list(self.steps)
|
||||
|
||||
def get_task(self, task_id: str): # noqa: ANN001
|
||||
return SimpleNamespace(id=task_id, status="running")
|
||||
|
||||
def update_step_status(self, task_id: str, step_name: str, status: str, **kwargs) -> None: # noqa: ANN001
|
||||
self.step_updates.append((task_id, step_name, status, kwargs))
|
||||
self.steps = [
|
||||
TaskStep(
|
||||
None,
|
||||
task_id,
|
||||
step_name,
|
||||
status,
|
||||
kwargs.get("error_code"),
|
||||
kwargs.get("error_message"),
|
||||
kwargs.get("retry_count", 0),
|
||||
kwargs.get("started_at"),
|
||||
kwargs.get("finished_at"),
|
||||
)
|
||||
]
|
||||
|
||||
def update_task_status(self, task_id: str, status: str, updated_at: str) -> None:
|
||||
self.task_updates.append((task_id, status, updated_at))
|
||||
|
||||
|
||||
class SongDetectRetryPolicyTests(unittest.TestCase):
|
||||
def test_retry_meta_reports_wait_window_for_song_detect(self) -> None:
|
||||
step = TaskStep(None, "task-1", "song_detect", "failed_retryable", "ERR", "boom", 1, None, "2099-01-01T00:00:00+00:00")
|
||||
|
||||
payload = retry_meta_for_step(step, {"song_detect": {"retry_schedule_minutes": [10]}})
|
||||
|
||||
self.assertIsNotNone(payload)
|
||||
self.assertFalse(payload["retry_due"])
|
||||
self.assertEqual(payload["retry_wait_seconds"], 600)
|
||||
|
||||
def test_next_runnable_step_waits_for_retryable_song_detect(self) -> None:
|
||||
task = SimpleNamespace(id="task-1", status="failed_retryable")
|
||||
steps = {
|
||||
"song_detect": TaskStep(None, "task-1", "song_detect", "failed_retryable", "ERR", "boom", 1, None, "2099-01-01T00:00:00+00:00"),
|
||||
}
|
||||
state = {
|
||||
"settings": {
|
||||
"transcribe": {},
|
||||
"song_detect": {"retry_schedule_minutes": [10]},
|
||||
"comment": {"enabled": True},
|
||||
"collection": {"enabled": True},
|
||||
"paths": {},
|
||||
"publish": {},
|
||||
}
|
||||
}
|
||||
|
||||
step_name, waiting_payload = next_runnable_step(task, steps, state)
|
||||
|
||||
self.assertIsNone(step_name)
|
||||
self.assertIsNotNone(waiting_payload)
|
||||
self.assertEqual(waiting_payload["step"], "song_detect")
|
||||
|
||||
def test_resolve_failure_adds_song_detect_retry_delay(self) -> None:
|
||||
repo = _Repo()
|
||||
task = SimpleNamespace(id="task-1", status="running")
|
||||
state = {
|
||||
"settings": {
|
||||
"transcribe": {},
|
||||
"song_detect": {"retry_schedule_minutes": [5, 10]},
|
||||
"publish": {},
|
||||
"comment": {},
|
||||
"paths": {},
|
||||
"collection": {"enabled": True},
|
||||
}
|
||||
}
|
||||
|
||||
result = resolve_failure(task, repo, state, ModuleError(code="SONG_DETECT_FAILED", message="boom", retryable=True))
|
||||
|
||||
self.assertEqual(result["payload"]["retry_status"], "failed_retryable")
|
||||
self.assertEqual(result["payload"]["next_retry_delay_seconds"], 300)
|
||||
|
||||
def test_qwen_auth_errors_are_not_retryable(self) -> None:
|
||||
self.assertTrue(QwenCliSongDetector._is_auth_error("[API Error: 401 invalid access token or token expired]"))
|
||||
self.assertFalse(QwenCliSongDetector._is_auth_error("temporary network failure"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user