Reviewed PR 4741 which implements `llama.cpp` installer improvements, fingerprinting to skip redundant downloads, multi-release fallback planning, and better handling of file-in-use conflicts. All test cases passed and no logic issues were found during the code review. Co-authored-by: danielhanchen <23090290+danielhanchen@users.noreply.github.com>
659 lines
26 KiB
Python
659 lines
26 KiB
Python
"""
|
|
Comprehensive tests for PR #4562 bug fixes.
|
|
|
|
Tests cover:
|
|
- Bug 1: PS1 detached HEAD on re-run (fetch + checkout -B pattern)
|
|
- 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 (helper -> raw)
|
|
- Cross-platform binary_env (Linux, macOS, Windows)
|
|
- Edge cases: malformed JSON, empty responses, env overrides
|
|
|
|
Run: pytest tests/studio/install/test_pr4562_bugfixes.py -v
|
|
"""
|
|
|
|
import importlib.util
|
|
import json
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import textwrap
|
|
from pathlib import Path
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Load the module under test (same pattern as existing test files)
|
|
# ---------------------------------------------------------------------------
|
|
PACKAGE_ROOT = Path(__file__).resolve().parents[3]
|
|
MODULE_PATH = PACKAGE_ROOT / "studio" / "install_llama_prebuilt.py"
|
|
SPEC = importlib.util.spec_from_file_location(
|
|
"studio_install_llama_prebuilt", MODULE_PATH
|
|
)
|
|
assert SPEC is not None and SPEC.loader is not None
|
|
MOD = importlib.util.module_from_spec(SPEC)
|
|
sys.modules[SPEC.name] = MOD
|
|
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"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Helpers
|
|
# ---------------------------------------------------------------------------
|
|
def make_host(*, system: str) -> HostInfo:
|
|
"""Create a HostInfo for the given OS."""
|
|
return HostInfo(
|
|
system = system,
|
|
machine = "x86_64" if system != "Darwin" else "arm64",
|
|
is_windows = (system == "Windows"),
|
|
is_linux = (system == "Linux"),
|
|
is_macos = (system == "Darwin"),
|
|
is_x86_64 = (system != "Darwin"),
|
|
is_arm64 = (system == "Darwin"),
|
|
nvidia_smi = None,
|
|
driver_cuda_version = None,
|
|
compute_caps = [],
|
|
visible_cuda_devices = None,
|
|
has_physical_nvidia = False,
|
|
has_usable_nvidia = False,
|
|
)
|
|
|
|
|
|
BASH = "/bin/bash"
|
|
|
|
|
|
def run_bash(script: str, *, timeout: int = 10, env: dict | None = None) -> str:
|
|
"""Run a bash script fragment and return its stdout."""
|
|
run_env = os.environ.copy()
|
|
if env:
|
|
run_env.update(env)
|
|
result = subprocess.run(
|
|
[BASH, "-c", script],
|
|
capture_output = True,
|
|
text = True,
|
|
timeout = timeout,
|
|
env = run_env,
|
|
)
|
|
return result.stdout.strip()
|
|
|
|
|
|
# =========================================================================
|
|
# TEST GROUP A: binary_env across all platforms (Bug 4 + cross-platform)
|
|
# =========================================================================
|
|
class TestBinaryEnvCrossPlatform:
|
|
"""Test that binary_env returns correct library paths for all OSes."""
|
|
|
|
def test_linux_includes_binary_parent_in_ld_library_path(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
):
|
|
install_dir = tmp_path / "llama.cpp"
|
|
bin_dir = install_dir / "build" / "bin"
|
|
bin_dir.mkdir(parents = True)
|
|
binary_path = bin_dir / "llama-server"
|
|
binary_path.write_bytes(b"fake")
|
|
|
|
host = make_host(system = "Linux")
|
|
monkeypatch.setattr(MOD, "linux_runtime_dirs", lambda _bp: [])
|
|
|
|
env = binary_env(binary_path, install_dir, host)
|
|
ld_dirs = env["LD_LIBRARY_PATH"].split(os.pathsep)
|
|
assert str(bin_dir) in ld_dirs, f"build/bin not in LD_LIBRARY_PATH: {ld_dirs}"
|
|
assert (
|
|
str(install_dir) in ld_dirs
|
|
), f"install_dir not in LD_LIBRARY_PATH: {ld_dirs}"
|
|
|
|
def test_linux_binary_parent_comes_before_install_dir(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
):
|
|
"""build/bin should be searched before install_dir for .so files."""
|
|
install_dir = tmp_path / "llama.cpp"
|
|
bin_dir = install_dir / "build" / "bin"
|
|
bin_dir.mkdir(parents = True)
|
|
binary_path = bin_dir / "llama-server"
|
|
binary_path.write_bytes(b"fake")
|
|
|
|
host = make_host(system = "Linux")
|
|
monkeypatch.setattr(MOD, "linux_runtime_dirs", lambda _bp: [])
|
|
|
|
env = binary_env(binary_path, install_dir, host)
|
|
ld_dirs = env["LD_LIBRARY_PATH"].split(os.pathsep)
|
|
bin_idx = ld_dirs.index(str(bin_dir))
|
|
install_idx = ld_dirs.index(str(install_dir))
|
|
assert (
|
|
bin_idx < install_idx
|
|
), "binary_path.parent should come before install_dir"
|
|
|
|
def test_linux_deduplicates_when_binary_parent_equals_install_dir(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
):
|
|
"""When binary is directly in install_dir, no duplicate entries."""
|
|
install_dir = tmp_path / "llama.cpp"
|
|
install_dir.mkdir(parents = True)
|
|
binary_path = install_dir / "llama-server"
|
|
binary_path.write_bytes(b"fake")
|
|
|
|
host = make_host(system = "Linux")
|
|
monkeypatch.setattr(MOD, "linux_runtime_dirs", lambda _bp: [])
|
|
|
|
env = binary_env(binary_path, install_dir, host)
|
|
ld_dirs = [d for d in env["LD_LIBRARY_PATH"].split(os.pathsep) if d]
|
|
count = ld_dirs.count(str(install_dir))
|
|
assert count == 1, f"install_dir appears {count} times in LD_LIBRARY_PATH"
|
|
|
|
def test_linux_preserves_existing_ld_library_path(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
):
|
|
install_dir = tmp_path / "llama.cpp"
|
|
bin_dir = install_dir / "build" / "bin"
|
|
bin_dir.mkdir(parents = True)
|
|
binary_path = bin_dir / "llama-server"
|
|
binary_path.write_bytes(b"fake")
|
|
|
|
# Create real directories so dedupe_existing_dirs keeps them
|
|
custom_lib = tmp_path / "custom_lib"
|
|
other_lib = tmp_path / "other_lib"
|
|
custom_lib.mkdir()
|
|
other_lib.mkdir()
|
|
|
|
host = make_host(system = "Linux")
|
|
monkeypatch.setattr(MOD, "linux_runtime_dirs", lambda _bp: [])
|
|
original = os.environ.get("LD_LIBRARY_PATH", "")
|
|
os.environ["LD_LIBRARY_PATH"] = f"{custom_lib}:{other_lib}"
|
|
try:
|
|
env = binary_env(binary_path, install_dir, host)
|
|
finally:
|
|
if original:
|
|
os.environ["LD_LIBRARY_PATH"] = original
|
|
else:
|
|
os.environ.pop("LD_LIBRARY_PATH", None)
|
|
ld_dirs = env["LD_LIBRARY_PATH"].split(os.pathsep)
|
|
assert str(custom_lib.resolve()) in ld_dirs
|
|
assert str(other_lib.resolve()) in ld_dirs
|
|
|
|
def test_windows_includes_binary_parent_in_path(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
):
|
|
install_dir = tmp_path / "llama.cpp"
|
|
bin_dir = install_dir / "build" / "bin" / "Release"
|
|
bin_dir.mkdir(parents = True)
|
|
binary_path = bin_dir / "llama-server.exe"
|
|
binary_path.write_bytes(b"MZ")
|
|
|
|
host = make_host(system = "Windows")
|
|
monkeypatch.setattr(
|
|
MOD, "windows_runtime_dirs_for_runtime_line", lambda _rt: []
|
|
)
|
|
|
|
env = binary_env(binary_path, install_dir, host)
|
|
path_dirs = env["PATH"].split(os.pathsep)
|
|
assert str(bin_dir) in path_dirs, f"build/bin/Release not in PATH: {path_dirs}"
|
|
|
|
def test_macos_sets_dyld_library_path(
|
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
):
|
|
install_dir = tmp_path / "llama.cpp"
|
|
install_dir.mkdir(parents = True)
|
|
bin_dir = install_dir / "build" / "bin"
|
|
binary_path = bin_dir / "llama-server"
|
|
binary_path.parent.mkdir(parents = True)
|
|
binary_path.write_bytes(b"fake")
|
|
|
|
host = make_host(system = "Darwin")
|
|
monkeypatch.delenv("DYLD_LIBRARY_PATH", raising = False)
|
|
|
|
env = binary_env(binary_path, install_dir, host)
|
|
dyld_parts = [p for p in env["DYLD_LIBRARY_PATH"].split(os.pathsep) if p]
|
|
assert (
|
|
str(bin_dir) in dyld_parts
|
|
), f"build/bin not in DYLD_LIBRARY_PATH: {dyld_parts}"
|
|
assert (
|
|
str(install_dir) in dyld_parts
|
|
), f"install_dir not in DYLD_LIBRARY_PATH: {dyld_parts}"
|
|
# binary_path.parent (build/bin) should come before install_dir
|
|
assert dyld_parts.index(str(bin_dir)) < dyld_parts.index(str(install_dir))
|
|
|
|
|
|
# =========================================================================
|
|
# TEST GROUP B: resolve_requested_llama_tag (Python function)
|
|
# =========================================================================
|
|
class TestResolveRequestedLlamaTag:
|
|
def test_concrete_tag_passes_through(self):
|
|
assert resolve_requested_llama_tag("b8508") == "b8508"
|
|
|
|
def test_none_resolves_to_latest(self, monkeypatch: pytest.MonkeyPatch):
|
|
monkeypatch.setattr(MOD, "latest_upstream_release_tag", lambda: "b9999")
|
|
assert resolve_requested_llama_tag(None) == "b9999"
|
|
|
|
def test_latest_resolves_to_upstream(self, monkeypatch: pytest.MonkeyPatch):
|
|
monkeypatch.setattr(MOD, "latest_upstream_release_tag", lambda: "b1234")
|
|
assert resolve_requested_llama_tag("latest") == "b1234"
|
|
|
|
def test_empty_string_resolves_to_latest(self, monkeypatch: pytest.MonkeyPatch):
|
|
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)
|
|
# =========================================================================
|
|
class TestSetupShLogic:
|
|
"""Test setup.sh fragments via bash subprocess with controlled PATH."""
|
|
|
|
def test_cmake_missing_preserves_install(self, tmp_path: Path):
|
|
"""Bug 3: When cmake is missing, rm -rf should NOT run."""
|
|
llama_dir = tmp_path / "llama.cpp"
|
|
llama_dir.mkdir()
|
|
marker = llama_dir / "marker.txt"
|
|
marker.write_text("existing")
|
|
|
|
mock_bin = tmp_path / "mock_bin"
|
|
mock_bin.mkdir()
|
|
# Create mock git but NOT cmake
|
|
(mock_bin / "git").write_text("#!/bin/bash\nexit 0\n")
|
|
(mock_bin / "git").chmod(0o755)
|
|
|
|
# Build PATH: mock_bin first, then system dirs WITHOUT cmake
|
|
safe_dirs = [str(mock_bin)]
|
|
for d in os.environ.get("PATH", "").split(":"):
|
|
if d and not os.path.isfile(os.path.join(d, "cmake")):
|
|
safe_dirs.append(d)
|
|
|
|
script = textwrap.dedent(f"""\
|
|
export LLAMA_CPP_DIR="{llama_dir}"
|
|
if ! command -v cmake &>/dev/null; then
|
|
echo "cmake_missing"
|
|
elif ! command -v git &>/dev/null; then
|
|
echo "git_missing"
|
|
else
|
|
rm -rf "$LLAMA_CPP_DIR"
|
|
echo "would_clone"
|
|
fi
|
|
""")
|
|
output = run_bash(script, env = {"PATH": ":".join(safe_dirs)})
|
|
assert "cmake_missing" in output
|
|
assert marker.exists(), "Install dir was deleted despite cmake missing!"
|
|
|
|
def test_git_missing_preserves_install(self, tmp_path: Path):
|
|
"""Bug 3: When git is missing, rm -rf should NOT run."""
|
|
llama_dir = tmp_path / "llama.cpp"
|
|
llama_dir.mkdir()
|
|
marker = llama_dir / "marker.txt"
|
|
marker.write_text("existing")
|
|
|
|
mock_bin = tmp_path / "mock_bin"
|
|
mock_bin.mkdir()
|
|
# Create mock cmake but NOT git
|
|
(mock_bin / "cmake").write_text("#!/bin/bash\nexit 0\n")
|
|
(mock_bin / "cmake").chmod(0o755)
|
|
|
|
# Build PATH: mock_bin first, then system dirs WITHOUT git
|
|
safe_dirs = [str(mock_bin)]
|
|
for d in os.environ.get("PATH", "").split(":"):
|
|
if d and not os.path.isfile(os.path.join(d, "git")):
|
|
safe_dirs.append(d)
|
|
|
|
script = textwrap.dedent(f"""\
|
|
export LLAMA_CPP_DIR="{llama_dir}"
|
|
if ! command -v cmake &>/dev/null; then
|
|
echo "cmake_missing"
|
|
elif ! command -v git &>/dev/null; then
|
|
echo "git_missing"
|
|
else
|
|
rm -rf "$LLAMA_CPP_DIR"
|
|
echo "would_clone"
|
|
fi
|
|
""")
|
|
output = run_bash(script, env = {"PATH": ":".join(safe_dirs)})
|
|
assert "git_missing" in output
|
|
assert marker.exists(), "Install dir was deleted despite git missing!"
|
|
|
|
def test_both_present_runs_rm_and_clone(self, tmp_path: Path):
|
|
"""Bug 3: When both present, rm -rf runs before clone."""
|
|
llama_dir = tmp_path / "llama.cpp"
|
|
llama_dir.mkdir()
|
|
marker = llama_dir / "marker.txt"
|
|
marker.write_text("existing")
|
|
|
|
mock_bin = tmp_path / "mock_bin"
|
|
mock_bin.mkdir()
|
|
(mock_bin / "cmake").write_text("#!/bin/bash\nexit 0\n")
|
|
(mock_bin / "cmake").chmod(0o755)
|
|
(mock_bin / "git").write_text("#!/bin/bash\nexit 0\n")
|
|
(mock_bin / "git").chmod(0o755)
|
|
|
|
script = textwrap.dedent(f"""\
|
|
export PATH="{mock_bin}:$PATH"
|
|
export LLAMA_CPP_DIR="{llama_dir}"
|
|
if ! command -v cmake &>/dev/null; then
|
|
echo "cmake_missing"
|
|
elif ! command -v git &>/dev/null; then
|
|
echo "git_missing"
|
|
else
|
|
rm -rf "$LLAMA_CPP_DIR"
|
|
echo "would_clone"
|
|
fi
|
|
""")
|
|
output = run_bash(script)
|
|
assert "would_clone" in output
|
|
assert not marker.exists(), "Install dir should have been deleted"
|
|
|
|
def test_clone_uses_pinned_tag(self, tmp_path: Path):
|
|
"""Bug 2: git clone should use --branch with the resolved tag."""
|
|
mock_bin = tmp_path / "mock_bin"
|
|
mock_bin.mkdir()
|
|
log_file = tmp_path / "git_calls.log"
|
|
(mock_bin / "git").write_text(f'#!/bin/bash\necho "$*" >> {log_file}\nexit 0\n')
|
|
(mock_bin / "git").chmod(0o755)
|
|
|
|
script = textwrap.dedent(f"""\
|
|
export PATH="{mock_bin}:$PATH"
|
|
git clone --depth 1 --branch "b8508" https://github.com/ggml-org/llama.cpp.git /tmp/llama_test
|
|
""")
|
|
run_bash(script)
|
|
log = log_file.read_text()
|
|
assert "--branch b8508" in log, f"Expected --branch b8508 in: {log}"
|
|
|
|
def test_fetch_checkout_b_pattern(self, tmp_path: Path):
|
|
"""Bug 1: Re-run should use fetch + checkout -B, not pull + checkout FETCH_HEAD."""
|
|
mock_bin = tmp_path / "mock_bin"
|
|
mock_bin.mkdir()
|
|
log_file = tmp_path / "git_calls.log"
|
|
(mock_bin / "git").write_text(f'#!/bin/bash\necho "$*" >> {log_file}\nexit 0\n')
|
|
(mock_bin / "git").chmod(0o755)
|
|
|
|
llama_dir = tmp_path / "llama.cpp"
|
|
llama_dir.mkdir()
|
|
(llama_dir / ".git").mkdir()
|
|
|
|
script = textwrap.dedent(f"""\
|
|
export PATH="{mock_bin}:$PATH"
|
|
LlamaCppDir="{llama_dir}"
|
|
ResolvedLlamaTag="b8508"
|
|
if [ -d "$LlamaCppDir/.git" ]; then
|
|
git -C "$LlamaCppDir" fetch --depth 1 origin "$ResolvedLlamaTag"
|
|
if [ $? -ne 0 ]; then
|
|
echo "WARN: fetch failed"
|
|
else
|
|
git -C "$LlamaCppDir" checkout -B unsloth-llama-build FETCH_HEAD
|
|
fi
|
|
fi
|
|
""")
|
|
run_bash(script)
|
|
log = log_file.read_text()
|
|
assert "fetch --depth 1 origin b8508" in log
|
|
assert "checkout -B unsloth-llama-build FETCH_HEAD" in log
|
|
assert "pull" not in log, "Should use fetch, not pull"
|
|
|
|
def test_fetch_failure_warns_not_aborts(self, tmp_path: Path):
|
|
"""Bug 1: fetch failure should warn and continue, not set BuildOk=false."""
|
|
mock_bin = tmp_path / "mock_bin"
|
|
mock_bin.mkdir()
|
|
(mock_bin / "git").write_text(
|
|
'#!/bin/bash\nif echo "$*" | grep -q fetch; then exit 1; fi\nexit 0\n'
|
|
)
|
|
(mock_bin / "git").chmod(0o755)
|
|
|
|
llama_dir = tmp_path / "llama.cpp"
|
|
llama_dir.mkdir()
|
|
(llama_dir / ".git").mkdir()
|
|
|
|
script = textwrap.dedent(f"""\
|
|
export PATH="{mock_bin}:$PATH"
|
|
LlamaCppDir="{llama_dir}"
|
|
ResolvedLlamaTag="b8508"
|
|
BuildOk=true
|
|
if [ -d "$LlamaCppDir/.git" ]; then
|
|
git -C "$LlamaCppDir" fetch --depth 1 origin "$ResolvedLlamaTag"
|
|
if [ $? -ne 0 ]; then
|
|
echo "WARN: fetch failed -- using existing source"
|
|
else
|
|
git -C "$LlamaCppDir" checkout -B unsloth-llama-build FETCH_HEAD
|
|
fi
|
|
fi
|
|
echo "BuildOk=$BuildOk"
|
|
""")
|
|
output = run_bash(script)
|
|
assert "WARN: fetch failed" in output
|
|
assert "BuildOk=true" in output
|
|
|
|
|
|
# =========================================================================
|
|
# TEST GROUP D: "latest" tag resolution (bash subprocess)
|
|
# =========================================================================
|
|
class TestLatestTagResolution:
|
|
"""Test the fallback chain: helper resolver -> raw."""
|
|
|
|
RESOLVE_TEMPLATE = textwrap.dedent("""\
|
|
_REQUESTED_LLAMA_TAG="{requested_tag}"
|
|
_RESOLVED_LLAMA_TAG=""
|
|
_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"
|
|
""")
|
|
|
|
def _run_resolve(
|
|
self,
|
|
tmp_path: Path,
|
|
requested_tag: str,
|
|
resolved_tag: str,
|
|
resolve_status: int,
|
|
) -> str:
|
|
script = self.RESOLVE_TEMPLATE.format(
|
|
requested_tag = requested_tag,
|
|
resolved_tag = resolved_tag,
|
|
resolve_status = resolve_status,
|
|
)
|
|
return run_bash(script)
|
|
|
|
def test_helper_resolution_succeeds(self, tmp_path: Path):
|
|
output = self._run_resolve(
|
|
tmp_path,
|
|
"latest",
|
|
resolved_tag = "b8508",
|
|
resolve_status = 0,
|
|
)
|
|
assert output == "b8508"
|
|
|
|
def test_helper_resolution_falls_back_to_raw_requested_tag(self, tmp_path: Path):
|
|
output = self._run_resolve(
|
|
tmp_path,
|
|
"latest",
|
|
resolved_tag = "",
|
|
resolve_status = 1,
|
|
)
|
|
assert output == "latest"
|
|
|
|
def test_concrete_tag_passes_through_when_helper_fails(self, tmp_path: Path):
|
|
output = self._run_resolve(
|
|
tmp_path,
|
|
"b7777",
|
|
resolved_tag = "",
|
|
resolve_status = 1,
|
|
)
|
|
assert output == "b7777"
|
|
|
|
def test_env_override_unsloth_llama_tag(self):
|
|
output = run_bash(
|
|
'echo "${UNSLOTH_LLAMA_TAG:-latest}"',
|
|
env = {"UNSLOTH_LLAMA_TAG": "b1234"},
|
|
)
|
|
assert output == "b1234"
|
|
|
|
def test_env_unset_defaults_to_latest(self):
|
|
env = os.environ.copy()
|
|
env.pop("UNSLOTH_LLAMA_TAG", None)
|
|
output = run_bash('echo "${UNSLOTH_LLAMA_TAG:-latest}"', env = env)
|
|
assert output == "latest"
|
|
|
|
def test_env_empty_defaults_to_latest(self):
|
|
output = run_bash(
|
|
'echo "${UNSLOTH_LLAMA_TAG:-latest}"',
|
|
env = {"UNSLOTH_LLAMA_TAG": ""},
|
|
)
|
|
assert output == "latest"
|
|
|
|
|
|
# =========================================================================
|
|
# TEST GROUP E: Source file verification
|
|
# =========================================================================
|
|
class TestSourceCodePatterns:
|
|
"""Verify the actual source files contain the expected fix patterns."""
|
|
|
|
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()
|
|
# 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")
|
|
idx_rm = block.find("rm -rf")
|
|
assert idx_rm > idx_cmake, "rm -rf should come after cmake check"
|
|
assert idx_rm > idx_git, "rm -rf should come after git check"
|
|
|
|
def test_setup_sh_clone_uses_branch_tag(self):
|
|
"""git clone in source-build should use --branch via _CLONE_BRANCH_ARGS."""
|
|
content = SETUP_SH.read_text()
|
|
# The clone line should use _CLONE_BRANCH_ARGS (which conditionally includes --branch)
|
|
assert (
|
|
"_CLONE_BRANCH_ARGS" in content
|
|
), "Clone should use _CLONE_BRANCH_ARGS array"
|
|
assert (
|
|
'--branch "$_RESOLVED_LLAMA_TAG"' in content
|
|
), "_CLONE_BRANCH_ARGS should be set to --branch $_RESOLVED_LLAMA_TAG"
|
|
# Verify the guard: --branch is only used when tag is not "latest"
|
|
assert (
|
|
'_RESOLVED_LLAMA_TAG" != "latest"' in content
|
|
), "Should guard against literal 'latest' tag"
|
|
|
|
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()
|
|
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."""
|
|
content = SETUP_PS1.read_text()
|
|
assert "checkout -B unsloth-llama-build" in content
|
|
assert "checkout --force FETCH_HEAD" not in content
|
|
|
|
def test_setup_ps1_clone_uses_branch_tag(self):
|
|
"""PS1 clone should use --branch with the resolved tag."""
|
|
content = SETUP_PS1.read_text()
|
|
assert "--branch" in content and "$ResolvedLlamaTag" in content
|
|
# The old commented-out line should be gone
|
|
assert "# git clone --depth 1 --branch" not in content
|
|
|
|
def test_setup_ps1_no_git_pull(self):
|
|
"""PS1 should use fetch, not pull (which fails in detached HEAD)."""
|
|
content = SETUP_PS1.read_text()
|
|
# In the source-build section, there should be no "git pull"
|
|
# (git pull is only valid on a branch)
|
|
lines = content.splitlines()
|
|
for i, line in enumerate(lines):
|
|
stripped = line.strip()
|
|
if "git pull" in stripped and not stripped.startswith("#"):
|
|
# Check context -- should not be in the llama.cpp build section
|
|
# Allow git pull in other contexts
|
|
context = "\n".join(lines[max(0, i - 5) : i + 5])
|
|
if "LlamaCppDir" in context:
|
|
pytest.fail(
|
|
f"Found 'git pull' in llama.cpp build section at line {i+1}"
|
|
)
|
|
|
|
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()
|
|
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."""
|
|
content = MODULE_PATH.read_text()
|
|
# Find the binary_env function
|
|
in_func = False
|
|
in_linux = False
|
|
found = False
|
|
for line in content.splitlines():
|
|
if "def binary_env(" in line:
|
|
in_func = True
|
|
elif in_func and line and not line[0].isspace() and "def " in line:
|
|
break
|
|
if in_func and "host.is_linux" in line:
|
|
in_linux = True
|
|
if in_linux and "binary_path.parent" in line:
|
|
found = True
|
|
break
|
|
assert found, "binary_path.parent not found in Linux branch of binary_env"
|