Add installer test coverage for prebuilt llama.cpp changes (#4756)
Split out from #4741 to keep the main PR focused on installer logic. - New test_install_llama_prebuilt_logic.py: tests for resolve logic, fallback behavior, env_int, busy/lock handling - New test_validate_llama_prebuilt.py: validator tests for staged release_tag/upstream_tag handling - New test_llama_pr_force_and_source.py: tests for PR_FORCE and LLAMA_SOURCE maintainer defaults - Updated test_selection_logic.py: expanded selection/fallback coverage - Updated test_pr4562_bugfixes.py: updated bugfix tests for new logic - Updated smoke_test_llama_prebuilt.py: minor update
This commit is contained in:
parent
428efc7d95
commit
f84c2d03d3
6 changed files with 2781 additions and 122 deletions
|
|
@ -39,7 +39,7 @@ def parse_args() -> argparse.Namespace:
|
|||
parser.add_argument(
|
||||
"--llama-tag",
|
||||
default = "latest",
|
||||
help = "llama.cpp tag to resolve. Defaults to the approved prebuilt tag for this host.",
|
||||
help = "llama.cpp tag to resolve. Defaults to the latest usable published Unsloth release.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--published-repo",
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
599
tests/studio/install/test_llama_pr_force_and_source.py
Normal file
599
tests/studio/install/test_llama_pr_force_and_source.py
Normal file
|
|
@ -0,0 +1,599 @@
|
|||
"""
|
||||
Tests for UNSLOTH_LLAMA_PR_FORCE and UNSLOTH_LLAMA_SOURCE in setup.sh / setup.ps1.
|
||||
|
||||
Tests cover:
|
||||
- Bash subprocess: PR_FORCE promotion, user-override, zero/empty/invalid ignored
|
||||
- Bash subprocess: custom source URL forces build, clone URL uses variable
|
||||
- Static source checks: defaults present, clone URLs parameterized
|
||||
- PowerShell subprocess: PR_FORCE promotion, user-override parity
|
||||
|
||||
Run: pytest tests/studio/install/test_llama_pr_force_and_source.py -v
|
||||
"""
|
||||
|
||||
import os
|
||||
import shlex
|
||||
import subprocess
|
||||
import textwrap
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Paths
|
||||
# ---------------------------------------------------------------------------
|
||||
PACKAGE_ROOT = Path(__file__).resolve().parents[3]
|
||||
SETUP_SH = PACKAGE_ROOT / "studio" / "setup.sh"
|
||||
SETUP_PS1 = PACKAGE_ROOT / "studio" / "setup.ps1"
|
||||
|
||||
BASH = "/bin/bash"
|
||||
PWSH = "/usr/bin/pwsh"
|
||||
PWSH_AVAILABLE = os.path.isfile(PWSH) and os.access(PWSH, os.X_OK)
|
||||
requires_pwsh = pytest.mark.skipif(not PWSH_AVAILABLE, reason = "pwsh not available")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
def run_bash(
|
||||
script: str, *, timeout: int = 10, env: dict | None = None
|
||||
) -> subprocess.CompletedProcess:
|
||||
"""Run a bash script fragment and return the CompletedProcess."""
|
||||
run_env = os.environ.copy()
|
||||
if env:
|
||||
run_env.update(env)
|
||||
return subprocess.run(
|
||||
[BASH, "-c", script],
|
||||
capture_output = True,
|
||||
text = True,
|
||||
timeout = timeout,
|
||||
env = run_env,
|
||||
)
|
||||
|
||||
|
||||
def run_pwsh(
|
||||
script: str, *, timeout: int = 10, env: dict | None = None
|
||||
) -> subprocess.CompletedProcess:
|
||||
"""Run a PowerShell script fragment and return the CompletedProcess."""
|
||||
run_env = os.environ.copy()
|
||||
run_env["NO_COLOR"] = "1"
|
||||
if env:
|
||||
run_env.update(env)
|
||||
return subprocess.run(
|
||||
[PWSH, "-NoProfile", "-Command", script],
|
||||
capture_output = True,
|
||||
text = True,
|
||||
timeout = timeout,
|
||||
env = run_env,
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Shared bash stubs
|
||||
# ---------------------------------------------------------------------------
|
||||
BASH_STUBS = textwrap.dedent("""\
|
||||
step() { echo "step:$1:$2"; }
|
||||
substep() { :; }
|
||||
verbose_substep() { :; }
|
||||
print_llama_error_log() { :; }
|
||||
C_ERR= C_WARN= C_OK= C_RST= C_TITLE= C_DIM=
|
||||
""")
|
||||
|
||||
RUN_QUIET_STUB = textwrap.dedent("""\
|
||||
run_quiet_no_exit() { local _label="$1"; shift; "$@"; return $?; }
|
||||
""")
|
||||
|
||||
|
||||
def make_mock_git(tmp_path: Path, *, fail_on: str = "") -> tuple[Path, Path]:
|
||||
"""Create a mock git binary that logs calls. Returns (mock_bin, log_file)."""
|
||||
mock_bin = tmp_path / "mock_bin"
|
||||
mock_bin.mkdir(exist_ok = True)
|
||||
log_file = tmp_path / "git_calls.log"
|
||||
|
||||
if fail_on:
|
||||
script = (
|
||||
f'#!/bin/bash\necho "$*" >> {log_file}\n'
|
||||
f'_args=("$@")\n'
|
||||
f"_i=0\n"
|
||||
f'while [ "${{_args[$_i]:-}}" = "-C" ]; do _i=$((_i+2)); done\n'
|
||||
f'_subcmd="${{_args[$_i]:-}}"\n'
|
||||
f'if [ "$_subcmd" = "{fail_on}" ]; then exit 1; fi\n'
|
||||
f"exit 0\n"
|
||||
)
|
||||
else:
|
||||
script = f'#!/bin/bash\necho "$*" >> {log_file}\nexit 0\n'
|
||||
|
||||
git_bin = mock_bin / "git"
|
||||
git_bin.write_text(script)
|
||||
git_bin.chmod(0o755)
|
||||
return mock_bin, log_file
|
||||
|
||||
|
||||
# =========================================================================
|
||||
# Bash fragment that exercises PR_FORCE and _LLAMA_SOURCE resolution
|
||||
# =========================================================================
|
||||
def _bash_resolution_fragment(
|
||||
llama_pr: str = "",
|
||||
llama_pr_force: str = "",
|
||||
llama_source: str = "",
|
||||
default_pr_force: str = "",
|
||||
default_source: str = "https://github.com/ggml-org/llama.cpp",
|
||||
) -> str:
|
||||
"""Build the bash fragment that mirrors setup.sh resolution logic."""
|
||||
return BASH_STUBS + textwrap.dedent(f"""\
|
||||
_LLAMA_PR={shlex.quote(llama_pr) if llama_pr else '""'}
|
||||
_DEFAULT_LLAMA_PR_FORCE={shlex.quote(default_pr_force) if default_pr_force else '""'}
|
||||
_DEFAULT_LLAMA_SOURCE={shlex.quote(default_source)}
|
||||
|
||||
_LLAMA_PR_FORCE={shlex.quote(llama_pr_force) if llama_pr_force else '"$_DEFAULT_LLAMA_PR_FORCE"'}
|
||||
_LLAMA_SOURCE={shlex.quote(llama_source) if llama_source else '"$_DEFAULT_LLAMA_SOURCE"'}
|
||||
_LLAMA_SOURCE="${{_LLAMA_SOURCE%.git}}"
|
||||
|
||||
_NEED_LLAMA_SOURCE_BUILD=false
|
||||
_SKIP_PREBUILT_INSTALL=false
|
||||
|
||||
if [ "$_LLAMA_SOURCE" != "https://github.com/ggml-org/llama.cpp" ]; then
|
||||
step "llama.cpp" "custom source: $_LLAMA_SOURCE -- forcing source build"
|
||||
_NEED_LLAMA_SOURCE_BUILD=true
|
||||
_SKIP_PREBUILT_INSTALL=true
|
||||
fi
|
||||
|
||||
if [ -z "$_LLAMA_PR" ] && [ -n "$_LLAMA_PR_FORCE" ] && \\
|
||||
[[ "$_LLAMA_PR_FORCE" =~ ^[0-9]+$ ]] && [ "$_LLAMA_PR_FORCE" -gt 0 ]; then
|
||||
_LLAMA_PR="$_LLAMA_PR_FORCE"
|
||||
step "llama.cpp" "baked-in PR_FORCE=$_LLAMA_PR_FORCE"
|
||||
fi
|
||||
|
||||
echo "LLAMA_PR=$_LLAMA_PR"
|
||||
echo "LLAMA_SOURCE=$_LLAMA_SOURCE"
|
||||
echo "NEED_SOURCE=$_NEED_LLAMA_SOURCE_BUILD"
|
||||
echo "SKIP_PREBUILT=$_SKIP_PREBUILT_INSTALL"
|
||||
""")
|
||||
|
||||
|
||||
# =========================================================================
|
||||
# TEST GROUP A: Bash PR_FORCE promotion (subprocess)
|
||||
# =========================================================================
|
||||
class TestBashPrForcePromotion:
|
||||
"""PR_FORCE promotes to _LLAMA_PR when user hasn't set one."""
|
||||
|
||||
def test_baked_in_pr_force_promotes(self):
|
||||
script = _bash_resolution_fragment(default_pr_force = "12345")
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_PR=12345" in r.stdout
|
||||
assert "baked-in PR_FORCE=12345" in r.stdout
|
||||
|
||||
def test_env_pr_force_promotes(self):
|
||||
script = _bash_resolution_fragment(llama_pr_force = "999")
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_PR=999" in r.stdout
|
||||
|
||||
def test_user_pr_overrides_pr_force(self):
|
||||
"""UNSLOTH_LLAMA_PR takes priority over PR_FORCE."""
|
||||
script = _bash_resolution_fragment(
|
||||
llama_pr = "100",
|
||||
llama_pr_force = "200",
|
||||
)
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_PR=100" in r.stdout
|
||||
assert "baked-in PR_FORCE" not in r.stdout
|
||||
|
||||
def test_user_pr_overrides_baked_in(self):
|
||||
script = _bash_resolution_fragment(
|
||||
llama_pr = "100",
|
||||
default_pr_force = "200",
|
||||
)
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_PR=100" in r.stdout
|
||||
assert "baked-in PR_FORCE" not in r.stdout
|
||||
|
||||
def test_pr_force_zero_ignored(self):
|
||||
script = _bash_resolution_fragment(llama_pr_force = "0")
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_PR=" in r.stdout
|
||||
assert "baked-in PR_FORCE" not in r.stdout
|
||||
|
||||
def test_pr_force_empty_ignored(self):
|
||||
script = _bash_resolution_fragment(default_pr_force = "")
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_PR=" in r.stdout
|
||||
assert "baked-in PR_FORCE" not in r.stdout
|
||||
|
||||
def test_pr_force_alpha_ignored(self):
|
||||
script = _bash_resolution_fragment(llama_pr_force = "abc")
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_PR=" in r.stdout
|
||||
assert "baked-in PR_FORCE" not in r.stdout
|
||||
|
||||
def test_pr_force_negative_ignored(self):
|
||||
script = _bash_resolution_fragment(llama_pr_force = "-5")
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_PR=" in r.stdout
|
||||
|
||||
def test_pr_force_decimal_ignored(self):
|
||||
script = _bash_resolution_fragment(llama_pr_force = "12.34")
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_PR=" in r.stdout
|
||||
|
||||
|
||||
# =========================================================================
|
||||
# TEST GROUP B: Bash custom source URL (subprocess)
|
||||
# =========================================================================
|
||||
class TestBashCustomSource:
|
||||
"""Custom _LLAMA_SOURCE forces source build."""
|
||||
|
||||
def test_custom_source_forces_build(self):
|
||||
script = _bash_resolution_fragment(
|
||||
llama_source = "https://github.com/unslothai/llama.cpp",
|
||||
)
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
assert "NEED_SOURCE=true" in r.stdout
|
||||
assert "SKIP_PREBUILT=true" in r.stdout
|
||||
assert "custom source:" in r.stdout
|
||||
|
||||
def test_default_source_no_force(self):
|
||||
script = _bash_resolution_fragment()
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
assert "NEED_SOURCE=false" in r.stdout
|
||||
assert "SKIP_PREBUILT=false" in r.stdout
|
||||
assert "custom source:" not in r.stdout
|
||||
|
||||
def test_trailing_git_stripped(self):
|
||||
script = _bash_resolution_fragment(
|
||||
llama_source = "https://github.com/unslothai/llama.cpp.git",
|
||||
)
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_SOURCE=https://github.com/unslothai/llama.cpp" in r.stdout
|
||||
assert "NEED_SOURCE=true" in r.stdout
|
||||
|
||||
def test_baked_in_source_forces_build(self):
|
||||
script = _bash_resolution_fragment(
|
||||
default_source = "https://github.com/unslothai/llama.cpp",
|
||||
)
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
assert "NEED_SOURCE=true" in r.stdout
|
||||
|
||||
def test_env_source_overrides_baked_in(self):
|
||||
"""User UNSLOTH_LLAMA_SOURCE overrides _DEFAULT_LLAMA_SOURCE."""
|
||||
script = _bash_resolution_fragment(
|
||||
llama_source = "https://github.com/custom/llama.cpp",
|
||||
default_source = "https://github.com/unslothai/llama.cpp",
|
||||
)
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_SOURCE=https://github.com/custom/llama.cpp" in r.stdout
|
||||
|
||||
|
||||
# =========================================================================
|
||||
# TEST GROUP C: Bash clone URL parameterization (subprocess with mock git)
|
||||
# =========================================================================
|
||||
class TestBashCloneUrlParameterized:
|
||||
"""Verify git clone uses _LLAMA_SOURCE instead of hardcoded URL."""
|
||||
|
||||
@staticmethod
|
||||
def _clone_script(
|
||||
mock_bin: Path,
|
||||
build_tmp: str,
|
||||
llama_pr: str = "",
|
||||
llama_source: str = "https://github.com/ggml-org/llama.cpp",
|
||||
resolved_tag: str = "b8508",
|
||||
) -> str:
|
||||
return RUN_QUIET_STUB + textwrap.dedent(f"""\
|
||||
export PATH="{mock_bin}:$PATH"
|
||||
_LLAMA_PR={shlex.quote(llama_pr) if llama_pr else '""'}
|
||||
_LLAMA_SOURCE={shlex.quote(llama_source)}
|
||||
_RESOLVED_LLAMA_TAG={shlex.quote(resolved_tag)}
|
||||
_BUILD_TMP={shlex.quote(build_tmp)}
|
||||
BUILD_OK=true
|
||||
|
||||
if [ -n "$_LLAMA_PR" ]; then
|
||||
run_quiet_no_exit "clone llama.cpp" \\
|
||||
git clone --depth 1 "${{_LLAMA_SOURCE}}.git" "$_BUILD_TMP" || BUILD_OK=false
|
||||
else
|
||||
_CLONE_BRANCH_ARGS=()
|
||||
if [ "$_RESOLVED_LLAMA_TAG" != "latest" ] && [ -n "$_RESOLVED_LLAMA_TAG" ]; then
|
||||
_CLONE_BRANCH_ARGS=(--branch "$_RESOLVED_LLAMA_TAG")
|
||||
fi
|
||||
run_quiet_no_exit "clone llama.cpp" \\
|
||||
git clone --depth 1 "${{_CLONE_BRANCH_ARGS[@]}}" "${{_LLAMA_SOURCE}}.git" "$_BUILD_TMP" || BUILD_OK=false
|
||||
fi
|
||||
echo "BUILD_OK=$BUILD_OK"
|
||||
""")
|
||||
|
||||
def test_pr_path_uses_custom_source(self, tmp_path: Path):
|
||||
mock_bin, log_file = make_mock_git(tmp_path)
|
||||
build_tmp = str(tmp_path / "build_tmp")
|
||||
script = self._clone_script(
|
||||
mock_bin,
|
||||
build_tmp,
|
||||
llama_pr = "123",
|
||||
llama_source = "https://github.com/unslothai/llama.cpp",
|
||||
)
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
log = log_file.read_text()
|
||||
assert "unslothai/llama.cpp.git" in log
|
||||
assert "ggml-org" not in log
|
||||
|
||||
def test_non_pr_path_uses_custom_source(self, tmp_path: Path):
|
||||
mock_bin, log_file = make_mock_git(tmp_path)
|
||||
build_tmp = str(tmp_path / "build_tmp")
|
||||
script = self._clone_script(
|
||||
mock_bin,
|
||||
build_tmp,
|
||||
llama_source = "https://github.com/unslothai/llama.cpp",
|
||||
)
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
log = log_file.read_text()
|
||||
assert "unslothai/llama.cpp.git" in log
|
||||
assert "ggml-org" not in log
|
||||
|
||||
def test_default_source_unchanged(self, tmp_path: Path):
|
||||
mock_bin, log_file = make_mock_git(tmp_path)
|
||||
build_tmp = str(tmp_path / "build_tmp")
|
||||
script = self._clone_script(mock_bin, build_tmp)
|
||||
r = run_bash(script)
|
||||
assert r.returncode == 0
|
||||
log = log_file.read_text()
|
||||
assert "ggml-org/llama.cpp.git" in log
|
||||
|
||||
|
||||
# =========================================================================
|
||||
# TEST GROUP D: Static source patterns -- setup.sh
|
||||
# =========================================================================
|
||||
class TestSourcePatternsSh:
|
||||
"""Verify setup.sh has the new defaults and parameterized clone URLs."""
|
||||
|
||||
@pytest.fixture(autouse = True)
|
||||
def _load_source(self):
|
||||
self.content = SETUP_SH.read_text()
|
||||
|
||||
def test_has_default_pr_force(self):
|
||||
assert '_DEFAULT_LLAMA_PR_FORCE=""' in self.content
|
||||
|
||||
def test_has_default_source(self):
|
||||
assert (
|
||||
'_DEFAULT_LLAMA_SOURCE="https://github.com/ggml-org/llama.cpp"'
|
||||
in self.content
|
||||
)
|
||||
|
||||
def test_has_pr_force_env_read(self):
|
||||
assert "UNSLOTH_LLAMA_PR_FORCE" in self.content
|
||||
|
||||
def test_has_source_env_read(self):
|
||||
assert "UNSLOTH_LLAMA_SOURCE" in self.content
|
||||
|
||||
def test_pr_force_resolution_block(self):
|
||||
assert '_LLAMA_PR="$_LLAMA_PR_FORCE"' in self.content
|
||||
|
||||
def test_source_trailing_git_strip(self):
|
||||
assert "${_LLAMA_SOURCE%.git}" in self.content
|
||||
|
||||
def test_clone_urls_parameterized_pr_path(self):
|
||||
"""PR clone path uses ${_LLAMA_SOURCE}.git, not hardcoded URL."""
|
||||
pr_clone_idx = self.content.index(
|
||||
'if [ -n "$_LLAMA_PR" ]; then\n'
|
||||
' run_quiet_no_exit "clone llama.cpp"'
|
||||
)
|
||||
else_idx = self.content.index("else\n", pr_clone_idx)
|
||||
pr_block = self.content[pr_clone_idx:else_idx]
|
||||
assert '"${_LLAMA_SOURCE}.git"' in pr_block
|
||||
assert "ggml-org/llama.cpp.git" not in pr_block
|
||||
|
||||
def test_clone_urls_parameterized_tag_path(self):
|
||||
"""Non-PR clone path uses ${_LLAMA_SOURCE}.git, not hardcoded URL."""
|
||||
# Find the non-PR clone line (after _CLONE_BRANCH_ARGS)
|
||||
idx = self.content.index("_CLONE_BRANCH_ARGS=()")
|
||||
block = self.content[idx : idx + 400]
|
||||
assert '"${_LLAMA_SOURCE}.git"' in block
|
||||
assert "ggml-org/llama.cpp.git" not in block
|
||||
|
||||
def test_custom_source_forces_build(self):
|
||||
assert "custom source: $_LLAMA_SOURCE -- forcing source build" in self.content
|
||||
|
||||
def test_no_hardcoded_clone_urls(self):
|
||||
"""No remaining hardcoded ggml-org clone URLs in clone commands."""
|
||||
lines = self.content.splitlines()
|
||||
for i, line in enumerate(lines, 1):
|
||||
if "git clone" in line and "ggml-org/llama.cpp.git" in line:
|
||||
pytest.fail(
|
||||
f"Line {i} has hardcoded ggml-org clone URL: {line.strip()}"
|
||||
)
|
||||
|
||||
|
||||
# =========================================================================
|
||||
# TEST GROUP E: Static source patterns -- setup.ps1
|
||||
# =========================================================================
|
||||
class TestSourcePatternsPs1:
|
||||
"""Verify setup.ps1 has the new defaults and parameterized clone URLs."""
|
||||
|
||||
@pytest.fixture(autouse = True)
|
||||
def _load_source(self):
|
||||
self.content = SETUP_PS1.read_text()
|
||||
|
||||
def test_has_default_pr_force(self):
|
||||
assert '$DefaultLlamaPrForce = ""' in self.content
|
||||
|
||||
def test_has_default_source(self):
|
||||
assert (
|
||||
'$DefaultLlamaSource = "https://github.com/ggml-org/llama.cpp"'
|
||||
in self.content
|
||||
)
|
||||
|
||||
def test_has_pr_force_env_read(self):
|
||||
assert "$env:UNSLOTH_LLAMA_PR_FORCE" in self.content
|
||||
|
||||
def test_has_source_env_read(self):
|
||||
assert "$env:UNSLOTH_LLAMA_SOURCE" in self.content
|
||||
|
||||
def test_pr_force_promotion_block(self):
|
||||
assert "$LlamaPr = $LlamaPrForce" in self.content
|
||||
|
||||
def test_source_trailing_git_strip(self):
|
||||
assert ".EndsWith('.git')" in self.content
|
||||
|
||||
def test_clone_urls_parameterized_pr_path(self):
|
||||
"""PR clone path uses $LlamaSource.git, not hardcoded URL."""
|
||||
pr_idx = self.content.index(
|
||||
"if ($LlamaPr) {\n", self.content.index("Cloning llama.cpp")
|
||||
)
|
||||
else_idx = self.content.index("} else {", pr_idx)
|
||||
pr_block = self.content[pr_idx:else_idx]
|
||||
assert '"$LlamaSource.git"' in pr_block
|
||||
assert "ggml-org/llama.cpp.git" not in pr_block
|
||||
|
||||
def test_clone_urls_parameterized_tag_path(self):
|
||||
"""Non-PR clone path uses $LlamaSource.git, not hardcoded URL."""
|
||||
clone_args_idx = self.content.index('$cloneArgs = @("clone"')
|
||||
block = self.content[clone_args_idx : clone_args_idx + 400]
|
||||
assert '"$LlamaSource.git"' in block
|
||||
assert "ggml-org/llama.cpp.git" not in block
|
||||
|
||||
def test_custom_source_forces_build(self):
|
||||
assert "custom source: $LlamaSource -- forcing source build" in self.content
|
||||
|
||||
def test_no_hardcoded_clone_urls(self):
|
||||
"""No remaining hardcoded ggml-org clone URLs in clone commands."""
|
||||
lines = self.content.splitlines()
|
||||
for i, line in enumerate(lines, 1):
|
||||
if "git clone" in line and "ggml-org/llama.cpp.git" in line:
|
||||
pytest.fail(
|
||||
f"Line {i} has hardcoded ggml-org clone URL: {line.strip()}"
|
||||
)
|
||||
|
||||
|
||||
# =========================================================================
|
||||
# TEST GROUP F: PowerShell PR_FORCE promotion (subprocess)
|
||||
# =========================================================================
|
||||
@requires_pwsh
|
||||
class TestPwshPrForcePromotion:
|
||||
"""PR_FORCE promotion and source URL logic via pwsh subprocess."""
|
||||
|
||||
FRAGMENT_TEMPLATE = textwrap.dedent("""\
|
||||
function step($a, $b, $c) { Write-Output "step:$a`:$b" }
|
||||
|
||||
$DefaultLlamaPrForce = "%%DEFAULT_PR_FORCE%%"
|
||||
$DefaultLlamaSource = "%%DEFAULT_SOURCE%%"
|
||||
|
||||
$LlamaPr = if ($env:UNSLOTH_LLAMA_PR) { $env:UNSLOTH_LLAMA_PR.Trim() } else { "" }
|
||||
$LlamaPrForce = if ($env:UNSLOTH_LLAMA_PR_FORCE) { $env:UNSLOTH_LLAMA_PR_FORCE.Trim() } else { $DefaultLlamaPrForce }
|
||||
$LlamaSource = if ($env:UNSLOTH_LLAMA_SOURCE) { $env:UNSLOTH_LLAMA_SOURCE.Trim() } else { $DefaultLlamaSource }
|
||||
if ($LlamaSource.EndsWith('.git')) { $LlamaSource = $LlamaSource.Substring(0, $LlamaSource.Length - 4) }
|
||||
|
||||
$NeedLlamaSourceBuild = $false
|
||||
$SkipPrebuiltInstall = $false
|
||||
|
||||
if ($LlamaSource -ne "https://github.com/ggml-org/llama.cpp") {
|
||||
step "llama.cpp" "custom source: $LlamaSource -- forcing source build" "Yellow"
|
||||
$NeedLlamaSourceBuild = $true
|
||||
$SkipPrebuiltInstall = $true
|
||||
}
|
||||
|
||||
if (-not $LlamaPr -and $LlamaPrForce -and $LlamaPrForce -match '^\\d+$' -and [int]$LlamaPrForce -gt 0) {
|
||||
$LlamaPr = $LlamaPrForce
|
||||
step "llama.cpp" "baked-in PR_FORCE=$LlamaPrForce" "Yellow"
|
||||
}
|
||||
|
||||
Write-Output "LLAMA_PR=$LlamaPr"
|
||||
Write-Output "LLAMA_SOURCE=$LlamaSource"
|
||||
Write-Output "NEED_SOURCE=$NeedLlamaSourceBuild"
|
||||
Write-Output "SKIP_PREBUILT=$SkipPrebuiltInstall"
|
||||
""")
|
||||
|
||||
def _run(
|
||||
self,
|
||||
default_pr_force: str = "",
|
||||
default_source: str = "https://github.com/ggml-org/llama.cpp",
|
||||
env: dict | None = None,
|
||||
) -> subprocess.CompletedProcess:
|
||||
script = self.FRAGMENT_TEMPLATE.replace(
|
||||
"%%DEFAULT_PR_FORCE%%",
|
||||
default_pr_force,
|
||||
).replace(
|
||||
"%%DEFAULT_SOURCE%%",
|
||||
default_source,
|
||||
)
|
||||
run_env = {}
|
||||
# Ensure env vars are unset by default
|
||||
run_env["UNSLOTH_LLAMA_PR"] = ""
|
||||
run_env["UNSLOTH_LLAMA_PR_FORCE"] = ""
|
||||
run_env["UNSLOTH_LLAMA_SOURCE"] = ""
|
||||
if env:
|
||||
run_env.update(env)
|
||||
return run_pwsh(script, env = run_env)
|
||||
|
||||
def test_baked_in_pr_force_promotes(self):
|
||||
r = self._run(default_pr_force = "12345")
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_PR=12345" in r.stdout
|
||||
assert "baked-in PR_FORCE=12345" in r.stdout
|
||||
|
||||
def test_env_pr_force_promotes(self):
|
||||
r = self._run(env = {"UNSLOTH_LLAMA_PR_FORCE": "999"})
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_PR=999" in r.stdout
|
||||
|
||||
def test_user_pr_overrides_pr_force(self):
|
||||
r = self._run(
|
||||
env = {
|
||||
"UNSLOTH_LLAMA_PR": "100",
|
||||
"UNSLOTH_LLAMA_PR_FORCE": "200",
|
||||
}
|
||||
)
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_PR=100" in r.stdout
|
||||
assert "baked-in PR_FORCE" not in r.stdout
|
||||
|
||||
def test_pr_force_zero_ignored(self):
|
||||
r = self._run(env = {"UNSLOTH_LLAMA_PR_FORCE": "0"})
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_PR=" in r.stdout
|
||||
assert "baked-in PR_FORCE" not in r.stdout
|
||||
|
||||
def test_pr_force_alpha_ignored(self):
|
||||
r = self._run(env = {"UNSLOTH_LLAMA_PR_FORCE": "abc"})
|
||||
assert r.returncode == 0
|
||||
assert "baked-in PR_FORCE" not in r.stdout
|
||||
|
||||
def test_custom_source_forces_build(self):
|
||||
r = self._run(
|
||||
env = {
|
||||
"UNSLOTH_LLAMA_SOURCE": "https://github.com/unslothai/llama.cpp",
|
||||
}
|
||||
)
|
||||
assert r.returncode == 0
|
||||
assert "NEED_SOURCE=True" in r.stdout
|
||||
assert "SKIP_PREBUILT=True" in r.stdout
|
||||
|
||||
def test_default_source_no_force(self):
|
||||
r = self._run()
|
||||
assert r.returncode == 0
|
||||
assert "NEED_SOURCE=False" in r.stdout
|
||||
assert "SKIP_PREBUILT=False" in r.stdout
|
||||
|
||||
def test_trailing_git_stripped(self):
|
||||
r = self._run(
|
||||
env = {
|
||||
"UNSLOTH_LLAMA_SOURCE": "https://github.com/unslothai/llama.cpp.git",
|
||||
}
|
||||
)
|
||||
assert r.returncode == 0
|
||||
assert "LLAMA_SOURCE=https://github.com/unslothai/llama.cpp" in r.stdout
|
||||
|
||||
def test_baked_in_source_forces_build(self):
|
||||
r = self._run(default_source = "https://github.com/unslothai/llama.cpp")
|
||||
assert r.returncode == 0
|
||||
assert "NEED_SOURCE=True" in r.stdout
|
||||
|
|
@ -6,7 +6,7 @@ Tests cover:
|
|||
- Bug 2: Source-build fallback ignores pinned tag (both .sh and .ps1)
|
||||
- Bug 3: Unix fallback deletes install before checking prerequisites
|
||||
- Bug 4: Linux LD_LIBRARY_PATH missing build/bin
|
||||
- "latest" tag resolution fallback chain (Unsloth -> ggml-org -> raw)
|
||||
- "latest" tag resolution fallback chain (helper -> raw)
|
||||
- Cross-platform binary_env (Linux, macOS, Windows)
|
||||
- Edge cases: malformed JSON, empty responses, env overrides
|
||||
|
||||
|
|
@ -40,6 +40,10 @@ SPEC.loader.exec_module(MOD)
|
|||
binary_env = MOD.binary_env
|
||||
HostInfo = MOD.HostInfo
|
||||
resolve_requested_llama_tag = MOD.resolve_requested_llama_tag
|
||||
PublishedReleaseBundle = MOD.PublishedReleaseBundle
|
||||
ApprovedArtifactHash = MOD.ApprovedArtifactHash
|
||||
ApprovedReleaseChecksums = MOD.ApprovedReleaseChecksums
|
||||
source_archive_logical_name = MOD.source_archive_logical_name
|
||||
|
||||
SETUP_SH = PACKAGE_ROOT / "studio" / "setup.sh"
|
||||
SETUP_PS1 = PACKAGE_ROOT / "studio" / "setup.ps1"
|
||||
|
|
@ -240,6 +244,57 @@ class TestResolveRequestedLlamaTag:
|
|||
monkeypatch.setattr(MOD, "latest_upstream_release_tag", lambda: "b5555")
|
||||
assert resolve_requested_llama_tag("") == "b5555"
|
||||
|
||||
def test_latest_with_published_repo_uses_latest_valid_published_release(
|
||||
self, monkeypatch: pytest.MonkeyPatch
|
||||
):
|
||||
invalid = PublishedReleaseBundle(
|
||||
repo = "unslothai/llama.cpp",
|
||||
release_tag = "v2.0",
|
||||
upstream_tag = "b9000",
|
||||
assets = {},
|
||||
manifest_asset_name = "llama-prebuilt-manifest.json",
|
||||
artifacts = [],
|
||||
selection_log = [],
|
||||
)
|
||||
valid = PublishedReleaseBundle(
|
||||
repo = "unslothai/llama.cpp",
|
||||
release_tag = "v1.0",
|
||||
upstream_tag = "b8999",
|
||||
assets = {},
|
||||
manifest_asset_name = "llama-prebuilt-manifest.json",
|
||||
artifacts = [],
|
||||
selection_log = [],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
MOD,
|
||||
"iter_published_release_bundles",
|
||||
lambda repo, published_release_tag = "": iter([invalid, valid]),
|
||||
)
|
||||
|
||||
def fake_load(repo, release_tag):
|
||||
if release_tag == "v2.0":
|
||||
raise MOD.PrebuiltFallback("checksum asset missing")
|
||||
return ApprovedReleaseChecksums(
|
||||
repo = repo,
|
||||
release_tag = release_tag,
|
||||
upstream_tag = "b8999",
|
||||
source_commit = None,
|
||||
artifacts = {
|
||||
source_archive_logical_name("b8999"): ApprovedArtifactHash(
|
||||
asset_name = source_archive_logical_name("b8999"),
|
||||
sha256 = "a" * 64,
|
||||
repo = "ggml-org/llama.cpp",
|
||||
kind = "upstream-source",
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
monkeypatch.setattr(MOD, "load_approved_release_checksums", fake_load)
|
||||
monkeypatch.setattr(MOD, "latest_upstream_release_tag", lambda: "b7777")
|
||||
|
||||
assert resolve_requested_llama_tag("latest", "unslothai/llama.cpp") == "b8999"
|
||||
|
||||
|
||||
# =========================================================================
|
||||
# TEST GROUP C: setup.sh logic (bash subprocess tests)
|
||||
|
|
@ -429,140 +484,61 @@ class TestSetupShLogic:
|
|||
# TEST GROUP D: "latest" tag resolution (bash subprocess)
|
||||
# =========================================================================
|
||||
class TestLatestTagResolution:
|
||||
"""Test the fallback chain: Unsloth API -> ggml-org API -> raw."""
|
||||
"""Test the fallback chain: helper resolver -> raw."""
|
||||
|
||||
RESOLVE_TEMPLATE = textwrap.dedent("""\
|
||||
export PATH="{mock_bin}:$PATH"
|
||||
_REQUESTED_LLAMA_TAG="{requested_tag}"
|
||||
_RESOLVED_LLAMA_TAG=""
|
||||
_RESOLVE_UPSTREAM_STATUS=1
|
||||
_HELPER_RELEASE_REPO="unslothai/llama.cpp"
|
||||
if [ "$_RESOLVE_UPSTREAM_STATUS" -ne 0 ] || [ -z "$_RESOLVED_LLAMA_TAG" ]; then
|
||||
if [ "$_REQUESTED_LLAMA_TAG" = "latest" ]; then
|
||||
_RESOLVED_LLAMA_TAG="$(curl -fsSL "https://api.github.com/repos/${{_HELPER_RELEASE_REPO}}/releases/latest" 2>/dev/null | python -c "import sys,json; print(json.load(sys.stdin)['tag_name'])" 2>/dev/null)" || _RESOLVED_LLAMA_TAG=""
|
||||
if [ -z "$_RESOLVED_LLAMA_TAG" ]; then
|
||||
_RESOLVED_LLAMA_TAG="$(curl -fsSL https://api.github.com/repos/ggml-org/llama.cpp/releases/latest 2>/dev/null | python -c "import sys,json; print(json.load(sys.stdin)['tag_name'])" 2>/dev/null)" || _RESOLVED_LLAMA_TAG=""
|
||||
fi
|
||||
fi
|
||||
if [ -z "$_RESOLVED_LLAMA_TAG" ]; then
|
||||
_RESOLVED_LLAMA_TAG="$_REQUESTED_LLAMA_TAG"
|
||||
fi
|
||||
_RESOLVE_UPSTREAM_STATUS={resolve_status}
|
||||
if [ "$_RESOLVE_UPSTREAM_STATUS" -eq 0 ] && [ -n "{resolved_tag}" ]; then
|
||||
_RESOLVED_LLAMA_TAG="{resolved_tag}"
|
||||
else
|
||||
_RESOLVED_LLAMA_TAG="$_REQUESTED_LLAMA_TAG"
|
||||
fi
|
||||
echo "$_RESOLVED_LLAMA_TAG"
|
||||
""")
|
||||
|
||||
@staticmethod
|
||||
def _make_curl_mock(
|
||||
mock_bin: Path, unsloth_response: str | None, ggml_response: str | None
|
||||
):
|
||||
"""Create a curl mock that returns different responses per repo."""
|
||||
lines = ["#!/bin/bash"]
|
||||
if unsloth_response is not None:
|
||||
lines.append(
|
||||
f'if echo "$*" | grep -q "unslothai/llama.cpp"; then echo \'{unsloth_response}\'; exit 0; fi'
|
||||
)
|
||||
else:
|
||||
lines.append(
|
||||
'if echo "$*" | grep -q "unslothai/llama.cpp"; then exit 1; fi'
|
||||
)
|
||||
if ggml_response is not None:
|
||||
lines.append(
|
||||
f'if echo "$*" | grep -q "ggml-org/llama.cpp"; then echo \'{ggml_response}\'; exit 0; fi'
|
||||
)
|
||||
else:
|
||||
lines.append('if echo "$*" | grep -q "ggml-org/llama.cpp"; then exit 1; fi')
|
||||
lines.append("exit 1")
|
||||
curl_path = mock_bin / "curl"
|
||||
curl_path.write_text("\n".join(lines) + "\n")
|
||||
curl_path.chmod(0o755)
|
||||
|
||||
def _run_resolve(
|
||||
self,
|
||||
tmp_path: Path,
|
||||
requested_tag: str,
|
||||
unsloth_resp: str | None,
|
||||
ggml_resp: str | None,
|
||||
resolved_tag: str,
|
||||
resolve_status: int,
|
||||
) -> str:
|
||||
mock_bin = tmp_path / "mock_bin"
|
||||
mock_bin.mkdir(exist_ok = True)
|
||||
self._make_curl_mock(mock_bin, unsloth_resp, ggml_resp)
|
||||
script = self.RESOLVE_TEMPLATE.format(
|
||||
mock_bin = mock_bin, requested_tag = requested_tag
|
||||
requested_tag = requested_tag,
|
||||
resolved_tag = resolved_tag,
|
||||
resolve_status = resolve_status,
|
||||
)
|
||||
return run_bash(script)
|
||||
|
||||
def test_unsloth_succeeds(self, tmp_path: Path):
|
||||
def test_helper_resolution_succeeds(self, tmp_path: Path):
|
||||
output = self._run_resolve(
|
||||
tmp_path,
|
||||
"latest",
|
||||
unsloth_resp = '{"tag_name":"b8508"}',
|
||||
ggml_resp = '{"tag_name":"b9000"}',
|
||||
resolved_tag = "b8508",
|
||||
resolve_status = 0,
|
||||
)
|
||||
assert output == "b8508"
|
||||
|
||||
def test_unsloth_fails_ggml_succeeds(self, tmp_path: Path):
|
||||
def test_helper_resolution_falls_back_to_raw_requested_tag(self, tmp_path: Path):
|
||||
output = self._run_resolve(
|
||||
tmp_path,
|
||||
"latest",
|
||||
unsloth_resp = None,
|
||||
ggml_resp = '{"tag_name":"b9000"}',
|
||||
)
|
||||
assert output == "b9000"
|
||||
|
||||
def test_both_fail_raw_fallback(self, tmp_path: Path):
|
||||
output = self._run_resolve(
|
||||
tmp_path,
|
||||
"latest",
|
||||
unsloth_resp = None,
|
||||
ggml_resp = None,
|
||||
resolved_tag = "",
|
||||
resolve_status = 1,
|
||||
)
|
||||
assert output == "latest"
|
||||
|
||||
def test_concrete_tag_passes_through(self, tmp_path: Path):
|
||||
def test_concrete_tag_passes_through_when_helper_fails(self, tmp_path: Path):
|
||||
output = self._run_resolve(
|
||||
tmp_path,
|
||||
"b7777",
|
||||
unsloth_resp = '{"tag_name":"b8508"}',
|
||||
ggml_resp = '{"tag_name":"b9000"}',
|
||||
resolved_tag = "",
|
||||
resolve_status = 1,
|
||||
)
|
||||
assert output == "b7777"
|
||||
|
||||
def test_unsloth_malformed_json_falls_through(self, tmp_path: Path):
|
||||
output = self._run_resolve(
|
||||
tmp_path,
|
||||
"latest",
|
||||
unsloth_resp = '{"bad_key":"no_tag"}',
|
||||
ggml_resp = '{"tag_name":"b9001"}',
|
||||
)
|
||||
assert output == "b9001"
|
||||
|
||||
def test_both_malformed_json_raw_fallback(self, tmp_path: Path):
|
||||
output = self._run_resolve(
|
||||
tmp_path,
|
||||
"latest",
|
||||
unsloth_resp = '{"bad":"data"}',
|
||||
ggml_resp = '{"also":"bad"}',
|
||||
)
|
||||
assert output == "latest"
|
||||
|
||||
def test_unsloth_empty_body_falls_through(self, tmp_path: Path):
|
||||
output = self._run_resolve(
|
||||
tmp_path,
|
||||
"latest",
|
||||
unsloth_resp = "",
|
||||
ggml_resp = '{"tag_name":"b7000"}',
|
||||
)
|
||||
assert output == "b7000"
|
||||
|
||||
def test_unsloth_empty_tag_name_falls_through(self, tmp_path: Path):
|
||||
output = self._run_resolve(
|
||||
tmp_path,
|
||||
"latest",
|
||||
unsloth_resp = '{"tag_name":""}',
|
||||
ggml_resp = '{"tag_name":"b6000"}',
|
||||
)
|
||||
assert output == "b6000"
|
||||
|
||||
def test_env_override_unsloth_llama_tag(self):
|
||||
output = run_bash(
|
||||
'echo "${UNSLOTH_LLAMA_TAG:-latest}"',
|
||||
|
|
@ -593,10 +569,10 @@ class TestSourceCodePatterns:
|
|||
def test_setup_sh_no_rm_before_prereq_check(self):
|
||||
"""rm -rf must appear AFTER cmake/git checks, not before."""
|
||||
content = SETUP_SH.read_text()
|
||||
# Find the source-build block
|
||||
idx_else = content.find("# Check prerequisites")
|
||||
assert idx_else != -1
|
||||
block = content[idx_else:]
|
||||
# Anchor on the source-build cmake check block.
|
||||
idx_block = content.find("command -v cmake")
|
||||
assert idx_block != -1
|
||||
block = content[idx_block:]
|
||||
# rm -rf should appear after the cmake/git checks
|
||||
idx_cmake = block.find("command -v cmake")
|
||||
idx_git = block.find("command -v git")
|
||||
|
|
@ -619,14 +595,12 @@ class TestSourceCodePatterns:
|
|||
'_RESOLVED_LLAMA_TAG" != "latest"' in content
|
||||
), "Should guard against literal 'latest' tag"
|
||||
|
||||
def test_setup_sh_latest_resolution_queries_unsloth_first(self):
|
||||
"""The Unsloth repo should be queried before ggml-org."""
|
||||
def test_setup_sh_latest_resolution_uses_helper_only(self):
|
||||
"""Shell fallback should rely on helper output, not raw GitHub API tag_name."""
|
||||
content = SETUP_SH.read_text()
|
||||
idx_unsloth = content.find("_HELPER_RELEASE_REPO}/releases/latest")
|
||||
idx_ggml = content.find("ggml-org/llama.cpp/releases/latest")
|
||||
assert idx_unsloth != -1, "Unsloth API query not found"
|
||||
assert idx_ggml != -1, "ggml-org API query not found"
|
||||
assert idx_unsloth < idx_ggml, "Unsloth should be queried before ggml-org"
|
||||
assert "--resolve-llama-tag" in content
|
||||
assert "_HELPER_RELEASE_REPO}/releases/latest" not in content
|
||||
assert "ggml-org/llama.cpp/releases/latest" not in content
|
||||
|
||||
def test_setup_ps1_uses_checkout_b(self):
|
||||
"""PS1 should use checkout -B, not checkout --force FETCH_HEAD."""
|
||||
|
|
@ -658,14 +632,12 @@ class TestSourceCodePatterns:
|
|||
f"Found 'git pull' in llama.cpp build section at line {i+1}"
|
||||
)
|
||||
|
||||
def test_setup_ps1_latest_resolution_queries_unsloth_first(self):
|
||||
"""PS1 should query Unsloth repo before ggml-org."""
|
||||
def test_setup_ps1_latest_resolution_uses_helper_only(self):
|
||||
"""PS1 fallback should rely on helper output, not raw GitHub API tag_name."""
|
||||
content = SETUP_PS1.read_text()
|
||||
idx_unsloth = content.find("$HelperReleaseRepo/releases/latest")
|
||||
idx_ggml = content.find("ggml-org/llama.cpp/releases/latest")
|
||||
assert idx_unsloth != -1, "Unsloth API query not found in PS1"
|
||||
assert idx_ggml != -1, "ggml-org API query not found in PS1"
|
||||
assert idx_unsloth < idx_ggml, "Unsloth should be queried before ggml-org"
|
||||
assert "--resolve-llama-tag" in content
|
||||
assert "$HelperReleaseRepo/releases/latest" not in content
|
||||
assert "ggml-org/llama.cpp/releases/latest" not in content
|
||||
|
||||
def test_binary_env_linux_has_binary_parent(self):
|
||||
"""The Linux branch of binary_env should include binary_path.parent."""
|
||||
|
|
|
|||
|
|
@ -54,6 +54,12 @@ apply_approved_hashes = INSTALL_LLAMA_PREBUILT.apply_approved_hashes
|
|||
linux_cuda_choice_from_release = INSTALL_LLAMA_PREBUILT.linux_cuda_choice_from_release
|
||||
windows_cuda_attempts = INSTALL_LLAMA_PREBUILT.windows_cuda_attempts
|
||||
resolve_upstream_asset_choice = INSTALL_LLAMA_PREBUILT.resolve_upstream_asset_choice
|
||||
resolve_requested_install_tag = INSTALL_LLAMA_PREBUILT.resolve_requested_install_tag
|
||||
resolve_install_attempts = INSTALL_LLAMA_PREBUILT.resolve_install_attempts
|
||||
resolve_install_release_plans = INSTALL_LLAMA_PREBUILT.resolve_install_release_plans
|
||||
resolve_published_release = INSTALL_LLAMA_PREBUILT.resolve_published_release
|
||||
source_archive_logical_name = INSTALL_LLAMA_PREBUILT.source_archive_logical_name
|
||||
env_int = INSTALL_LLAMA_PREBUILT.env_int
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -131,6 +137,37 @@ def make_checksums(asset_names):
|
|||
)
|
||||
|
||||
|
||||
def make_checksums_with_source(
|
||||
asset_names,
|
||||
*,
|
||||
release_tag = "v1.0",
|
||||
upstream_tag = "b8508",
|
||||
):
|
||||
return ApprovedReleaseChecksums(
|
||||
repo = "unslothai/llama.cpp",
|
||||
release_tag = release_tag,
|
||||
upstream_tag = upstream_tag,
|
||||
source_commit = None,
|
||||
artifacts = {
|
||||
**{
|
||||
name: ApprovedArtifactHash(
|
||||
asset_name = name,
|
||||
sha256 = "a" * 64,
|
||||
repo = "unslothai/llama.cpp",
|
||||
kind = "prebuilt",
|
||||
)
|
||||
for name in asset_names
|
||||
},
|
||||
source_archive_logical_name(upstream_tag): ApprovedArtifactHash(
|
||||
asset_name = source_archive_logical_name(upstream_tag),
|
||||
sha256 = "b" * 64,
|
||||
repo = "ggml-org/llama.cpp",
|
||||
kind = "upstream-source",
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def mock_linux_runtime(monkeypatch, lines):
|
||||
dirs = {line: ["/usr/lib/stub"] for line in lines}
|
||||
monkeypatch.setattr(
|
||||
|
|
@ -408,7 +445,100 @@ class TestApplyApprovedHashes:
|
|||
|
||||
|
||||
# ===========================================================================
|
||||
# J. linux_cuda_choice_from_release -- core selection
|
||||
# J. published release resolution
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
class TestPublishedReleaseResolution:
|
||||
def test_latest_skips_invalid_release_and_uses_next_valid(self, monkeypatch):
|
||||
invalid = make_release([], release_tag = "v2.0", upstream_tag = "b9000")
|
||||
valid = make_release([], release_tag = "v1.0", upstream_tag = "b8999")
|
||||
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"iter_published_release_bundles",
|
||||
lambda repo, published_release_tag = "": iter([invalid, valid]),
|
||||
)
|
||||
|
||||
def fake_load(repo, release_tag):
|
||||
if release_tag == "v2.0":
|
||||
raise PrebuiltFallback("checksum asset missing")
|
||||
return make_checksums_with_source(
|
||||
[], release_tag = "v1.0", upstream_tag = "b8999"
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"load_approved_release_checksums",
|
||||
fake_load,
|
||||
)
|
||||
|
||||
resolved = resolve_published_release("latest", "unslothai/llama.cpp")
|
||||
assert resolved.bundle.release_tag == "v1.0"
|
||||
assert resolved.bundle.upstream_tag == "b8999"
|
||||
assert resolved.checksums.release_tag == "v1.0"
|
||||
|
||||
def test_concrete_tag_matches_manifest_upstream_tag(self, monkeypatch):
|
||||
release = make_release([], release_tag = "release-b8508", upstream_tag = "b8508")
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"iter_published_release_bundles",
|
||||
lambda repo, published_release_tag = "": iter([release]),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"load_approved_release_checksums",
|
||||
lambda repo, release_tag: make_checksums_with_source(
|
||||
[],
|
||||
release_tag = release_tag,
|
||||
upstream_tag = "b8508",
|
||||
),
|
||||
)
|
||||
|
||||
assert (
|
||||
resolve_requested_install_tag("b8508", "", "unslothai/llama.cpp") == "b8508"
|
||||
)
|
||||
|
||||
def test_concrete_tag_without_matching_release_raises(self, monkeypatch):
|
||||
release = make_release([], release_tag = "release-b9000", upstream_tag = "b9000")
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"iter_published_release_bundles",
|
||||
lambda repo, published_release_tag = "": iter([release]),
|
||||
)
|
||||
|
||||
with pytest.raises(PrebuiltFallback, match = "matched upstream tag b8508"):
|
||||
resolve_requested_install_tag("b8508", "", "unslothai/llama.cpp")
|
||||
|
||||
def test_pinned_release_must_match_requested_upstream_tag(self, monkeypatch):
|
||||
bundle = make_release(
|
||||
[], release_tag = "llama-prebuilt-latest", upstream_tag = "b9000"
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"pinned_published_release_bundle",
|
||||
lambda repo, release_tag: bundle,
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"load_approved_release_checksums",
|
||||
lambda repo, release_tag: make_checksums_with_source(
|
||||
[],
|
||||
release_tag = release_tag,
|
||||
upstream_tag = "b9000",
|
||||
),
|
||||
)
|
||||
|
||||
with pytest.raises(PrebuiltFallback, match = "but requested b8508"):
|
||||
resolve_requested_install_tag(
|
||||
"b8508",
|
||||
"llama-prebuilt-latest",
|
||||
"unslothai/llama.cpp",
|
||||
)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# K. linux_cuda_choice_from_release -- core selection
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
|
|
@ -676,7 +806,554 @@ class TestLinuxCudaChoiceFromRelease:
|
|||
|
||||
|
||||
# ===========================================================================
|
||||
# K. windows_cuda_attempts
|
||||
# L. resolve_install_attempts
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
class TestResolveInstallAttempts:
|
||||
def test_windows_cuda_prefers_published_asset_from_selected_release(
|
||||
self, monkeypatch
|
||||
):
|
||||
host = make_host(system = "Windows", machine = "AMD64")
|
||||
host.driver_cuda_version = (12, 4)
|
||||
mock_windows_runtime(monkeypatch, ["cuda12"])
|
||||
asset_name = "llama-b9000-bin-win-cuda-12.4-x64.zip"
|
||||
release = make_release(
|
||||
[
|
||||
make_artifact(
|
||||
asset_name,
|
||||
install_kind = "windows-cuda",
|
||||
runtime_line = "cuda12",
|
||||
coverage_class = None,
|
||||
supported_sms = [],
|
||||
min_sm = None,
|
||||
max_sm = None,
|
||||
bundle_profile = None,
|
||||
)
|
||||
],
|
||||
release_tag = "llama-prebuilt-latest",
|
||||
upstream_tag = "b9000",
|
||||
assets = {asset_name: f"https://published.example/{asset_name}"},
|
||||
)
|
||||
checksums = make_checksums_with_source(
|
||||
[asset_name],
|
||||
release_tag = release.release_tag,
|
||||
upstream_tag = "b9000",
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"iter_resolved_published_releases",
|
||||
lambda requested_tag, published_repo, published_release_tag = "": iter(
|
||||
[
|
||||
INSTALL_LLAMA_PREBUILT.ResolvedPublishedRelease(
|
||||
bundle = release,
|
||||
checksums = checksums,
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"github_release_assets",
|
||||
lambda repo, tag: (_ for _ in ()).throw(
|
||||
AssertionError(
|
||||
"published Windows CUDA choice should not query upstream"
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
requested_tag, resolved_tag, attempts, approved = resolve_install_attempts(
|
||||
"latest",
|
||||
host,
|
||||
"unslothai/llama.cpp",
|
||||
"",
|
||||
)
|
||||
|
||||
assert requested_tag == "latest"
|
||||
assert resolved_tag == "b9000"
|
||||
assert attempts[0].name == asset_name
|
||||
assert attempts[0].source_label == "published"
|
||||
assert attempts[0].expected_sha256 == "a" * 64
|
||||
assert approved.release_tag == "llama-prebuilt-latest"
|
||||
|
||||
def test_windows_cuda_uses_selected_release_upstream_tag(self, monkeypatch):
|
||||
host = make_host(system = "Windows", machine = "AMD64")
|
||||
host.driver_cuda_version = (12, 4)
|
||||
mock_windows_runtime(monkeypatch, ["cuda12"])
|
||||
release = make_release(
|
||||
[], release_tag = "llama-prebuilt-latest", upstream_tag = "b9000"
|
||||
)
|
||||
checksums = make_checksums_with_source(
|
||||
["llama-b9000-bin-win-cuda-12.4-x64.zip"],
|
||||
release_tag = release.release_tag,
|
||||
upstream_tag = "b9000",
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"iter_resolved_published_releases",
|
||||
lambda requested_tag, published_repo, published_release_tag = "": iter(
|
||||
[
|
||||
INSTALL_LLAMA_PREBUILT.ResolvedPublishedRelease(
|
||||
bundle = release,
|
||||
checksums = checksums,
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"github_release_assets",
|
||||
lambda repo, tag: {
|
||||
f"llama-{tag}-bin-win-cuda-12.4-x64.zip": f"https://example.com/llama-{tag}-bin-win-cuda-12.4-x64.zip"
|
||||
},
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"resolve_windows_cuda_choices",
|
||||
lambda host, tag, assets: [
|
||||
AssetChoice(
|
||||
repo = UPSTREAM_REPO,
|
||||
tag = tag,
|
||||
name = f"llama-{tag}-bin-win-cuda-12.4-x64.zip",
|
||||
url = assets[f"llama-{tag}-bin-win-cuda-12.4-x64.zip"],
|
||||
source_label = "upstream",
|
||||
install_kind = "windows-cuda",
|
||||
runtime_line = "cuda12",
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
requested_tag, resolved_tag, attempts, approved = resolve_install_attempts(
|
||||
"latest",
|
||||
host,
|
||||
"unslothai/llama.cpp",
|
||||
"",
|
||||
)
|
||||
|
||||
assert requested_tag == "latest"
|
||||
assert resolved_tag == "b9000"
|
||||
assert attempts[0].name == "llama-b9000-bin-win-cuda-12.4-x64.zip"
|
||||
assert attempts[0].expected_sha256 == "a" * 64
|
||||
assert approved.release_tag == "llama-prebuilt-latest"
|
||||
|
||||
def test_linux_cpu_uses_same_tag_upstream_asset(self, monkeypatch):
|
||||
host = make_host(
|
||||
has_usable_nvidia = False,
|
||||
has_physical_nvidia = False,
|
||||
nvidia_smi = None,
|
||||
)
|
||||
release = make_release(
|
||||
[], release_tag = "llama-prebuilt-latest", upstream_tag = "b9000"
|
||||
)
|
||||
checksums = make_checksums_with_source(
|
||||
["llama-b9000-bin-ubuntu-x64.tar.gz"],
|
||||
release_tag = release.release_tag,
|
||||
upstream_tag = "b9000",
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"iter_resolved_published_releases",
|
||||
lambda requested_tag, published_repo, published_release_tag = "": iter(
|
||||
[
|
||||
INSTALL_LLAMA_PREBUILT.ResolvedPublishedRelease(
|
||||
bundle = release,
|
||||
checksums = checksums,
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"github_release_assets",
|
||||
lambda repo, tag: {
|
||||
f"llama-{tag}-bin-ubuntu-x64.tar.gz": f"https://example.com/llama-{tag}-bin-ubuntu-x64.tar.gz"
|
||||
},
|
||||
)
|
||||
|
||||
_requested_tag, resolved_tag, attempts, _approved = resolve_install_attempts(
|
||||
"latest",
|
||||
host,
|
||||
"unslothai/llama.cpp",
|
||||
"",
|
||||
)
|
||||
|
||||
assert resolved_tag == "b9000"
|
||||
assert attempts[0].name == "llama-b9000-bin-ubuntu-x64.tar.gz"
|
||||
assert attempts[0].source_label == "upstream"
|
||||
assert attempts[0].expected_sha256 == "a" * 64
|
||||
|
||||
def test_linux_cuda_does_not_fall_back_to_upstream_cpu(self, monkeypatch):
|
||||
host = make_host(system = "Linux", machine = "x86_64", compute_caps = ["86"])
|
||||
release = make_release(
|
||||
[], release_tag = "llama-prebuilt-latest", upstream_tag = "b9000"
|
||||
)
|
||||
checksums = make_checksums_with_source(
|
||||
[],
|
||||
release_tag = release.release_tag,
|
||||
upstream_tag = "b9000",
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"iter_resolved_published_releases",
|
||||
lambda requested_tag, published_repo, published_release_tag = "": iter(
|
||||
[
|
||||
INSTALL_LLAMA_PREBUILT.ResolvedPublishedRelease(
|
||||
bundle = release,
|
||||
checksums = checksums,
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
mock_linux_runtime(monkeypatch, ["cuda12"])
|
||||
|
||||
with pytest.raises(
|
||||
PrebuiltFallback, match = "no compatible published Linux CUDA bundle"
|
||||
):
|
||||
resolve_install_attempts("latest", host, "unslothai/llama.cpp", "")
|
||||
|
||||
def test_windows_cpu_prefers_published_asset(self, monkeypatch):
|
||||
host = make_host(
|
||||
system = "Windows",
|
||||
machine = "AMD64",
|
||||
has_usable_nvidia = False,
|
||||
has_physical_nvidia = False,
|
||||
nvidia_smi = None,
|
||||
)
|
||||
asset_name = "llama-b9000-bin-win-cpu-x64.zip"
|
||||
release = make_release(
|
||||
[
|
||||
make_artifact(
|
||||
asset_name,
|
||||
install_kind = "windows-cpu",
|
||||
runtime_line = None,
|
||||
coverage_class = None,
|
||||
supported_sms = [],
|
||||
min_sm = None,
|
||||
max_sm = None,
|
||||
bundle_profile = None,
|
||||
)
|
||||
],
|
||||
release_tag = "llama-prebuilt-latest",
|
||||
upstream_tag = "b9000",
|
||||
assets = {asset_name: f"https://published.example/{asset_name}"},
|
||||
)
|
||||
checksums = make_checksums_with_source(
|
||||
[asset_name],
|
||||
release_tag = release.release_tag,
|
||||
upstream_tag = "b9000",
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"iter_resolved_published_releases",
|
||||
lambda requested_tag, published_repo, published_release_tag = "": iter(
|
||||
[
|
||||
INSTALL_LLAMA_PREBUILT.ResolvedPublishedRelease(
|
||||
bundle = release,
|
||||
checksums = checksums,
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"github_release_assets",
|
||||
lambda repo, tag: (_ for _ in ()).throw(
|
||||
AssertionError("published Windows CPU choice should not query upstream")
|
||||
),
|
||||
)
|
||||
|
||||
_requested_tag, resolved_tag, attempts, _approved = resolve_install_attempts(
|
||||
"latest",
|
||||
host,
|
||||
"unslothai/llama.cpp",
|
||||
"",
|
||||
)
|
||||
|
||||
assert resolved_tag == "b9000"
|
||||
assert attempts[0].name == asset_name
|
||||
assert attempts[0].source_label == "published"
|
||||
|
||||
def test_macos_prefers_published_asset(self, monkeypatch):
|
||||
host = make_host(
|
||||
system = "Darwin",
|
||||
machine = "arm64",
|
||||
nvidia_smi = None,
|
||||
driver_cuda_version = None,
|
||||
compute_caps = [],
|
||||
has_physical_nvidia = False,
|
||||
has_usable_nvidia = False,
|
||||
)
|
||||
asset_name = "llama-b9000-bin-macos-arm64.tar.gz"
|
||||
release = make_release(
|
||||
[
|
||||
make_artifact(
|
||||
asset_name,
|
||||
install_kind = "macos-arm64",
|
||||
runtime_line = None,
|
||||
coverage_class = None,
|
||||
supported_sms = [],
|
||||
min_sm = None,
|
||||
max_sm = None,
|
||||
bundle_profile = None,
|
||||
)
|
||||
],
|
||||
release_tag = "llama-prebuilt-latest",
|
||||
upstream_tag = "b9000",
|
||||
assets = {asset_name: f"https://published.example/{asset_name}"},
|
||||
)
|
||||
checksums = make_checksums_with_source(
|
||||
[asset_name],
|
||||
release_tag = release.release_tag,
|
||||
upstream_tag = "b9000",
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"iter_resolved_published_releases",
|
||||
lambda requested_tag, published_repo, published_release_tag = "": iter(
|
||||
[
|
||||
INSTALL_LLAMA_PREBUILT.ResolvedPublishedRelease(
|
||||
bundle = release,
|
||||
checksums = checksums,
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"github_release_assets",
|
||||
lambda repo, tag: (_ for _ in ()).throw(
|
||||
AssertionError("published macOS choice should not query upstream")
|
||||
),
|
||||
)
|
||||
|
||||
_requested_tag, resolved_tag, attempts, _approved = resolve_install_attempts(
|
||||
"latest",
|
||||
host,
|
||||
"unslothai/llama.cpp",
|
||||
"",
|
||||
)
|
||||
|
||||
assert resolved_tag == "b9000"
|
||||
assert attempts[0].name == asset_name
|
||||
assert attempts[0].source_label == "published"
|
||||
|
||||
def test_windows_cpu_missing_checksum_rejects_install(self, monkeypatch):
|
||||
host = make_host(
|
||||
system = "Windows",
|
||||
machine = "AMD64",
|
||||
has_usable_nvidia = False,
|
||||
has_physical_nvidia = False,
|
||||
nvidia_smi = None,
|
||||
)
|
||||
published_name = "llama-b9000-bin-win-cpu-x64.zip"
|
||||
release = make_release(
|
||||
[
|
||||
make_artifact(
|
||||
published_name,
|
||||
install_kind = "windows-cpu",
|
||||
runtime_line = None,
|
||||
coverage_class = None,
|
||||
supported_sms = [],
|
||||
min_sm = None,
|
||||
max_sm = None,
|
||||
bundle_profile = None,
|
||||
)
|
||||
],
|
||||
release_tag = "llama-prebuilt-latest",
|
||||
upstream_tag = "b9000",
|
||||
assets = {published_name: f"https://published.example/{published_name}"},
|
||||
)
|
||||
checksums = make_checksums_with_source(
|
||||
[],
|
||||
release_tag = release.release_tag,
|
||||
upstream_tag = "b9000",
|
||||
)
|
||||
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"iter_resolved_published_releases",
|
||||
lambda requested_tag, published_repo, published_release_tag = "": iter(
|
||||
[
|
||||
INSTALL_LLAMA_PREBUILT.ResolvedPublishedRelease(
|
||||
bundle = release,
|
||||
checksums = checksums,
|
||||
)
|
||||
]
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"github_release_assets",
|
||||
lambda repo, tag: {
|
||||
f"llama-{tag}-bin-win-cpu-x64.zip": f"https://upstream.example/llama-{tag}-bin-win-cpu-x64.zip"
|
||||
},
|
||||
)
|
||||
|
||||
with pytest.raises(
|
||||
PrebuiltFallback,
|
||||
match = "approved checksum asset did not contain the selected prebuilt archive",
|
||||
):
|
||||
resolve_install_attempts(
|
||||
"latest",
|
||||
host,
|
||||
"unslothai/llama.cpp",
|
||||
"",
|
||||
)
|
||||
|
||||
|
||||
class TestResolveInstallReleasePlans:
|
||||
def test_latest_collects_multiple_older_release_plans_up_to_limit(
|
||||
self, monkeypatch
|
||||
):
|
||||
host = make_host(
|
||||
has_usable_nvidia = False,
|
||||
has_physical_nvidia = False,
|
||||
nvidia_smi = None,
|
||||
)
|
||||
releases = [
|
||||
INSTALL_LLAMA_PREBUILT.ResolvedPublishedRelease(
|
||||
bundle = make_release([], release_tag = "r3", upstream_tag = "b9003"),
|
||||
checksums = make_checksums_with_source(
|
||||
["llama-b9003-bin-ubuntu-x64.tar.gz"],
|
||||
release_tag = "r3",
|
||||
upstream_tag = "b9003",
|
||||
),
|
||||
),
|
||||
INSTALL_LLAMA_PREBUILT.ResolvedPublishedRelease(
|
||||
bundle = make_release([], release_tag = "r2", upstream_tag = "b9002"),
|
||||
checksums = make_checksums_with_source(
|
||||
["llama-b9002-bin-ubuntu-x64.tar.gz"],
|
||||
release_tag = "r2",
|
||||
upstream_tag = "b9002",
|
||||
),
|
||||
),
|
||||
INSTALL_LLAMA_PREBUILT.ResolvedPublishedRelease(
|
||||
bundle = make_release([], release_tag = "r1", upstream_tag = "b9001"),
|
||||
checksums = make_checksums_with_source(
|
||||
["llama-b9001-bin-ubuntu-x64.tar.gz"],
|
||||
release_tag = "r1",
|
||||
upstream_tag = "b9001",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"iter_resolved_published_releases",
|
||||
lambda requested_tag, published_repo, published_release_tag = "": iter(
|
||||
releases
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"github_release_assets",
|
||||
lambda repo, tag: {
|
||||
f"llama-{tag}-bin-ubuntu-x64.tar.gz": f"https://example.com/llama-{tag}-bin-ubuntu-x64.tar.gz"
|
||||
},
|
||||
)
|
||||
|
||||
requested_tag, plans = resolve_install_release_plans(
|
||||
"latest",
|
||||
host,
|
||||
"unslothai/llama.cpp",
|
||||
"",
|
||||
max_release_fallbacks = 2,
|
||||
)
|
||||
|
||||
assert requested_tag == "latest"
|
||||
assert [plan.release_tag for plan in plans] == ["r3", "r2"]
|
||||
assert [plan.llama_tag for plan in plans] == ["b9003", "b9002"]
|
||||
|
||||
def test_latest_skips_non_installable_release_and_keeps_searching(
|
||||
self, monkeypatch
|
||||
):
|
||||
host = make_host(
|
||||
has_usable_nvidia = False,
|
||||
has_physical_nvidia = False,
|
||||
nvidia_smi = None,
|
||||
)
|
||||
releases = [
|
||||
INSTALL_LLAMA_PREBUILT.ResolvedPublishedRelease(
|
||||
bundle = make_release([], release_tag = "r2", upstream_tag = "b9002"),
|
||||
checksums = make_checksums_with_source(
|
||||
[],
|
||||
release_tag = "r2",
|
||||
upstream_tag = "b9002",
|
||||
),
|
||||
),
|
||||
INSTALL_LLAMA_PREBUILT.ResolvedPublishedRelease(
|
||||
bundle = make_release([], release_tag = "r1", upstream_tag = "b9001"),
|
||||
checksums = make_checksums_with_source(
|
||||
["llama-b9001-bin-ubuntu-x64.tar.gz"],
|
||||
release_tag = "r1",
|
||||
upstream_tag = "b9001",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"iter_resolved_published_releases",
|
||||
lambda requested_tag, published_repo, published_release_tag = "": iter(
|
||||
releases
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(
|
||||
INSTALL_LLAMA_PREBUILT,
|
||||
"github_release_assets",
|
||||
lambda repo, tag: (
|
||||
{}
|
||||
if tag == "b9002"
|
||||
else {
|
||||
f"llama-{tag}-bin-ubuntu-x64.tar.gz": f"https://example.com/llama-{tag}-bin-ubuntu-x64.tar.gz"
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
_requested_tag, plans = resolve_install_release_plans(
|
||||
"latest",
|
||||
host,
|
||||
"unslothai/llama.cpp",
|
||||
"",
|
||||
max_release_fallbacks = 2,
|
||||
)
|
||||
|
||||
assert len(plans) == 1
|
||||
assert plans[0].release_tag == "r1"
|
||||
assert plans[0].llama_tag == "b9001"
|
||||
|
||||
def test_malformed_release_fallback_env_uses_default(self, monkeypatch):
|
||||
monkeypatch.setenv("UNSLOTH_LLAMA_MAX_PREBUILT_RELEASE_FALLBACKS", "not-an-int")
|
||||
assert (
|
||||
env_int("UNSLOTH_LLAMA_MAX_PREBUILT_RELEASE_FALLBACKS", 3, minimum = 1) == 3
|
||||
)
|
||||
|
||||
def test_import_with_malformed_release_fallback_env_does_not_crash(
|
||||
self, monkeypatch
|
||||
):
|
||||
monkeypatch.setenv("UNSLOTH_LLAMA_MAX_PREBUILT_RELEASE_FALLBACKS", "bad-value")
|
||||
spec = importlib.util.spec_from_file_location(
|
||||
"studio_install_llama_prebuilt_env_reload",
|
||||
MODULE_PATH,
|
||||
)
|
||||
assert spec is not None and spec.loader is not None
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[spec.name] = module
|
||||
try:
|
||||
spec.loader.exec_module(module)
|
||||
assert module.DEFAULT_MAX_PREBUILT_RELEASE_FALLBACKS == 2
|
||||
finally:
|
||||
sys.modules.pop(spec.name, None)
|
||||
|
||||
|
||||
# ===========================================================================
|
||||
# N. windows_cuda_attempts
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
|
|
@ -753,7 +1430,7 @@ class TestWindowsCudaAttempts:
|
|||
|
||||
|
||||
# ===========================================================================
|
||||
# L. resolve_upstream_asset_choice -- platform routing
|
||||
# O. resolve_upstream_asset_choice -- platform routing
|
||||
# ===========================================================================
|
||||
|
||||
|
||||
|
|
|
|||
175
tests/studio/install/test_validate_llama_prebuilt.py
Normal file
175
tests/studio/install/test_validate_llama_prebuilt.py
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
import importlib.util
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||
MODULE_PATH = REPO_ROOT / "validate-llama-prebuilt.py"
|
||||
|
||||
if not MODULE_PATH.is_file():
|
||||
pytest.skip(
|
||||
f"validate-llama-prebuilt.py not present at {MODULE_PATH}",
|
||||
allow_module_level = True,
|
||||
)
|
||||
|
||||
SPEC = importlib.util.spec_from_file_location("validate_llama_prebuilt", MODULE_PATH)
|
||||
assert SPEC is not None and SPEC.loader is not None
|
||||
VALIDATE = importlib.util.module_from_spec(SPEC)
|
||||
sys.modules[SPEC.name] = VALIDATE
|
||||
SPEC.loader.exec_module(VALIDATE)
|
||||
|
||||
|
||||
def test_build_local_approved_checksums_uses_staged_upstream_tag(
|
||||
tmp_path: Path, monkeypatch
|
||||
):
|
||||
stage_dir = tmp_path / "release-1"
|
||||
stage_dir.mkdir()
|
||||
asset_path = stage_dir / "app-test-linux-x64-cuda12-newer.tar.gz"
|
||||
asset_path.write_bytes(b"bundle")
|
||||
sibling_checksums = stage_dir / VALIDATE.installer.DEFAULT_PUBLISHED_SHA256_ASSET
|
||||
sibling_checksums.write_text(
|
||||
"""
|
||||
{
|
||||
"schema_version": 1,
|
||||
"component": "llama.cpp",
|
||||
"release_tag": "release-1",
|
||||
"upstream_tag": "b9001",
|
||||
"source_commit": "deadbeef",
|
||||
"artifacts": {
|
||||
"llama.cpp-source-b9001.tar.gz": {
|
||||
"sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
"repo": "ggml-org/llama.cpp",
|
||||
"kind": "upstream-source"
|
||||
}
|
||||
}
|
||||
}
|
||||
""".strip()
|
||||
+ "\n",
|
||||
encoding = "utf-8",
|
||||
)
|
||||
asset = VALIDATE.LocalAsset(
|
||||
path = asset_path,
|
||||
tag = "test",
|
||||
name = asset_path.name,
|
||||
install_kind = "linux-cuda",
|
||||
source_kind = "app-bundle",
|
||||
native_runnable = True,
|
||||
bundle_profile = "cuda12-newer",
|
||||
runtime_line = "cuda12",
|
||||
)
|
||||
|
||||
checksums = VALIDATE.build_local_approved_checksums(
|
||||
asset,
|
||||
allow_network_source_hash = False,
|
||||
)
|
||||
|
||||
assert checksums.release_tag == "release-1"
|
||||
assert checksums.upstream_tag == "b9001"
|
||||
assert "llama.cpp-source-b9001.tar.gz" in checksums.artifacts
|
||||
assert "llama.cpp-source-test.tar.gz" not in checksums.artifacts
|
||||
|
||||
|
||||
def test_validate_native_asset_passes_release_tag_and_upstream_tag(
|
||||
tmp_path: Path, monkeypatch
|
||||
):
|
||||
stage_dir = tmp_path / "release-7"
|
||||
stage_dir.mkdir()
|
||||
asset_path = stage_dir / "app-test-linux-x64-cuda12-newer.tar.gz"
|
||||
asset_path.write_bytes(b"bundle")
|
||||
sibling_checksums = stage_dir / VALIDATE.installer.DEFAULT_PUBLISHED_SHA256_ASSET
|
||||
sibling_checksums.write_text(
|
||||
"""
|
||||
{
|
||||
"schema_version": 1,
|
||||
"component": "llama.cpp",
|
||||
"release_tag": "release-7",
|
||||
"upstream_tag": "b9007",
|
||||
"source_commit": "deadbeef",
|
||||
"artifacts": {
|
||||
"llama.cpp-source-b9007.tar.gz": {
|
||||
"sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
"repo": "ggml-org/llama.cpp",
|
||||
"kind": "upstream-source"
|
||||
}
|
||||
}
|
||||
}
|
||||
""".strip()
|
||||
+ "\n",
|
||||
encoding = "utf-8",
|
||||
)
|
||||
asset = VALIDATE.LocalAsset(
|
||||
path = asset_path,
|
||||
tag = "test",
|
||||
name = asset_path.name,
|
||||
install_kind = "linux-cuda",
|
||||
source_kind = "app-bundle",
|
||||
native_runnable = True,
|
||||
bundle_profile = "cuda12-newer",
|
||||
runtime_line = "cuda12",
|
||||
)
|
||||
|
||||
host = VALIDATE.installer.HostInfo(
|
||||
system = "Linux",
|
||||
machine = "x86_64",
|
||||
is_windows = False,
|
||||
is_linux = True,
|
||||
is_macos = False,
|
||||
is_x86_64 = True,
|
||||
is_arm64 = False,
|
||||
nvidia_smi = None,
|
||||
driver_cuda_version = None,
|
||||
compute_caps = [],
|
||||
visible_cuda_devices = None,
|
||||
has_physical_nvidia = False,
|
||||
has_usable_nvidia = False,
|
||||
)
|
||||
monkeypatch.setattr(VALIDATE.installer, "detect_host", lambda: host)
|
||||
monkeypatch.setattr(
|
||||
VALIDATE.installer,
|
||||
"download_validation_model",
|
||||
lambda probe_path, cache_path: probe_path.write_bytes(b"probe"),
|
||||
)
|
||||
|
||||
captured = {}
|
||||
|
||||
def fake_validate_prebuilt_attempts(
|
||||
attempts,
|
||||
host,
|
||||
install_dir,
|
||||
work_dir,
|
||||
probe_path,
|
||||
*,
|
||||
requested_tag,
|
||||
llama_tag,
|
||||
release_tag,
|
||||
approved_checksums,
|
||||
initial_fallback_used = False,
|
||||
existing_install_dir = None,
|
||||
):
|
||||
captured["requested_tag"] = requested_tag
|
||||
captured["llama_tag"] = llama_tag
|
||||
captured["release_tag"] = release_tag
|
||||
staging_dir = VALIDATE.installer.create_install_staging_dir(install_dir)
|
||||
return attempts[0], staging_dir, False
|
||||
|
||||
monkeypatch.setattr(
|
||||
VALIDATE.installer,
|
||||
"validate_prebuilt_attempts",
|
||||
fake_validate_prebuilt_attempts,
|
||||
)
|
||||
|
||||
record = VALIDATE.validate_native_asset(
|
||||
asset,
|
||||
keep_temp = False,
|
||||
allow_network_source_hash = False,
|
||||
)
|
||||
|
||||
assert record.status == "PASS"
|
||||
assert captured == {
|
||||
"requested_tag": "test",
|
||||
"llama_tag": "b9007",
|
||||
"release_tag": "release-7",
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue