mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-07-05 23:01:28 +08:00
Handle invalid UTF-8 with replacement decoding
This commit is contained in:
@@ -1,68 +1,62 @@
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
|
||||
import anyio
|
||||
from anyio import Path as AsyncPath
|
||||
|
||||
from app.agent.middleware.jobs import _alist_jobs, filter_active_jobs
|
||||
|
||||
|
||||
class JobsMiddlewareTest(unittest.TestCase):
|
||||
def test_filter_active_jobs_only_keeps_pending_and_in_progress(self):
|
||||
jobs_metadata = [
|
||||
{
|
||||
"id": "pending-job",
|
||||
"name": "待执行任务",
|
||||
"description": "desc",
|
||||
"path": "/tmp/pending/JOB.md",
|
||||
"schedule": "once",
|
||||
"status": "pending",
|
||||
"last_run": None,
|
||||
},
|
||||
{
|
||||
"id": "running-job",
|
||||
"name": "执行中任务",
|
||||
"description": "desc",
|
||||
"path": "/tmp/running/JOB.md",
|
||||
"schedule": "recurring",
|
||||
"status": "in_progress",
|
||||
"last_run": "2026-05-10 10:00",
|
||||
},
|
||||
{
|
||||
"id": "completed-recurring-job",
|
||||
"name": "已完成循环任务",
|
||||
"description": "desc",
|
||||
"path": "/tmp/completed/JOB.md",
|
||||
"schedule": "recurring",
|
||||
"status": "completed",
|
||||
"last_run": "2026-05-10 11:00",
|
||||
},
|
||||
{
|
||||
"id": "cancelled-job",
|
||||
"name": "已取消任务",
|
||||
"description": "desc",
|
||||
"path": "/tmp/cancelled/JOB.md",
|
||||
"schedule": "once",
|
||||
"status": "cancelled",
|
||||
"last_run": None,
|
||||
},
|
||||
]
|
||||
def test_filter_active_jobs_only_keeps_pending_and_in_progress():
|
||||
"""筛选任务时只保留待执行和执行中的任务。"""
|
||||
jobs_metadata = [
|
||||
{
|
||||
"id": "pending-job",
|
||||
"name": "待执行任务",
|
||||
"description": "desc",
|
||||
"path": "/tmp/pending/JOB.md",
|
||||
"schedule": "once",
|
||||
"status": "pending",
|
||||
"last_run": None,
|
||||
},
|
||||
{
|
||||
"id": "running-job",
|
||||
"name": "执行中任务",
|
||||
"description": "desc",
|
||||
"path": "/tmp/running/JOB.md",
|
||||
"schedule": "recurring",
|
||||
"status": "in_progress",
|
||||
"last_run": "2026-05-10 10:00",
|
||||
},
|
||||
{
|
||||
"id": "completed-recurring-job",
|
||||
"name": "已完成循环任务",
|
||||
"description": "desc",
|
||||
"path": "/tmp/completed/JOB.md",
|
||||
"schedule": "recurring",
|
||||
"status": "completed",
|
||||
"last_run": "2026-05-10 11:00",
|
||||
},
|
||||
{
|
||||
"id": "cancelled-job",
|
||||
"name": "已取消任务",
|
||||
"description": "desc",
|
||||
"path": "/tmp/cancelled/JOB.md",
|
||||
"schedule": "once",
|
||||
"status": "cancelled",
|
||||
"last_run": None,
|
||||
},
|
||||
]
|
||||
|
||||
active_job_ids = [job["id"] for job in filter_active_jobs(jobs_metadata)]
|
||||
active_job_ids = [job["id"] for job in filter_active_jobs(jobs_metadata)]
|
||||
|
||||
self.assertEqual(["pending-job", "running-job"], active_job_ids)
|
||||
assert active_job_ids == ["pending-job", "running-job"]
|
||||
|
||||
|
||||
class JobsMiddlewareAsyncTest(unittest.IsolatedAsyncioTestCase):
|
||||
async def test_alist_jobs_sorts_job_directories_by_name(self):
|
||||
with tempfile.TemporaryDirectory() as tempdir:
|
||||
root = Path(tempdir)
|
||||
|
||||
for job_id in ("z-job", "a-job", "m-job"):
|
||||
job_dir = root / job_id
|
||||
job_dir.mkdir()
|
||||
(job_dir / "JOB.md").write_text(
|
||||
f"""---
|
||||
def test_alist_jobs_sorts_job_directories_by_name(tmp_path):
|
||||
"""加载任务元数据时按任务目录名稳定排序。"""
|
||||
for job_id in ("z-job", "a-job", "m-job"):
|
||||
job_dir = tmp_path / job_id
|
||||
job_dir.mkdir()
|
||||
(job_dir / "JOB.md").write_text(
|
||||
f"""---
|
||||
name: {job_id}
|
||||
description: test
|
||||
schedule: once
|
||||
@@ -70,9 +64,30 @@ status: pending
|
||||
---
|
||||
# {job_id}
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
jobs = await _alist_jobs(AsyncPath(str(root)))
|
||||
jobs = anyio.run(_alist_jobs, AsyncPath(str(tmp_path)))
|
||||
|
||||
self.assertEqual(["a-job", "m-job", "z-job"], [job["id"] for job in jobs])
|
||||
assert [job["id"] for job in jobs] == ["a-job", "m-job", "z-job"]
|
||||
|
||||
|
||||
def test_alist_jobs_tolerates_invalid_utf8_bytes(tmp_path):
|
||||
"""加载任务元数据时非法 UTF-8 字节不应中断整个 Agent。"""
|
||||
job_dir = tmp_path / "broken-job"
|
||||
job_dir.mkdir()
|
||||
(job_dir / "JOB.md").write_bytes(
|
||||
b"""---
|
||||
name: broken-job
|
||||
description: test
|
||||
schedule: once
|
||||
status: pending
|
||||
---
|
||||
# broken-job
|
||||
\x90
|
||||
"""
|
||||
)
|
||||
|
||||
jobs = anyio.run(_alist_jobs, AsyncPath(str(tmp_path)))
|
||||
|
||||
assert [job["id"] for job in jobs] == ["broken-job"]
|
||||
|
||||
Reference in New Issue
Block a user