145 lines
3.5 KiB
Python
145 lines
3.5 KiB
Python
|
|
import sys
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
import pytest
|
||
|
|
|
||
|
|
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
|
||
|
|
|
||
|
|
from llamacppctl.cli import build_parser, validate_args # noqa: E402
|
||
|
|
|
||
|
|
|
||
|
|
def parse(argv):
|
||
|
|
parser = build_parser()
|
||
|
|
args = parser.parse_args(argv)
|
||
|
|
validate_args(args, parser)
|
||
|
|
return args
|
||
|
|
|
||
|
|
|
||
|
|
def parse_error(argv):
|
||
|
|
parser = build_parser()
|
||
|
|
with pytest.raises(SystemExit):
|
||
|
|
args = parser.parse_args(argv)
|
||
|
|
validate_args(args, parser)
|
||
|
|
|
||
|
|
|
||
|
|
def test_requires_one_action():
|
||
|
|
parse_error([])
|
||
|
|
|
||
|
|
|
||
|
|
def test_actions_are_mutually_exclusive():
|
||
|
|
parse_error(["--start", "--stop"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_start_is_valid_minimal():
|
||
|
|
args = parse(["--start"])
|
||
|
|
assert args.start is True
|
||
|
|
|
||
|
|
|
||
|
|
def test_chat_requires_prompt_source():
|
||
|
|
parse_error(["--chat"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_chat_with_prompt_is_valid():
|
||
|
|
args = parse(["--chat", "-p", "hello"])
|
||
|
|
assert args.chat is True
|
||
|
|
assert args.prompt == "hello"
|
||
|
|
|
||
|
|
|
||
|
|
def test_stop_rejects_prompt_sources():
|
||
|
|
parse_error(["--stop", "-p", "hello"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_stop_rejects_system_sources():
|
||
|
|
parse_error(["--stop", "-s", "system text"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_check_with_system_but_no_prompt_rejected():
|
||
|
|
parse_error(["--check", "-s", "system text"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_check_with_system_and_prompt_ok():
|
||
|
|
args = parse(["--check", "-s", "system text", "-p", "hello"])
|
||
|
|
assert args.check is True
|
||
|
|
|
||
|
|
|
||
|
|
def test_mutually_exclusive_system_sources():
|
||
|
|
parse_error(["--start", "-s", "a", "--system-file", "b.txt"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_mutually_exclusive_prompt_sources():
|
||
|
|
parse_error(["--start", "-p", "a", "--prompt-url", "https://example.com/p"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_max_input_bytes_must_be_positive():
|
||
|
|
parse_error(["--start", "--max-input-bytes", "0"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_negative_max_input_bytes_rejected():
|
||
|
|
parse_error(["--start", "--max-input-bytes", "-5"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_connect_timeout_must_be_positive():
|
||
|
|
parse_error(["--start", "--connect-timeout", "0"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_read_timeout_must_be_positive():
|
||
|
|
parse_error(["--start", "--read-timeout", "-1"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_allow_private_url_conflicts_with_allowlist():
|
||
|
|
parse_error(["--start", "--allow-private-url", "--url-allow-host", "example.com"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_host_port_out_of_range_rejected():
|
||
|
|
parse_error(["--start", "--host-port", "70000"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_host_port_zero_rejected():
|
||
|
|
parse_error(["--start", "--host-port", "0"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_container_port_out_of_range_rejected():
|
||
|
|
parse_error(["--start", "--container-port", "-1"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_container_name_empty_string_rejected():
|
||
|
|
parse_error(["--start", "--container-name", " "])
|
||
|
|
|
||
|
|
|
||
|
|
def test_container_name_valid():
|
||
|
|
args = parse(["--start", "--container-name", "my_llm"])
|
||
|
|
assert args.container_name == "my_llm"
|
||
|
|
|
||
|
|
|
||
|
|
def test_boolean_flag_pairs_default_none():
|
||
|
|
args = parse(["--start"])
|
||
|
|
assert args.jinja is None
|
||
|
|
assert args.fa is None
|
||
|
|
assert args.kv_unified is None
|
||
|
|
assert args.cont_batching is None
|
||
|
|
assert args.no_context_shift is None
|
||
|
|
|
||
|
|
|
||
|
|
def test_boolean_flag_pairs_explicit_true_false():
|
||
|
|
args = parse(["--start", "--jinja", "--no-fa"])
|
||
|
|
assert args.jinja is True
|
||
|
|
assert args.fa is False
|
||
|
|
|
||
|
|
|
||
|
|
def test_dry_run_flag():
|
||
|
|
args = parse(["--start", "--dry-run"])
|
||
|
|
assert args.dry_run is True
|
||
|
|
|
||
|
|
|
||
|
|
def test_print_effective_config_flag():
|
||
|
|
args = parse(["--start", "--print-effective-config"])
|
||
|
|
assert args.print_effective_config is True
|
||
|
|
|
||
|
|
|
||
|
|
def test_reasoning_choice_validated():
|
||
|
|
parse_error(["--start", "--reasoning", "maybe"])
|
||
|
|
|
||
|
|
|
||
|
|
def test_reasoning_choice_valid():
|
||
|
|
args = parse(["--start", "--reasoning", "off"])
|
||
|
|
assert args.reasoning == "off"
|