deer-flow/tests/skills/test_podcast_cli.py
haotianqi666 46da5008cd
fix(skills): report podcast CLI failures with a nonzero status (#7236)
Co-authored-by: haotianqi666 <250384991+haotianqi666@users.noreply.github.com>
2026-10-24 10:49:05 +08:00

146 lines
4.6 KiB
Python

"""Exercise the documented podcast command, including its process status."""
import base64
import json
import runpy
import subprocess
import sys
from pathlib import Path
import pytest
import requests
SCRIPT = (
Path(__file__).resolve().parents[2]
/ "skills/public/podcast-generation/scripts/generate.py"
)
SCRIPT_DATA = {"lines": [{"speaker": "male", "paragraph": "Hello"}]}
@pytest.fixture(autouse=True)
def isolated_provider_env(monkeypatch):
for name in (
"PODCAST_GENERATION_PROVIDER",
"VOLCENGINE_TTS_APPID",
"VOLCENGINE_TTS_ACCESS_TOKEN",
"MINIMAX_API_KEY",
):
monkeypatch.delenv(name, raising=False)
monkeypatch.setenv("MINIMAX_TTS_MAX_RETRIES", "0")
@pytest.mark.parametrize(
("case", "error"),
[
("missing-file", "FileNotFoundError"),
("invalid-json", "JSONDecodeError"),
("empty-script", "Script contains no lines"),
("no-credentials", "No credentials found"),
("volcengine", "VOLCENGINE_TTS_APPID"),
("minimax", "MINIMAX_API_KEY is not set"),
],
)
def test_cli_failure_status(monkeypatch, tmp_path, case, error):
script = tmp_path / "script.json"
if case != "missing-file":
data = {"lines": []} if case == "empty-script" else SCRIPT_DATA
script.write_text(
"{" if case == "invalid-json" else json.dumps(data), encoding="utf-8"
)
if case in ("volcengine", "minimax"):
monkeypatch.setenv("PODCAST_GENERATION_PROVIDER", case)
output = tmp_path / "episode.mp3"
result = subprocess.run(
[
sys.executable,
str(SCRIPT),
"--script-file",
str(script),
"--output-file",
str(output),
],
capture_output=True,
text=True,
timeout=20,
check=False,
)
assert result.returncode == 1
assert result.stdout == ""
assert "Error generating podcast:" in result.stderr
assert error in result.stderr
assert not output.exists()
@pytest.mark.parametrize("provider", ["volcengine", "minimax"])
@pytest.mark.parametrize(
"outcome", ["success", "http-error", "connection-error", "empty-audio"]
)
def test_cli_provider_outcome(monkeypatch, tmp_path, capsys, provider, outcome):
monkeypatch.setenv("PODCAST_GENERATION_PROVIDER", provider)
monkeypatch.setenv("VOLCENGINE_TTS_APPID", "test-app")
monkeypatch.setenv("VOLCENGINE_TTS_ACCESS_TOKEN", "test-token")
monkeypatch.setenv("MINIMAX_API_KEY", "test-key")
script = tmp_path / "script.json"
script.write_text(json.dumps(SCRIPT_DATA), encoding="utf-8")
output = tmp_path / "episode.mp3"
output.write_bytes(b"previous episode")
transcript = tmp_path / "episode.md"
monkeypatch.setattr(
sys,
"argv",
[
str(SCRIPT),
"--script-file",
str(script),
"--output-file",
str(output),
"--transcript-file",
str(transcript),
],
)
def post(*args, **kwargs):
if outcome == "connection-error":
raise requests.ConnectionError("provider unavailable")
response = requests.Response()
response.status_code = 403 if outcome == "http-error" else 200
audio = b"" if outcome == "empty-audio" else b"new episode"
if provider == "volcengine":
payload = {"code": 3000, "data": base64.b64encode(audio).decode("ascii")}
else:
payload = {"base_resp": {"status_code": 0}, "data": {"audio": audio.hex()}}
response._content = json.dumps(payload).encode("utf-8")
return response
monkeypatch.setattr(requests, "post", post)
if outcome == "success":
runpy.run_path(str(SCRIPT), run_name="__main__")
assert output.read_bytes() == b"new episode"
assert "**Host (Male)**: Hello" in transcript.read_text(encoding="utf-8")
captured = capsys.readouterr()
assert "Successfully generated podcast" in captured.out
assert captured.err == ""
else:
with pytest.raises(SystemExit) as exc:
runpy.run_path(str(SCRIPT), run_name="__main__")
assert exc.value.code == 1
assert output.read_bytes() == b"previous episode"
captured = capsys.readouterr()
assert captured.out == ""
assert "Error generating podcast:" in captured.err
def test_cli_argument_error_remains_nonzero():
result = subprocess.run(
[sys.executable, str(SCRIPT)],
capture_output=True,
text=True,
timeout=20,
check=False,
)
assert result.returncode == 2
assert "--script-file" in result.stderr