import subprocess
import os
import pytest
import tempfile
import shutil
from pathlib import Path
from typing import List
SCRIPTS_DIR = Path(__file__).parent.parent.parent / "kadt" / "llm_service"
SCRIPTS: List[str] = [
"install_base_sw.sh",
"install_llm.sh",
"download.sh",
]
def run_script(args: List[str], cwd: Path = None) -> subprocess.CompletedProcess:
return subprocess.run(
args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
cwd=cwd
)
def has_help_message(output: str) -> bool:
keywords = ["帮助", "help", "Help", "Usage", "usage", "Options"]
return any(kw in output for kw in keywords)
def has_error_message(output: str) -> bool:
keywords = ["错误", "error", "Error", "失败", "failed", "invalid", "Invalid"]
return any(kw in output for kw in keywords)
class TestScriptExistence:
@pytest.mark.parametrize("script", SCRIPTS)
@staticmethod
def test_script_exists(script: str) -> None:
path = SCRIPTS_DIR / script
assert path.is_file(), f"{script} 不存在于 {SCRIPTS_DIR}"
class TestScriptHelp:
@pytest.mark.parametrize("script", SCRIPTS)
@staticmethod
def test_help_message(script: str) -> None:
path = SCRIPTS_DIR / script
result = run_script(["bash", str(path), "--help"], cwd=SCRIPTS_DIR)
assert result.returncode in (0, 1), f"{script} --help 返回异常退出码: {result.returncode}"
output = result.stdout + result.stderr
assert has_help_message(output), f"{script} 没有输出帮助信息, 输出: {output[:200]}"
class TestVllmDownload:
@staticmethod
def test_no_args_shows_help() -> None:
script_path = SCRIPTS_DIR / "download.sh"
result = run_script(["bash", str(script_path)], cwd=SCRIPTS_DIR)
output = result.stdout + result.stderr
assert result.returncode != 0, "无参数调用应返回非零退出码"
assert has_help_message(output), f"无参数时应显示帮助信息, 输出: {output[:200]}"
@staticmethod
def test_invalid_os_param_rejected() -> None:
script_path = SCRIPTS_DIR / "download.sh"
result = run_script(
["bash", str(script_path), "--os", "not_exist_os", "-o", "openEuler", "-m", "1"],
cwd=SCRIPTS_DIR
)
output = result.stdout + result.stderr
assert result.returncode != 127, "命令不应找不到 (exit 127)"
assert result.returncode != 0 or has_help_message(output) or has_error_message(output), \
f"无效 OS 参数应被拒绝或提示错误, 返回码: {result.returncode}, 输出: {output[:200]}"
class TestInstallBaseSw:
@staticmethod
def test_no_args_runs_or_shows_info() -> None:
script_path = SCRIPTS_DIR / "install_base_sw.sh"
result = run_script(["bash", str(script_path)], cwd=SCRIPTS_DIR)
output = result.stdout + result.stderr
assert "INSTALL_SOFTWARE" in output or has_help_message(output) or result.returncode != 0, \
f"无参数调用应显示配置信息或帮助, 输出: {output[:200]}"
@staticmethod
def test_invalid_software_param_rejected() -> None:
script_path = SCRIPTS_DIR / "install_base_sw.sh"
result = run_script(
["bash", str(script_path), "--install-software", "not_exist_pkg"],
cwd=SCRIPTS_DIR
)
output = result.stdout + result.stderr
assert result.returncode != 0 or has_error_message(output), \
f"无效软件包参数应被拒绝, 返回码: {result.returncode}, 输出: {output[:200]}"
class TestInstallLlm:
@staticmethod
def test_no_args_shows_help() -> None:
script_path = SCRIPTS_DIR / "install_llm.sh"
result = run_script(["bash", str(script_path)], cwd=SCRIPTS_DIR)
output = result.stdout + result.stderr
assert has_help_message(output), f"无参数时应显示帮助信息, 输出: {output[:200]}"
@staticmethod
def test_invalid_model_param_rejected() -> None:
script_path = SCRIPTS_DIR / "install_llm.sh"
result = run_script([
"bash", str(script_path),
"--model", "not_exist_model",
"--port", "8000",
"--api-key", "test"
], cwd=SCRIPTS_DIR)
output = result.stdout + result.stderr
assert result.returncode != 0 or has_error_message(output), \
f"无效模型参数应被拒绝, 返回码: {result.returncode}, 输出: {output[:200]}"
class TestMissingCommonScript:
@staticmethod
def test_missing_common_directory() -> None:
with tempfile.TemporaryDirectory() as tmpdir:
for script in SCRIPTS:
src = SCRIPTS_DIR / script
dst = Path(tmpdir) / script
shutil.copy(src, dst)
for script in SCRIPTS:
test_script = Path(tmpdir) / script
result = run_script(["bash", str(test_script), "--help"], cwd=Path(tmpdir))
output = result.stdout + result.stderr
assert "未找到公共脚本" in output, \
f"{script} 缺少 common 时应明确报错'未找到公共脚本', 输出: {output[:200]}"