103 lines
5.0 KiB
Python
103 lines
5.0 KiB
Python
from __future__ import annotations
|
|
|
|
import ast
|
|
import asyncio
|
|
import json
|
|
import unittest
|
|
from unittest.mock import AsyncMock, patch
|
|
|
|
import web
|
|
|
|
|
|
class WebDynamicProcessesTests(unittest.TestCase):
|
|
def test_process_monitor_entries_include_saved_youtube_pro_channels(self) -> None:
|
|
channels = [{"id": "lane1", "name": "Lane 1", "pm2Name": "youtube2__lane1"}]
|
|
with patch("web.get_youtube_pro_channels", return_value=channels):
|
|
entries = web.process_monitor_entries()
|
|
|
|
pm2_names = {row["pm2"] for row in entries}
|
|
self.assertIn("youtube2__lane1", pm2_names)
|
|
|
|
def test_process_monitor_entries_default_pm2_name_when_missing(self) -> None:
|
|
channels = [{"id": "lane2", "name": "Lane 2"}]
|
|
with patch("web.get_youtube_pro_channels", return_value=channels):
|
|
entries = web.process_monitor_entries()
|
|
|
|
pm2_names = {row["pm2"] for row in entries}
|
|
self.assertIn("youtube2__lane2", pm2_names)
|
|
|
|
def test_script_for_pm2_or_pro_accepts_custom_saved_pm2_name(self) -> None:
|
|
channels = [{"id": "lane3", "name": "Lane 3", "pm2Name": "custom-lane-three"}]
|
|
with patch("web.get_youtube_pro_channels", return_value=channels):
|
|
resolved = web.script_for_pm2_or_pro("custom-lane-three")
|
|
|
|
self.assertEqual(resolved, "youtube.py")
|
|
|
|
def test_process_monitor_entries_overlay_static_youtube_label_for_lane_one(self) -> None:
|
|
channels = [{"id": "lane1", "name": "Lane 1", "pm2Name": "youtube"}]
|
|
with patch("web.get_youtube_pro_channels", return_value=channels):
|
|
entries = web.process_monitor_entries()
|
|
|
|
youtube_row = next(row for row in entries if row["pm2"] == "youtube")
|
|
self.assertEqual(youtube_row["label"], "YouTube Pro \u00b7 Lane 1")
|
|
|
|
def test_process_monitor_entries_do_not_duplicate_static_pm2_rows(self) -> None:
|
|
channels = [
|
|
{"id": "lane1", "name": "Lane 1", "pm2Name": "youtube"},
|
|
{"id": "lane2", "name": "Lane 2", "pm2Name": "youtube2__lane2"},
|
|
]
|
|
with patch("web.get_youtube_pro_channels", return_value=channels):
|
|
entries = web.process_monitor_entries()
|
|
|
|
self.assertEqual(sum(1 for row in entries if row["pm2"] == "youtube"), 1)
|
|
self.assertEqual(sum(1 for row in entries if row["pm2"] == "youtube2__lane2"), 1)
|
|
|
|
def test_web_module_does_not_repeat_process_entry_function_defs(self) -> None:
|
|
tree = ast.parse((web.BASE_DIR / "web.py").read_text(encoding="utf-8"))
|
|
defs: dict[str, list[int]] = {}
|
|
for node in tree.body:
|
|
if isinstance(node, ast.FunctionDef):
|
|
defs.setdefault(node.name, []).append(node.lineno)
|
|
|
|
self.assertEqual(len(defs.get("youtube_pro_process_entries", [])), 1)
|
|
self.assertEqual(len(defs.get("process_monitor_entries", [])), 1)
|
|
|
|
def test_status_marks_local_saved_process_as_configured_when_not_running(self) -> None:
|
|
original_use_pm2 = web.process_backend._use_pm2
|
|
web.process_backend._use_pm2 = False
|
|
try:
|
|
with patch.object(web.process_backend, "full_status_raw", AsyncMock(return_value="local table")):
|
|
with patch("web.get_process_info", AsyncMock(return_value={"process_status": "not_found", "out_path": None, "err_path": None})):
|
|
with patch("web.read_log_path_normalized", AsyncMock(return_value="")):
|
|
with patch.object(web.process_backend, "live_ffmpeg_pids", AsyncMock(return_value=[])):
|
|
response = asyncio.run(web.status("youtube"))
|
|
finally:
|
|
web.process_backend._use_pm2 = original_use_pm2
|
|
|
|
payload = json.loads(response.body)
|
|
self.assertEqual(payload["process_status"], "configured")
|
|
self.assertEqual(payload["business_status"], "ready")
|
|
self.assertIn("已在控制台配置", payload["recent_log"])
|
|
self.assertTrue(payload["raw_status"].startswith("进程「youtube」已在控制台配置"))
|
|
|
|
def test_process_monitor_includes_runtime_snapshot_for_local_configured_process(self) -> None:
|
|
original_use_pm2 = web.process_backend._use_pm2
|
|
web.process_backend._use_pm2 = False
|
|
try:
|
|
with patch.object(web.process_backend, "ensure_mode", AsyncMock()):
|
|
with patch("web.get_process_info", AsyncMock(return_value={"process_status": "not_found", "out_path": None, "err_path": None})):
|
|
with patch("web.read_log_path_normalized", AsyncMock(return_value="")):
|
|
with patch.object(web.process_backend, "live_ffmpeg_pids", AsyncMock(return_value=[])):
|
|
payload = asyncio.run(web.process_monitor())
|
|
finally:
|
|
web.process_backend._use_pm2 = original_use_pm2
|
|
|
|
youtube_row = next(row for row in payload["entries"] if row["pm2"] == "youtube")
|
|
self.assertEqual(youtube_row["process_status"], "configured")
|
|
self.assertEqual(youtube_row["business_status"], "ready")
|
|
self.assertFalse(youtube_row["is_pushing"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|