Files
searchi/tools/linux_archive_smoke.py

141 lines
8.0 KiB
Python

"""Check a real extracted Linux headless candidate using Google CPU inference.
This is an installed-layout smoke test, not a broad relevance benchmark or
clean-machine certification. No GPU provider or network setup is exercised.
"""
import argparse
import hashlib
import json
import os
from pathlib import Path
import shutil
import subprocess
import tarfile
import tempfile
import time
ROOT = Path(__file__).resolve().parents[1]
MAX_FILE = 256 * 1024 * 1024
def sha256(path):
with path.open("rb") as stream:
return hashlib.file_digest(stream, "sha256").hexdigest()
def extract_checked(archive_path, destination):
from package_linux import safe_name
with tarfile.open(archive_path, "r:*") as archive:
members = archive.getmembers()
if not 1 <= len(members) <= 128 or len({item.name for item in members}) != len(members):
raise ValueError("Invalid candidate member inventory")
for member in members:
safe_name(member.name)
if not member.isfile() or not 0 < member.size <= MAX_FILE:
raise ValueError("Unexpected candidate member")
manifest_member = archive.getmember("PACKAGE.json")
if manifest_member.size > 65536:
raise ValueError("Oversized candidate manifest")
manifest = json.load(archive.extractfile(manifest_member))
records = manifest["files"]
expected = {record["path"]: record for record in records}
if (manifest.get("platform") != "linux" or manifest.get("architecture") != "x86_64"
or len(expected) != len(records) or set(expected) != {member.name for member in members} - {"PACKAGE.json"}
or sum(member.size for member in members) > 1024 * 1024 * 1024):
raise ValueError("Candidate inventory does not cover archive")
for member in members:
target = destination / member.name
if not target.resolve().is_relative_to(destination.resolve()):
raise ValueError("Candidate path escapes extraction")
target.parent.mkdir(parents=True, exist_ok=True)
with archive.extractfile(member) as source, target.open("xb") as output:
shutil.copyfileobj(source, output, length=65536)
if member.name != "PACKAGE.json":
record = expected[member.name]
mode = int(record["mode"], 8)
if (target.stat().st_size != record["bytes"] or sha256(target) != record["sha256"]
or mode not in {0o644, 0o755} or member.mode != mode):
raise ValueError("Candidate bytes or permissions mismatch")
target.chmod(mode)
return manifest
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--archive", type=Path, required=True)
parser.add_argument("--models", type=Path, required=True)
parser.add_argument("--output", type=Path, required=True)
args = parser.parse_args()
if os.name != "posix" or not Path("/proc/self/exe").exists():
parser.error("Run natively on Linux")
models = args.models.resolve()
environment = dict(os.environ, SEARCHI_FORCE_CPU="1", GGML_DISABLE_VULKAN="1")
environment.pop("LD_LIBRARY_PATH", None)
environment.pop("GGML_BACKEND_PATH", None)
environment.pop("SEARCHI_FFMPEG_PATH", None)
environment.pop("SEARCHI_FFPROBE_PATH", None)
timings = {}
with tempfile.TemporaryDirectory(prefix="searchi archive QA ") as directory:
root = Path(directory)
installed = root / "installed"
installed.mkdir()
manifest = extract_checked(args.archive, installed)
cli, worker = installed / "searchi", installed / "searchi-gemma-worker"
corpus = root / "corpus"
corpus.mkdir()
(corpus / "supplier.md").write_text("The supplier partnership may be ended with sixty days written notice.\n", encoding="utf-8")
(corpus / "retry.py").write_text("import time\n\ndef fetch_with_backoff(operation):\n delay = 1\n for attempt in range(5):\n try:\n return operation()\n except Exception:\n time.sleep(delay)\n delay *= 2\n", encoding="utf-8")
shutil.copy2(ROOT / "crates/searchi-semantic/tests/fixtures/digup-speech.wav", corpus / "speech.wav")
db = root / "index.sqlite"
def run(label, arguments, json_output=False):
started = time.perf_counter()
try:
output = subprocess.run([str(cli), *map(str, arguments)], cwd=installed, env=environment,
check=True, capture_output=True, text=True, encoding="utf-8", timeout=180)
except subprocess.CalledProcessError as error:
args.output.parent.mkdir(parents=True, exist_ok=True)
with args.output.open("x", encoding="utf-8") as evidence:
json.dump({"complete": False, "failed_phase": label,
"exit_code": error.returncode, "stderr": error.stderr[-8192:],
"stdout": error.stdout[-8192:], "command_elapsed_ms": timings}, evidence, indent=2)
raise RuntimeError(f"{label} failed: {error.stderr[-4096:]}") from error
timings[label] = (time.perf_counter() - started) * 1000
return json.loads(output.stdout) if json_output else output.stdout
run("help", ["--help"])
run("index", ["index", "--db", db, "--root", corpus])
# Omit explicit decoder paths to exercise installed helper discovery.
report = run("embed", ["embed", "--db", db, "--model-dir", models,
"--embedding-worker", worker, "--cpu-threads", "1"], True)
if report["media_files"] != 1 or report["media_failures"] != 0 or report["passages"] != 2 or report["chunks"] < 3:
raise RuntimeError("Installed mixed document/code/audio indexing failed")
model_arguments = ["--model-dir", models, "--embedding-worker", worker, "--cpu-threads", "1"]
hits = run("semantic_search", ["search", "--db", db,
"Wie beenden wir die Zusammenarbeit mit dem Lieferanten?", "--json", *model_arguments], True)
if not hits or hits[0]["filename"] != "supplier.md" or "sixty days" not in hits[0]["snippet"] or not hits[0]["source"]:
raise RuntimeError("Installed Google semantic search lost the supplier passage")
code = run("code_search", ["search", "--db", db,
"recover from transient network failures with increasing delays", "--code-only", "--json", *model_arguments], True)
if not code or code[0]["filename"] != "retry.py" or code[0]["source"]["kind"] != "line":
raise RuntimeError("Installed scoped code search lost its citation")
restricted = run("strict_filter", ["search", "--db", db, "supplier cancellation",
"--extension", "pdf", "--json", *model_arguments], True)
if restricted:
raise RuntimeError("Installed semantic search violated extension filter")
evidence = {"complete": True, "platform": "linux-x86_64", "cpu_only": True,
"archive_sha256": sha256(args.archive), "archive_bytes": args.archive.stat().st_size,
"verified_files": len(manifest["files"]), "extraction_path_contains_spaces": True,
"automatic_media_helper_discovery": "passed", "embedding_report": report,
"semantic_top_filename": hits[0]["filename"], "code_source": code[0]["source"],
"strict_filter": "passed", "command_elapsed_ms": timings,
"timing_scope": "single deployment smoke samples; not retrieval/performance benchmarks",
"limitations": ["GPU untested", "desktop untested", "clean-machine/ABI coverage untested", "broad retrieval quality untested"]}
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(json.dumps(evidence, indent=2) + "\n", encoding="utf-8")
print(json.dumps({"passed": True, "verified_files": evidence["verified_files"], "media_files": report["media_files"]}))
if __name__ == "__main__":
main()