feat: add isolated utility export modes
This commit is contained in:
+108
-2
@@ -14,7 +14,14 @@ from controller.service import ControllerService, ControllerUnavailableError
|
||||
|
||||
|
||||
class FakeControllerService:
|
||||
def __init__(self, *, enqueue_result=None, enqueue_error=None, health=None):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
enqueue_result=None,
|
||||
enqueue_error=None,
|
||||
health=None,
|
||||
export_jobs=None,
|
||||
):
|
||||
self.enqueue_result = enqueue_result or {
|
||||
"status": "queued",
|
||||
"slot": 3,
|
||||
@@ -29,7 +36,9 @@ class FakeControllerService:
|
||||
"router_state": "video",
|
||||
"degraded_reasons": [],
|
||||
}
|
||||
self.export_jobs = list(export_jobs or [])
|
||||
self.enqueue_calls = []
|
||||
self.export_calls = []
|
||||
|
||||
def enqueue_download(self, url, submitter, note):
|
||||
self.enqueue_calls.append((url, submitter, note))
|
||||
@@ -37,6 +46,20 @@ class FakeControllerService:
|
||||
raise self.enqueue_error
|
||||
return dict(self.enqueue_result)
|
||||
|
||||
def enqueue_export(self, url, mode, submitter, note):
|
||||
self.export_calls.append((url, mode, submitter, note))
|
||||
if self.enqueue_error is not None:
|
||||
raise self.enqueue_error
|
||||
return {
|
||||
"kind": "export",
|
||||
"status": "queued",
|
||||
"job_id": "export-job",
|
||||
"mode": mode,
|
||||
}
|
||||
|
||||
def list_export_jobs(self, *, limit=10):
|
||||
return [dict(job) for job in self.export_jobs[:limit]]
|
||||
|
||||
def health(self):
|
||||
return dict(self.health_result)
|
||||
|
||||
@@ -71,11 +94,94 @@ class FlaskFactoryTests(unittest.TestCase):
|
||||
response = self._app(FakeControllerService()).test_client().get("/")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn(b"Submit YouTube Playlist", response.data)
|
||||
self.assertIn(b"Submit YouTube Media", response.data)
|
||||
self.assertIn(b'action="/submit"', response.data)
|
||||
self.assertIn(b'name="url"', response.data)
|
||||
self.assertIn(b'name="submitter"', response.data)
|
||||
self.assertIn(b'name="note"', response.data)
|
||||
self.assertIn(b'name="download_mode"', response.data)
|
||||
self.assertIn(b'value="player_slot" checked', response.data)
|
||||
self.assertIn(b"MP4 Export", response.data)
|
||||
self.assertIn(b"M4A Audio", response.data)
|
||||
self.assertIn(b"MP3 Audio", response.data)
|
||||
|
||||
def test_older_clients_omitting_mode_still_use_player_slot(self):
|
||||
service = FakeControllerService()
|
||||
|
||||
response = self._post(service, submitter=" Alice ")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(
|
||||
service.enqueue_calls,
|
||||
[("https://www.youtube.com/playlist?list=PL1234567890", "Alice", None)],
|
||||
)
|
||||
self.assertEqual(service.export_calls, [])
|
||||
|
||||
def test_each_utility_mode_uses_export_path_without_player_slot(self):
|
||||
for mode, label in (
|
||||
("mp4", b"MP4 Export queued"),
|
||||
("m4a", b"M4A Audio queued"),
|
||||
("mp3", b"MP3 Audio queued"),
|
||||
):
|
||||
with self.subTest(mode=mode):
|
||||
service = FakeControllerService()
|
||||
response = self._post(
|
||||
service,
|
||||
download_mode=mode,
|
||||
submitter="Operator",
|
||||
note="Utility",
|
||||
)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn(label, response.data)
|
||||
self.assertEqual(service.enqueue_calls, [])
|
||||
self.assertEqual(
|
||||
service.export_calls,
|
||||
[
|
||||
(
|
||||
"https://www.youtube.com/playlist?list=PL1234567890",
|
||||
mode,
|
||||
"Operator",
|
||||
"Utility",
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
def test_invalid_download_mode_is_rejected_server_side(self):
|
||||
service = FakeControllerService()
|
||||
|
||||
response = self._post(service, download_mode="../../slot1")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn(b"Invalid download type", response.data)
|
||||
self.assertEqual(service.enqueue_calls, [])
|
||||
self.assertEqual(service.export_calls, [])
|
||||
|
||||
def test_recent_export_status_shows_results_and_failures(self):
|
||||
service = FakeControllerService(
|
||||
export_jobs=[
|
||||
{
|
||||
"job_id": "one",
|
||||
"mode": "mp4",
|
||||
"status": "completed",
|
||||
"output_paths": ["exports/video/one/Service.mp4"],
|
||||
"error": None,
|
||||
},
|
||||
{
|
||||
"job_id": "two",
|
||||
"mode": "mp3",
|
||||
"status": "failed",
|
||||
"output_paths": [],
|
||||
"error": "ffmpeg failed",
|
||||
},
|
||||
]
|
||||
)
|
||||
|
||||
response = self._app(service).test_client().get("/")
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn(b"Recent utility exports", response.data)
|
||||
self.assertIn(b"exports/video/one/Service.mp4", response.data)
|
||||
self.assertIn(b"ffmpeg failed", response.data)
|
||||
|
||||
def test_submit_rejects_non_youtube_and_malformed_urls(self):
|
||||
invalid_urls = (
|
||||
|
||||
Reference in New Issue
Block a user