Files
Strata/tools/test_strata_mcp.py
T

1192 lines
69 KiB
Python

"""tools/test_strata_mcp.py - tests for tools/strata_mcp.py (Strata's MCP server), standard library only.
python -m unittest tools/test_strata_mcp.py -v
Setup and the model server are fakes (a temporary Strata folder with a stand-in setup.py and serve/server.py), so
nothing is downloaded and no GPU is used: the JSON-RPC handshake, argument checks, install / start / stop with real
background processes, status against a fake HTTP server, and that the built-in model table still matches setup.py.
"""
from __future__ import annotations
import io
import json
import os
import socket
import subprocess
import sys
import shutil
import tempfile
import threading
import time
import unittest
from unittest import mock
from http.server import BaseHTTPRequestHandler, HTTPServer
from pathlib import Path
HERE = Path(__file__).resolve().parent
sys.path.insert(0, str(HERE))
import strata_mcp as M # noqa: E402
FAKE_SETUP = r'''
import json, sys, time
from pathlib import Path
def main():
root = Path(__file__).resolve().parent
(root / "setup-args.json").write_text(json.dumps(sys.argv[1:]))
print("Strata - fake setup", flush=True)
print("\n=== Step 1: checking your PC ===", flush=True)
print(" [ok] GPU: fake", flush=True)
print("\n=== Step 5: downloading Qwen3.8-Flash-Next Q2_0 ===", flush=True)
for pct in (10, 20, 30):
print(f"\r model.gguf: {pct * 0.5:.2f} / 50.00 GB ({pct}%) ", end="", flush=True)
print(flush=True)
if (root / "slow").exists():
end = time.time() + 30
while not (root / "go").exists() and time.time() < end:
time.sleep(0.1)
if (root / "fail").exists():
print("\n [X] not enough free disk space", flush=True)
print(" use --models-dir on a bigger drive", flush=True)
sys.exit(1)
a = sys.argv
model = a[a.index("--model") + 1].lower()
cfg = {"exe": sys.executable, "args": ["--max-context", a[a.index("--context") + 1]], "port": 8080,
"model_name": "qwen3.8-flash-next-" + model, "log": str(root / f"strata-{model}.log")}
(root / f"strata-{model}.json").write_text(json.dumps(cfg))
print("All set.", flush=True)
if __name__ == "__main__":
main()
'''
FAKE_SERVER = r'''
import json, os, signal, sys, time
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
a = sys.argv
port = int(a[a.index("--port") + 1])
cfg = json.loads(Path(a[a.index("--config") + 1]).read_text())
root = Path(__file__).resolve().parent.parent
print("loading the model (fake) ...", flush=True)
if cfg.get("crash"):
print("engine failed: out of memory (fake)", flush=True)
sys.exit(3)
time.sleep(cfg.get("delay", 0))
state = {"loaded": True}
class H(BaseHTTPRequestHandler):
def log_message(self, *x):
pass
def js(self, code, obj):
b = json.dumps(obj).encode()
self.send_response(code)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(b)))
self.end_headers()
self.wfile.write(b)
def do_GET(self):
p = self.path.split("?")[0]
if p == "/health":
self.js(200, {"status": "ok", "service": "strata", "model": cfg["model_name"], "max_context": 32768,
"images": False, "api_key": False, "loaded": state["loaded"]})
elif p == "/status":
self.js(200, {"busy": bool(cfg.get("busy")), "queued": 0})
elif p == "/v1/status":
self.js(200, {"service": "strata", "engine": "0.1.32", "uptime_s": 5, "activity": {"requests": 0},
"machine": {"gpu": {"name": "Fake GPU", "used_mib": 11000, "total_mib": 12227},
"ram": {"used_gib": 40.0, "total_gib": 63.1}}})
else:
self.js(404, {"error": {"message": "not found"}})
def do_POST(self):
n = int(self.headers.get("Content-Length") or 0)
body = json.loads(self.rfile.read(n) or b"{}")
p = self.path.split("?")[0]
if p == "/unload":
state["loaded"] = False
with open(root / "unloaded.txt", "a") as f:
f.write(str(port) + "\n")
self.js(200, {"status": "unloaded"})
elif p == "/v1/chat/completions":
with open(root / "bench-request.json", "w") as f:
json.dump(body, f)
self.js(200, {"model": cfg["model_name"], "choices": [{"message": {"content": "x"}, "finish_reason": "length"}],
"usage": {"prompt_tokens": 30, "completion_tokens": body.get("max_tokens", 1)},
"timings": {"predicted_per_second": 61.5, "prompt_per_second": 400.0}})
else:
self.js(404, {})
httpd = ThreadingHTTPServer(("127.0.0.1", port), H)
def term(*_):
print("[strata] stopped (fake)", flush=True)
os._exit(0)
signal.signal(signal.SIGTERM, term)
print(f"ready: http://127.0.0.1:{port}/v1", flush=True)
httpd.serve_forever()
'''
def free_port() -> int:
s = socket.socket()
s.bind(("127.0.0.1", 0))
p = s.getsockname()[1]
s.close()
return p
def wait_for(cond, seconds=30.0):
end = time.time() + seconds
while time.time() < end:
if cond():
return True
time.sleep(0.1)
return cond()
FAKE_HW = {"os": "TestOS 1", "ram_gb": 64.0, "cpu": {"name": "Fake CPU", "cores": 12, "avx2": True, "avx512": True},
"gpus": [{"index": 0, "name": "NVIDIA GeForce RTX 5070", "vram_gb": 11.9, "arch": "120", "vendor": "nvidia",
"problem": None, "usable": True}]}
class FakeRoot(unittest.TestCase):
"""A temporary Strata folder: fake setup.py and serve/server.py, its own settings file (data folder)."""
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
base = Path(self.tmp.name)
self.root = base / "Strata"
(self.root / "serve").mkdir(parents=True)
(self.root / "setup.py").write_text(FAKE_SETUP)
(self.root / "serve" / "server.py").write_text(FAKE_SERVER)
self.env_backup = {k: os.environ.get(k) for k in ("APPDATA", "XDG_CONFIG_HOME")}
os.environ["APPDATA"] = os.environ["XDG_CONFIG_HOME"] = str(base / "config")
self.strata = M.Strata(self.root)
self.strata.python_override = sys.executable
self.strata.health_timeout = 1.0
self.strata._hardware = lambda: dict(FAKE_HW)
self.strata.disk_free = lambda p: 1000.0
self.tools = M.Tools(self.strata)
self.extra = []
# the tests must never see a Strata server that happens to run on the real default port on this PC
self._default_port = M.DEFAULT_PORT
M.DEFAULT_PORT = free_port()
def tearDown(self):
M.DEFAULT_PORT = self._default_port
for p in self.extra:
if p.poll() is None:
p.kill()
p.wait(10)
srv = self.strata.state("server")
if srv and M.proc_alive(srv.get("pid"), srv.get("ident")):
M.proc_kill_tree(srv["pid"], srv["ident"])
M.wait_gone(srv["pid"], srv["ident"], 10)
job = self.strata.state("install")
if job and M.proc_alive(job.get("pid"), job.get("ident")):
M.proc_kill_tree(job["pid"], job["ident"])
M.wait_gone(job["pid"], job["ident"], 10)
for p in self.strata.children:
try:
p.wait(5)
except subprocess.TimeoutExpired:
pass
for k, v in self.env_backup.items():
if v is None:
os.environ.pop(k, None)
else:
os.environ[k] = v
for _ in range(20): # Windows: a log may still be closing
try:
self.tmp.cleanup()
break
except OSError:
time.sleep(0.25)
def call(self, name, args=None):
"""A tools/call through the JSON-RPC layer: (result dict, isError)."""
srv = M.McpServer(self.strata, io.BytesIO())
r = srv.handle({"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {"name": name, "arguments": args or {}}})
res = r["result"]
return json.loads(res["content"][0]["text"]), res["isError"]
def write_config(self, tag="q2_0", port=8080, **extra):
cfg = {"exe": sys.executable, "args": ["--max-context", "32768"], "port": port,
"model_name": f"qwen3.8-flash-next-{tag}", "log": str(self.root / f"strata-{tag}.log"), **extra}
(self.root / f"strata-{tag}.json").write_text(json.dumps(cfg))
(self.root / f"strata-{tag}.log").write_text("engine line 1\nengine line 2\n")
return cfg
# ------------------------------------------------------------------------------------------------ the protocol
class Protocol(FakeRoot):
def run_lines(self, msgs):
inp = io.BytesIO(("\n".join(m if isinstance(m, str) else json.dumps(m) for m in msgs) + "\n").encode())
out = io.BytesIO()
M.McpServer(self.strata, out).serve(inp)
return {m.get("id"): m for m in (json.loads(x) for x in out.getvalue().decode().splitlines())}
def test_handshake_list_call(self):
r = self.run_lines([
{"jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": {"protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": {"name": "t", "version": "1"}}},
{"jsonrpc": "2.0", "method": "notifications/initialized"},
{"jsonrpc": "2.0", "id": 2, "method": "tools/list"},
{"jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {"name": "strata_models", "arguments": {}}},
{"jsonrpc": "2.0", "id": 4, "method": "ping"},
])
init = r[1]["result"]
self.assertEqual(init["protocolVersion"], "2025-06-18")
self.assertIn("tools", init["capabilities"])
self.assertEqual(init["serverInfo"]["name"], "strata")
names = [t["name"] for t in r[2]["result"]["tools"]]
self.assertEqual(names, ["strata_status", "strata_models", "strata_remove", "strata_install", "strata_start", "strata_stop",
"strata_logs", "strata_benchmark", "strata_connect_info"])
for t in r[2]["result"]["tools"]:
self.assertEqual(t["inputSchema"]["type"], "object")
self.assertFalse(t["inputSchema"]["additionalProperties"])
self.assertGreater(len(t["description"]), 60)
call = r[3]["result"]
self.assertFalse(call["isError"])
self.assertIn("families", call["structuredContent"])
self.assertEqual(json.loads(call["content"][0]["text"])["recommendation"]["model"], "IQ3_S")
self.assertEqual(r[4]["result"], {})
self.assertNotIn(None, r) # the notification got no answer
def test_older_protocol_and_errors(self):
r = self.run_lines([
{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2024-11-05"}},
"{not json",
{"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "rm_rf", "arguments": {}}},
{"jsonrpc": "2.0", "id": 3, "method": "no/such"},
{"jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": {"name": "strata_logs", "arguments": []}},
])
self.assertEqual(r[1]["result"]["protocolVersion"], "2024-11-05")
self.assertEqual(r[None]["error"]["code"], -32700)
self.assertEqual(r[2]["error"]["code"], -32602)
self.assertEqual(r[3]["error"]["code"], -32601)
self.assertTrue(r[4]["result"]["isError"])
self.assertNotIn("structuredContent", r[4]["result"]) # 2024-11-05 has no structured results
def test_real_stdio_process(self):
"""The script itself over a pipe: stdout carries only JSON-RPC lines."""
msgs = [{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2025-06-18"}},
{"jsonrpc": "2.0", "id": 2, "method": "tools/list"},
{"jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": {"name": "strata_logs", "arguments": {"source": "setup"}}}]
p = subprocess.run([sys.executable, str(HERE / "strata_mcp.py"), "--root", str(self.root)],
input="\n".join(json.dumps(m) for m in msgs) + "\n", capture_output=True, text=True,
timeout=60, env=dict(os.environ))
lines = [json.loads(x) for x in p.stdout.splitlines()]
self.assertEqual(sorted(m["id"] for m in lines), [1, 2, 3])
self.assertEqual(len(next(m for m in lines if m["id"] == 2)["result"]["tools"]), 9)
self.assertIn("ready", p.stderr)
def test_not_a_strata_folder(self):
p = subprocess.run([sys.executable, str(HERE / "strata_mcp.py"), "--root", self.tmp.name], input="",
capture_output=True, text=True, timeout=60)
self.assertEqual(p.returncode, 2)
# ------------------------------------------------------------------------------------------------ validation
class Validation(FakeRoot):
def assertRejected(self, tool, args, text):
res, err = self.call(tool, args)
self.assertTrue(err, f"{tool} {args} was accepted: {res}")
self.assertIn(text, res["error"])
def test_install_arguments(self):
self.assertRejected("strata_install", {"model": "Q9_X"}, "model must be one of")
self.assertRejected("strata_install", {"family": "llama"}, "family must be one of")
self.assertRejected("strata_install", {"context": 100}, "context must be between")
self.assertRejected("strata_install", {"gpus": "0;rm -rf /"}, "gpus=")
self.assertRejected("strata_install", {"gpus": "0 && calc"}, "gpus=")
self.assertRejected("strata_install", {"gpu": -1}, "between")
self.assertRejected("strata_install", {"gpu": "1; calc"}, "whole number")
self.assertRejected("strata_install", {"gpu": 0, "gpus": "0,1"}, "not both")
self.assertRejected("strata_install", {"port": 80}, "between")
self.assertRejected("strata_install", {"backend": "rocm"}, "backend must be one of")
self.assertRejected("strata_install", {"command": "setup.py --build"}, "unknown argument")
res, err = self.call("strata_install", {"family": "swift", "model": "IQ3_S"})
self.assertFalse(err, res) # Swift 1.5 got its IQ3_S (same shard layout as its IQ2_XS)
self.assertIn("--family swift --model IQ3_S", res["plan"]["setup_command"])
res, err = self.call("strata_install", {"family": "unsloth", "model": "UD-Q4_K_XL", "vision": "yes"})
self.assertFalse(err, res) # #967: images are allowed with UD-Q4_K_XL (setup warns)
self.assertEqual(res["plan"]["images"], "yes")
self.assertRejected("strata_install", {"vision": "yes\nrm"}, "control characters")
def test_amd_vision_follows_the_picture_rule(self):
"""Owner rule 2026-10-18: pictures are on for AMD too, on Linux and Windows (setup picks the reader: CPU under 24 GB, GPU from 24 GB)."""
for win in (False, True):
with mock.patch.object(M, "WIN", win):
for asked in ("yes", "gpu", "cpu"):
res, err = self.call("strata_install", {"backend": "hip", "vision": asked})
self.assertFalse(err, res)
self.assertEqual(res["plan"]["images"], asked)
self.assertIn("--vision " + asked, res["plan"]["setup_command"])
res, err = self.call("strata_install", {"backend": "hip", "vision": "no"})
self.assertFalse(err, res)
self.assertEqual(res["plan"]["images"], "no")
def test_pictures_default_on(self):
"""Nothing asked: pictures are on where the model can read them (any backend), off for a model that cannot."""
for backend in (None, "cuda", "hip"):
args = {"backend": backend} if backend else {}
res, err = self.call("strata_install", args)
self.assertFalse(err, res)
self.assertEqual(res["plan"]["images"], "yes")
self.assertIn("--vision yes", res["plan"]["setup_command"])
res, err = self.call("strata_install", {"vision": "no"})
self.assertFalse(err, res)
self.assertEqual(res["plan"]["images"], "no")
def test_data_dir_paths(self):
self.assertRejected("strata_install", {"data_dir": "models"}, "absolute")
self.assertRejected("strata_install", {"data_dir": str(self.root.parent / "x" / ".." / "Strata-x")}, "'..'")
self.assertRejected("strata_install", {"data_dir": str(self.root.parent / "Documents")}, "named Strata")
self.assertRejected("strata_install", {"data_dir": str(self.root.parent / "nope" / "Strata-data")},
"does not exist")
self.assertRejected("strata_install", {"data_dir": "\\\\server\\share\\Strata-data"}, "network")
sysdir = (os.environ.get("SystemRoot", "C:\\Windows") + "\\Strata-data") if M.WIN else "/etc/Strata-data"
self.assertRejected("strata_install", {"data_dir": sysdir}, "system folder")
ok = [self.root.parent / "Strata-data", self.root / "models-here", self.root.parent / "Strata-big"]
for d in ok:
self.assertEqual(M.norm(self.tools.check_data_dir(str(d))), M.norm(d))
def test_the_persons_own_data_folder_is_accepted_whatever_it_is_called(self):
"""The app writes the folder the person chose into the settings file (apps/host model-folder.mjs); an AI tool naming a new
folder still needs a Strata... name."""
chosen = self.root.parent / "my-big-disk"
chosen.mkdir()
self.assertRejected("strata_install", {"data_dir": str(chosen)}, "named Strata")
settings = self.tools.s.settings_path()
settings.parent.mkdir(parents=True, exist_ok=True)
settings.write_text(json.dumps({"data_dir": str(chosen)}))
self.assertEqual(M.norm(self.tools.check_data_dir(str(chosen))), M.norm(chosen))
def test_other_tools_arguments(self):
self.assertRejected("strata_start", {"model": "../../etc/passwd"}, "not valid")
self.assertRejected("strata_start", {"model": "q2_0"}, "no model is installed")
self.write_config("q2_0")
self.assertRejected("strata_start", {"model": "iq3_s"}, "no installed model 'iq3_s'")
self.assertRejected("strata_start", {"wait_seconds": 100000}, "between")
self.assertRejected("strata_logs", {"lines": 0}, "between")
self.assertRejected("strata_logs", {"source": "/etc/passwd"}, "source must be one of")
self.assertRejected("strata_benchmark", {"max_tokens": 100000}, "between")
self.assertRejected("strata_stop", {"force": "yes"}, "true or false")
def test_engine_log_outside_is_not_read(self):
self.write_config("q2_0", log=str(Path(self.tmp.name).parent / "elsewhere.log"))
res, err = self.call("strata_logs", {"source": "engine", "model": "q2_0"})
self.assertTrue(err)
self.assertIn("outside the Strata folder", res["error"])
self.write_config("q2_0")
res, err = self.call("strata_logs", {"source": "engine"})
self.assertFalse(err)
self.assertEqual(res["lines"], ["engine line 1", "engine line 2"])
# ------------------------------------------------------------------------------------------------ install
class Install(FakeRoot):
def wait_job(self):
self.assertTrue(wait_for(lambda: not self.strata.install_job()["running"], 60))
def test_plan_then_install(self):
res, err = self.call("strata_install", {})
self.assertFalse(err)
self.assertIn("Nothing was done yet", res["summary"])
self.assertEqual((res["plan"]["family"], res["plan"]["model"], res["plan"]["context"]), ("qwen", "IQ3_S", 131072))
self.assertFalse((self.root / "setup-args.json").exists())
self.assertIsNone(self.strata.install_job())
res, err = self.call("strata_install", {"model": "Q2_0", "context": 65536, "vision": "no", "confirm": True})
self.assertFalse(err, res)
self.assertIn("started in the background", res["summary"])
self.wait_job()
args = json.loads((self.root / "setup-args.json").read_text())
self.assertEqual(args[:2], ["--yes", "--no-start"])
for pair in (["--family", "qwen"], ["--model", "Q2_0"], ["--context", "65536"], ["--vision", "no"]):
i = args.index(pair[0])
self.assertEqual(args[i:i + 2], pair)
res, err = self.call("strata_install", {})
self.assertEqual(res["install"]["result"], "installed")
self.assertEqual(res["install"]["exit_code"], 0)
self.assertEqual(res["next"], "strata_start")
st, _ = self.call("strata_status", {"hardware": False})
self.assertEqual([m["model"] for m in st["installed"]["models"]], ["q2_0"])
def test_progress_while_running_and_cancel(self):
(self.root / "slow").write_text("")
res, err = self.call("strata_install", {"family": "coder", "confirm": True})
self.assertFalse(err, res)
self.assertTrue(wait_for(lambda: (self.strata.install_job() or {}).get("download") is not None, 30))
res, err = self.call("strata_install", {"model": "IQ3_S", "confirm": True}) # a second call: progress only
self.assertFalse(err)
self.assertIn("an install is running", res["summary"])
self.assertEqual(res["install"]["step"], "5/7: downloading Qwen3.8-Flash-Next Q2_0")
self.assertEqual(res["install"]["download"]["percent"], 30)
res, err = self.call("strata_start", {})
self.assertTrue(err)
self.assertIn("install is still running", res["error"])
res, err = self.call("strata_install", {"cancel": True})
self.assertIn("stopped", res["summary"])
self.assertFalse(self.strata.install_job()["running"])
def test_failure_is_reported(self):
(self.root / "fail").write_text("")
self.call("strata_install", {"model": "Q2_0", "confirm": True})
self.wait_job()
res, _ = self.call("strata_install", {})
self.assertEqual(res["install"]["result"], "failed")
self.assertIn("not enough free disk space - use --models-dir on a bigger drive", res["install"]["error"])
def test_disk_space_is_checked(self):
self.strata.disk_free = lambda p: 10.0
res, err = self.call("strata_install", {"model": "Q2_0"})
self.assertIn("not enough free disk space", res["plan"]["disk_short"])
res, err = self.call("strata_install", {"model": "Q2_0", "confirm": True})
self.assertTrue(err)
self.assertIsNone(self.strata.install_job())
# ------------------------------------------------------------------------------------------------ start / stop / status
class StartStop(FakeRoot):
def test_start_status_bench_stop(self):
port = free_port()
self.write_config("q2_0", port=port, delay=1.5)
res, err = self.call("strata_start", {"wait_seconds": 30})
self.assertFalse(err, res)
self.assertIn("Strata is running", res["summary"])
pid = res["server"]["pid"]
st, _ = self.call("strata_status", {"hardware": False})
self.assertIn(f"running on port {port}", st["summary"])
srv = st["running"][0]
self.assertEqual(srv["engine_version"], "0.1.32")
self.assertEqual(srv["gpu"]["total_mib"], 12227)
self.assertIn("this MCP server", srv["started_by"])
res, err = self.call("strata_start", {}) # already running: nothing new
self.assertIn("already running", res["summary"])
b, err = self.call("strata_benchmark", {"max_tokens": 64})
self.assertFalse(err, b)
self.assertEqual(b["output_tok_s"], 61.5)
sent = json.loads((self.root / "bench-request.json").read_text())
self.assertEqual((sent["temperature"], sent["max_tokens"], sent["reasoning_effort"]), (0, 64, "none"))
c, _ = self.call("strata_connect_info", {})
self.assertEqual(c["openai_base_url"], f"http://127.0.0.1:{port}/v1")
logs, _ = self.call("strata_logs", {"source": "server"})
self.assertTrue(any(line.startswith("ready:") for line in logs["lines"]))
res, err = self.call("strata_stop", {})
self.assertFalse(err, res)
self.assertIn("Strata stopped", res["summary"])
self.assertEqual(res["engine_unloaded"], "unloaded")
self.assertEqual((self.root / "unloaded.txt").read_text().split(), [str(port)])
ident = M.proc_identity(pid)
self.assertIsNone(ident)
st, _ = self.call("strata_status", {"hardware": False})
self.assertEqual(st["running"], [])
res, _ = self.call("strata_stop", {})
self.assertEqual(res["summary"], "Strata is not running")
def test_start_reports_a_crash(self):
self.write_config("q2_0", port=free_port(), crash=True)
res, err = self.call("strata_start", {"wait_seconds": 30})
self.assertTrue(err)
self.assertIn("out of memory (fake)", res["error"])
self.assertEqual(self.strata.state("server"), {})
def test_loading_then_ready(self):
port = free_port()
self.write_config("q2_0", port=port, delay=3)
res, err = self.call("strata_start", {"wait_seconds": 0})
self.assertIn("loading", res["summary"])
st, _ = self.call("strata_status", {"hardware": False})
self.assertIn("loading", st["summary"])
self.assertTrue(wait_for(lambda: self.strata.probe(port) is not None, 30))
def test_stop_while_busy_needs_force(self):
port = free_port()
self.write_config("q2_0", port=port, busy=True)
self.call("strata_start", {"wait_seconds": 30})
res, err = self.call("strata_stop", {})
self.assertTrue(err)
self.assertIn("force=true", res["error"])
res, err = self.call("strata_stop", {"force": True})
self.assertFalse(err, res)
def test_external_server_is_only_unloaded(self):
port = free_port()
self.write_config("q2_0", port=port)
p = subprocess.Popen([sys.executable, str(self.root / "serve" / "server.py"), "--config",
str(self.root / "strata-q2_0.json"), "--port", str(port)],
stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
self.extra.append(p)
self.assertTrue(wait_for(lambda: self.strata.probe(port) is not None, 30))
st, _ = self.call("strata_status", {"hardware": False})
self.assertIn("outside this MCP server", st["running"][0]["started_by"])
res, err = self.call("strata_start", {})
self.assertIn("started outside this MCP server", res["summary"])
res, err = self.call("strata_stop", {})
self.assertFalse(err, res)
self.assertIn("only its model was unloaded", res["summary"])
time.sleep(0.5)
self.assertIsNone(p.poll()) # the server itself was not touched
def test_never_kills_an_unrelated_process(self):
other = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(60)"])
self.extra.append(other)
# a stale record: this process id, but another start time (a reused id)
self.strata.save_state("server", {"pid": other.pid, "ident": "win:1" if M.WIN else "linux:1",
"port": free_port(), "model": "q2_0"})
res, _ = self.call("strata_stop", {})
self.assertEqual(res["summary"], "Strata is not running")
self.assertFalse(M.proc_terminate(other.pid, "linux:1"))
time.sleep(0.3)
self.assertIsNone(other.poll())
def test_status_sees_other_programs_on_the_port(self):
class H(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(404)
self.end_headers()
def log_message(self, *a):
pass
httpd = HTTPServer(("127.0.0.1", 0), H)
port = httpd.server_address[1]
threading.Thread(target=httpd.serve_forever, daemon=True).start()
try:
self.write_config("q2_0", port=port)
st, _ = self.call("strata_status", {"hardware": False})
self.assertEqual(st["running"], [])
self.assertEqual(st["ports_used_by_other_programs"][0]["port"], port)
res, err = self.call("strata_start", {})
self.assertTrue(err)
self.assertIn("used by another program", res["error"])
finally:
httpd.shutdown()
httpd.server_close()
# ------------------------------------------------------------------------------------------------ helpers
class Helpers(unittest.TestCase):
def test_progress_from_setup_output(self):
with tempfile.TemporaryDirectory() as d:
f = Path(d) / "setup.log"
f.write_text("=== Step 4: the Strata engine ===\n [ok] engine\n=== Step 5: downloading X ===\n"
"\r a.gguf: 1.00 / 50.00 GB (2%) \r a.gguf: 25.00 / 50.00 GB (50%) \n")
p = M.install_progress(M.read_tail(f, 50))
self.assertEqual(p["step"], "5/7: downloading X")
self.assertEqual(p["download"], {"file": "a.gguf", "done_gb": 25.0, "total_gb": 50.0, "percent": 50})
self.assertNotIn("error", p)
def test_builtin_table_matches_setup(self):
s = M.Strata(HERE.parent)
S = s.setup_module()
self.assertIsNotNone(S, "the repository's setup.py did not import")
self.assertEqual(list(S.MODELS), list(M.FALLBACK_MODELS))
for m, d in S.MODELS.items():
for k in ("download_gb", "ram_gb", "arena_gb"):
self.assertEqual(d[k], M.FALLBACK_MODELS[m][k], f"{m} {k}")
for k in ("experimental", "vision"):
self.assertEqual(d.get(k), M.FALLBACK_MODELS[m].get(k), f"{m} {k}")
self.assertEqual(d.get("families", ("qwen", "swift")), M.FALLBACK_MODELS[m].get("families", ("qwen", "swift")))
self.assertEqual(list(S.FAMILIES), list(M.FALLBACK_FAMILIES))
for f, d in S.FAMILIES.items():
self.assertEqual(d["tag"], M.FALLBACK_FAMILIES[f]["tag"])
self.assertEqual(list(S.CONTEXTS), M.FALLBACK_CONTEXTS)
def test_unsloth_sizes(self):
"""0.1.39: UD-IQ4_XS is a regular size, listed first; MODEL-UPDATE Phase 2: UD-Q4_K_XL is no longer experimental,
and UD-Q5_K_XL, UD-Q6_K_XL and Q8_0 follow by size."""
s = M.Strata(HERE.parent)
for models in (s.tables()[0], M.FALLBACK_MODELS):
self.assertEqual(s.sizes_of(models, "unsloth"), ["UD-IQ4_XS", "UD-Q4_K_XL", "UD-Q5_K_XL", "UD-Q6_K_XL", "Q8_0", "UD-IQ1_M", "UD-Q2_0",
"UD-IQ2_XS", "UD-Q2_K_XL", "UD-IQ3_XXS", "UD-Q3_K_XL", "UD-IQ4_XS-v31"])
self.assertFalse(models["UD-IQ4_XS"].get("experimental"))
self.assertFalse(models["UD-Q4_K_XL"].get("experimental"))
self.assertEqual(s.sizes_of(M.FALLBACK_MODELS, "qwen"), ["Q2_0", "IQ2_XS", "IQ3_XXS", "IQ3_S"])
fam = next(f for f in s.model_table({"ram_gb": 63.7, "gpus": []}) if f["family"] == "unsloth")
self.assertFalse(fam["experimental"])
self.assertTrue(fam["images"])
by = {x["model"]: x for x in fam["sizes"]}
self.assertEqual((by["UD-IQ4_XS"]["experimental"], by["UD-IQ4_XS"]["images"]), (False, True))
self.assertEqual((by["UD-Q4_K_XL"]["experimental"], by["UD-Q4_K_XL"]["images"]), (False, True)) # #967
self.assertFalse(by["UD-IQ4_XS"]["on_this_pc"].startswith("experimental"))
self.assertIn("read from the SSD", by["UD-Q4_K_XL"]["on_this_pc"]) # 64 GB: the RAM budget
fam = next(f for f in s.model_table({"ram_gb": 127.8, "gpus": []}) if f["family"] == "unsloth")
by = {x["model"]: x for x in fam["sizes"]}
self.assertEqual(by["UD-Q4_K_XL"]["on_this_pc"], "fits (all of its experts in RAM)")
self.assertIn("read from the SSD", by["Q8_0"]["on_this_pc"])
def test_qwen36_is_listed_with_its_three_sizes(self):
"""QA 2026-10-18: the Qwen3.6-35B-A3B page of the first-run setup showed no versions, because setup.py keeps the family
in OWN_PATH_FAMILIES (not FAMILIES) and the model list only walked FAMILIES."""
s = M.Strata(HERE.parent)
self.assertIn("qwen36", s.tables()[1])
fam = next(f for f in s.model_table({"ram_gb": 63.7, "gpus": [{"index": 0, "name": "x", "vram_gb": 12.0, "usable": True}]})
if f["family"] == "qwen36")
by = {x["model"]: x for x in fam["sizes"]}
self.assertEqual(list(by), ["UD-Q4_K_XL", "UD-Q6_K_XL", "Q8_0"])
self.assertEqual(by["UD-Q4_K_XL"]["id"], "qwen36-ud-q4_k_xl") # the tag the install writes its config under
self.assertEqual(by["UD-Q4_K_XL"]["download_gb"], 22.9)
self.assertTrue(all(x["images"] and x["engine_min"] == "0.1.45" and x["gpu_options"] is None for x in by.values()))
self.assertEqual({x["on_this_pc"] for x in by.values()}, {"fits"})
small = next(f for f in s.model_table({"ram_gb": 16, "gpus": []}) if f["family"] == "qwen36")
self.assertEqual({x["on_this_pc"] for x in small["sizes"]}, {"does not fit"})
self.assertEqual(s.sizes_of(s.tables()[0], "unsloth")[:5], ["UD-IQ4_XS", "UD-Q4_K_XL", "UD-Q5_K_XL", "UD-Q6_K_XL", "Q8_0"]) # the Unsloth Flash-Next sizes are untouched (round 0214 adds sizes after them)
def test_qwen36_install_plan(self):
s = M.Strata(HERE.parent)
s.hardware = lambda fresh=False: {"ram_gb": 64.0, "gpus": [{"index": 0, "name": "x", "vram_gb": 12.0, "usable": True, "vendor": "nvidia"}],
"cpu": {"avx2": True}}
s.disk_free = lambda p: 1000.0
plan, args = M.Tools(s).install_plan("qwen36", "UD-Q4_K_XL", 32768, "yes", "int8", None, None, None, "auto", None, None)
self.assertEqual((plan["title"], plan["download_gb"], plan["family"]), ("Qwen3.6-35B-A3B UD-Q4_K_XL", 22.9, "qwen36"))
self.assertEqual(args[:10], ["--yes", "--no-start", "--family", "qwen36", "--model", "UD-Q4_K_XL", "--context", "32768",
"--vision", "yes"])
for flag in ("--kv", "--low-ram", "--experimental-speed-projection"): # Flash-Next settings: setup would only warn
self.assertNotIn(flag, args)
plan, _a = M.Tools(s).install_plan("qwen36", None, 32768, "no", None, None, None, None, None, None, None)
self.assertEqual(plan["model"], "UD-Q4_K_XL")
with self.assertRaises(M.ToolError):
M.Tools(s).install_plan("qwen36", "IQ3_S", 32768, "no", None, None, None, None, None, None, None)
def test_recommendation_follows_ram(self):
s = M.Strata(HERE.parent)
gpu = [{"index": 0, "name": "x", "vram_gb": 24.0, "usable": True, "vendor": "nvidia"}]
cases = {96: ("qwen", "IQ3_S", 131072), 48: ("qwen", "IQ3_S", 131072), 32: ("qwen", "IQ3_XXS", 131072), 12: ("coder", "IQ1_M", 131072)} # the owner's tiers count RAM + VRAM (24 GB card): 120, 72, 56 GB; the Coder where the older rules stand
for ram, want in cases.items():
r = s.recommend({"ram_gb": ram, "gpus": gpu, "cpu": {"avx2": True}})
self.assertEqual((r["family"], r["model"], r["context"]), want, ram)
r = s.recommend({"ram_gb": 16, "gpus": [{**gpu[0], "vram_gb": 8.0}], "cpu": {"avx2": True}})
self.assertIsNone(r["model"])
r = s.recommend({"ram_gb": 64, "gpus": [], "cpu": {"avx2": True}})
self.assertIsNone(r["model"])
r = s.recommend({"ram_gb": 64, "gpus": [{**gpu[0], "vram_gb": 12.0}], "cpu": {"avx2": True}})
self.assertEqual(r["context"], 131072) # 128K on every card, a 12 GB one too (owner, 2026-11-01)
def test_a_pick_that_reads_from_the_ssd_says_so(self):
# #3425: 36 GB RAM + 16 GB VRAM - 5 GB is the 48 GB tier; about 8 GB of IQ3_XXS would come from the SSD
s = M.Strata(HERE.parent)
gpu = [{"index": 0, "name": "x", "vram_gb": 15.9, "usable": True, "vendor": "nvidia"}]
r = s.recommend({"ram_gb": 36.0, "gpus": gpu, "cpu": {"avx2": True}})
self.assertEqual((r["family"], r["model"]), ("qwen", "IQ3_XXS"))
self.assertTrue(any("read from the SSD" in n for n in r["notes"]), r["notes"])
roomy = s.recommend({"ram_gb": 64, "gpus": gpu, "cpu": {"avx2": True}})
self.assertFalse(any("read from the SSD" in n for n in roomy["notes"]), roomy["notes"])
def test_3425_the_tiers_leave_5_gb_for_windows(self):
# the reporter: RTX 5080 (16 GB) + 32 GB of RAM used to sum to 48 GB and get IQ3_XXS; now the 40 GB tier
s = M.Strata(HERE.parent)
gpu = [{"index": 0, "name": "x", "vram_gb": 15.9, "usable": True, "vendor": "nvidia"}]
self.assertEqual(M.TIER_SYSTEM_RESERVE_GB, 5.0)
r = s.recommend({"ram_gb": 31.9, "gpus": gpu, "cpu": {"avx2": True}})
self.assertEqual((r["family"], r["model"]), ("swift", "IQ2_XS"))
# boundary: 43 GB of RAM + VRAM is the lowest 40 GB tier PC, 51 GB the lowest 48 GB tier PC
def pick(ram, vram):
g = [{**gpu[0], "vram_gb": vram}]
r = s.recommend({"ram_gb": ram, "gpus": g, "cpu": {"avx2": True}})
return r["family"], r["model"]
self.assertEqual(pick(30.0, 13.0), ("swift", "IQ2_XS"))
self.assertNotEqual(pick(30.0, 12.9), ("swift", "IQ2_XS"))
self.assertEqual(pick(38.0, 13.0), ("qwen", "IQ3_XXS"))
self.assertEqual(pick(38.0, 12.9), ("swift", "IQ2_XS"))
self.assertEqual(pick(54.0, 13.0), ("qwen", "IQ3_S"))
self.assertEqual(pick(54.0, 12.9), ("qwen", "IQ3_XXS"))
class PhysicalCores(unittest.TestCase):
"""#3417: the hardware report's cpu.cores is the physical cores; the Work profile takes 80% of it for --pool-workers."""
def test_physical_not_logical(self):
from strata_control import tune_machine
with mock.patch.object(tune_machine, "cpu", return_value={"model": "x", "logical": 16, "physical": 8, "hybrid": False}), mock.patch.object(M.os, "cpu_count", return_value=16):
self.assertEqual(M.physical_cores(), 8)
def test_unknown_falls_back_to_threads(self):
from strata_control import tune_machine
with mock.patch.object(tune_machine, "cpu", return_value={"physical": None}), mock.patch.object(M.os, "cpu_count", return_value=16):
self.assertEqual(M.physical_cores(), 16)
with mock.patch.object(tune_machine, "cpu", side_effect=OSError("no")), mock.patch.object(M.os, "cpu_count", return_value=4):
self.assertEqual(M.physical_cores(), 4)
class MacCatalog(unittest.TestCase):
"""A Mac (Apple Silicon): one pool of unified memory, judged by strata_control/mac_fit.py (the rules metal/setup_mac.py uses)."""
def hw(self, ram, macos="27.2", chip="Apple M4"):
from strata_control import mac_fit
s = M.Strata(HERE.parent)
info = {"chip": chip, "ram_gb": float(ram), "macos": macos, "arm64": True, "clt": "", "perf_cores": 4}
with mock.patch.object(M.sys, "platform", "darwin"), mock.patch.object(mac_fit, "mac_info", return_value=info):
hw = s._hardware()
return s, hw
def engine(self, marker: bool):
"""A stand-in strata-dsv41 program: with or without the Metal picture-tower marker (the engine is only read, never started)."""
d = Path(tempfile.mkdtemp())
self.addCleanup(shutil.rmtree, d, True)
f = d / "strata-dsv41"
f.write_bytes(b"\0" * 64 + (b"STRATA_DS4_METAL_VISION_V1" if marker else b"") + b"\0" * 64)
return f
def test_the_hardware_is_one_apple_gpu_with_unified_memory(self):
s, hw = self.hw(32)
self.assertEqual(hw["ram_gb"], 32.0)
self.assertEqual(len(hw["gpus"]), 1)
g = hw["gpus"][0]
self.assertEqual((g["vendor"], g["name"], g["usable"], g["vram_gb"], g["unified_gb"]), ("apple", "Apple M4", True, 0.0, 32.0))
self.assertEqual(hw["mac"]["unified_gb"], 32.0)
self.assertFalse(hw["nvidia_smi"])
def test_recommendation_by_unified_memory(self):
cases = {32: ("Q2_0", 32768), 48: ("Q2_0", 32768), 80: ("IQ3_XXS", 32768), 128: ("IQ3_S", 65536)}
for ram, (model, ctx) in cases.items():
s, hw = self.hw(ram)
r = s.recommend(hw)
self.assertEqual((r["family"], r["model"], r["context"], r["backend"]), ("qwen", model, ctx, "metal"), ram)
self.assertNotIn("NVIDIA", r["why"])
self.assertFalse([n for n in r["notes"] if "UD-" in n], "the Unsloth sizes are not offered in the app yet")
s, hw = self.hw(32)
self.assertIn("read from the SSD", s.recommend(hw)["why"])
s, hw = self.hw(128)
self.assertIn("stays in memory", s.recommend(hw)["why"])
def test_a_mac_too_small_or_too_old_has_no_recommendation_and_says_why(self):
s, hw = self.hw(8)
r = s.recommend(hw)
self.assertIsNone(r["model"])
self.assertIn("8 GB of unified memory", r["why"])
s, hw = self.hw(32, macos="14.6")
r = s.recommend(hw)
self.assertIsNone(r["model"])
self.assertIn("macOS 15 or newer", r["why"])
def test_the_model_list_is_the_macs_sizes_with_unified_memory_verdicts(self):
s, hw = self.hw(32)
fams = s.model_table(hw)
self.assertEqual([f["family"] for f in fams], ["qwen", "unsloth", "gyro", "deepseek41"],
"Unsloth's sets since round 0214 (the app repacks them), no Swift or NVFP4 on a Mac; Gyro after the regular sizes, DeepSeek (0.2.7.1) last")
by = {x["model"]: x for x in fams[0]["sizes"]}
self.assertEqual(list(by), ["Q2_0", "IQ3_XXS", "IQ3_S"])
un = {x["model"]: x for x in fams[1]["sizes"]}
self.assertEqual(list(un), ["UD-IQ1_M", "UD-Q2_0", "UD-IQ2_XS", "UD-Q2_K_XL", "UD-IQ3_XXS", "UD-Q3_K_XL", "UD-IQ4_XS-v31", "UD-Q4_K_XL", "UD-Q5_K_XL", "UD-Q6_K_XL"])
self.assertEqual((un["UD-IQ1_M"]["download_gb"], un["UD-IQ1_M"]["experts_gb"]), (68.0, 34.8))
self.assertTrue(all(x["on_this_pc"] and x["images"] and x["id"] == "unsloth-" + x["model"].lower() for x in un.values()))
self.assertTrue(un["UD-Q5_K_XL"]["on_this_pc"].startswith("slow here"), "32 GB: 104 GB to map does not fit, said not refused")
gy = {x["model"]: x for x in fams[2]["sizes"]}
self.assertEqual(list(gy), ["Gyro-S", "Gyro-M"])
self.assertEqual(gy["Gyro-S"]["download_gb"], 58.5)
self.assertTrue(all(v["on_this_pc"] and "SSD" in v["on_this_pc"] for v in gy.values()), "32 GB: both stream (said, not refused)")
self.assertIn("read from the SSD", by["Q2_0"]["on_this_pc"])
self.assertIn("slower", by["Q2_0"]["on_this_pc"])
self.assertIn("~14 tok/s", by["Q2_0"]["on_this_pc"])
self.assertTrue(by["IQ3_S"]["on_this_pc"].startswith("slow here"))
self.assertTrue(all(x["images"] for x in by.values()), "the Mac engine carries the Metal picture reader: pictures are on")
s, hw = self.hw(128)
fits = {x["model"]: x["on_this_pc"] for f in s.model_table(hw) if f["family"] != "deepseek41" for x in f["sizes"]}
from strata_control import mac_fit
for m, v in fits.items(): # the 128 GB Mac keeps ~96 GB resident: UD-Q5_K_XL and UD-Q6_K_XL (104 / 115 GB to map) stream, said not refused
self.assertEqual(v == "fits", not mac_fit.streams(m, 128.0), m)
self.assertEqual({m for m, v in fits.items() if v != "fits"}, {"UD-Q5_K_XL", "UD-Q6_K_XL"})
s, hw = self.hw(8)
self.assertEqual({x["on_this_pc"] for f in s.model_table(hw) if f["family"] != "deepseek41" for x in f["sizes"]}, {"does not fit"})
self.assertTrue(all(x["on_this_pc"].startswith("does not fit") for f in s.model_table(hw) if f["family"] == "deepseek41" for x in f["sizes"]))
def test_deepseek_pictures_on_a_mac_follow_the_installed_engine(self):
"""DeepSeek reads pictures on a Mac exactly when the installed strata-dsv41 carries STRATA_DS4_METAL_VISION_V1; no engine installed yet: on (setup looks again once it is fetched)."""
s, hw = self.hw(128)
pics = lambda: {x["model"]: (x["images"], x["images_reader"]) for f in s.model_table(hw) if f["family"] == "deepseek41" for x in f["sizes"]}
s.dsv41_engine_exe = lambda: self.engine(True)
self.assertEqual(set(pics().values()), {(True, "gpu")})
s.dsv41_engine_exe = lambda: self.engine(False)
self.assertEqual(set(pics().values()), {(False, "none")})
s.dsv41_engine_exe = lambda: None
self.assertEqual(set(pics().values()), {(True, "gpu")})
from strata_control import dsv41_engine
self.assertEqual([dsv41_engine.mac_vision_state(self.engine(True)), dsv41_engine.mac_vision_state(self.engine(False)), dsv41_engine.mac_vision_state(None)], ["yes", "no", "unknown"])
def test_the_mac_install_tool_accepts_pictures_with_the_marker_and_says_why_not_without_it(self):
s, hw = self.hw(128)
s.hardware = lambda fresh=False: hw
s.disk_free = lambda p: 1000.0
s.dsv41_engine_exe = lambda: self.engine(True)
_plan, args = M.Tools(s).install_plan("deepseek41", "IST-DAS-2.25bpw", None, "yes", None, None, None, None, None, None, None, None)
self.assertEqual(args[args.index("--vision") + 1], "yes")
s.dsv41_engine_exe = lambda: self.engine(False)
with self.assertRaises(M.ToolError) as cm:
M.Tools(s).install_plan("deepseek41", "IST-DAS-2.25bpw", None, "yes", None, None, None, None, None, None, None, None)
self.assertIn("reads text only with this engine (its picture reader needs an engine update)", str(cm.exception))
_plan, args = M.Tools(s).install_plan("deepseek41", "IST-DAS-2.25bpw", None, None, None, None, None, None, None, None, None, None)
self.assertEqual(args[args.index("--vision") + 1], "no")
def test_a_pc_does_not_look_at_the_mac_marker(self):
s = M.Strata(HERE.parent)
s.dsv41_engine_exe = lambda: self.engine(False)
hw = {"ram_gb": 128, "gpus": [{"index": 0, "name": "x", "vram_gb": 24.0, "usable": True, "vendor": "nvidia"}], "cpu": {"cores": 16}}
rows = [x for f in s.model_table(hw) if f["family"] == "deepseek41" for x in f["sizes"]]
self.assertTrue(rows and all(x["images"] for x in rows))
def test_deepseek_on_a_mac_offers_the_sets_with_the_mac_words(self):
s, hw = self.hw(128)
s.dsv41_engine_exe = lambda: self.engine(False)
ds = next(f for f in s.model_table(hw) if f["family"] == "deepseek41")
by = {x["model"]: x for x in ds["sizes"]}
self.assertEqual(list(by), ["IST-DAS-2.00bpw", "IST-DAS-2.25bpw", "ISTA-DAS-Coder", "UD-IQ1_S", "UD-IQ1_M"], "the 1.75 bpw set was never run on a Mac; the Coder, UD-IQ1_S and UD-IQ1_M are offered with a plain note")
for x in by.values():
self.assertTrue(x["multi_file"] and not x["images"])
self.assertGreater(x["disk_gb"], x["download_gb"])
if x["model"] == "ISTA-DAS-Coder": # 66 GB of experts: all of them stay in a 128 GB Mac's memory
self.assertTrue(x["on_this_pc"].startswith("fits: every expert stays"), x["on_this_pc"])
continue
self.assertTrue(x["on_this_pc"].startswith("runs on this Mac's memory"), x["on_this_pc"])
self.assertIn("read from the SSD", x["on_this_pc"])
s, hw = self.hw(32)
ds = next(f for f in s.model_table(hw) if f["family"] == "deepseek41")
for x in ds["sizes"]: # a small Mac: said plainly, never refused
self.assertTrue(x["on_this_pc"].startswith("slow here"), x["on_this_pc"])
self.assertIn("can still be installed", x["on_this_pc"])
from strata_cli.launch import catalog as C
self.assertEqual(C.verdict(by["IST-DAS-2.00bpw"]["on_this_pc"])[0], C.FITS)
self.assertEqual(C.verdict(ds["sizes"][0]["on_this_pc"])[0], C.TIGHT)
def test_the_install_plan_on_a_mac_has_no_card_kv_or_ram_options(self):
s, hw = self.hw(32)
s.hardware = lambda fresh=False: hw
s.disk_free = lambda p: 1000.0
with tempfile.TemporaryDirectory() as own:
plan, args = M.Tools(s).install_plan("qwen", "Q2_0", None, "no", "int8", 0, None, None, "auto", None, None, own)
self.assertEqual(plan["context"], 32768)
self.assertEqual(args[:9], ["--yes", "--no-start", "--family", "qwen", "--model", "Q2_0", "--context", "32768", "--vision"])
for flag in ("--kv", "--gpu", "--gpus", "--low-ram", "--backend"):
self.assertNotIn(flag, args)
self.assertIn("--gguf-dir", args)
with tempfile.TemporaryDirectory() as own: # nothing said about pictures: on, as everywhere (the Mac's reader is the Metal one)
_plan, args = M.Tools(s).install_plan("qwen", "Q2_0", None, None, "int8", 0, None, None, "auto", None, None, own)
self.assertEqual(args[args.index("--vision") + 1], "yes")
with self.assertRaises(M.ToolError):
s2, hw2 = self.hw(8)
s2.hardware = lambda fresh=False: hw2
M.Tools(s2).install_plan(None, None, None, None, None, None, None, None, None, None, None)
def test_the_install_plan_counts_the_repacked_file_of_an_unsloth_set(self):
"""Round 0214: the Mac app repacks Unsloth's shards into one GGUF: the disk it needs is the download, that file (mac_fit shard1_gb) and room to work."""
s, hw = self.hw(128)
s.hardware = lambda fresh=False: hw
s.disk_free = lambda p: 1000.0
with tempfile.TemporaryDirectory() as t:
target = Path(t) / "Strata-data"
target.mkdir()
plan, args = M.Tools(s).install_plan("unsloth", "UD-IQ1_M", None, "no", "int8", 0, None, None, "auto", None, str(target))
plain, _ = M.Tools(s).install_plan("qwen", "Q2_0", None, "no", "int8", 0, None, None, "auto", None, str(target))
self.assertEqual(plan["disk_needed_gb"], round(68.0 + 8 + 39.2))
self.assertEqual(plain["disk_needed_gb"], round(plain["download_gb"] + 8)) # no repack for a GSQ-RCO file
self.assertEqual(args[:6], ["--yes", "--no-start", "--family", "unsloth", "--model", "UD-IQ1_M"])
s.disk_free = lambda p: 100.0
with tempfile.TemporaryDirectory() as t:
target = Path(t) / "Strata-data"
target.mkdir()
short, _ = M.Tools(s).install_plan("unsloth", "UD-IQ1_M", None, "no", "int8", 0, None, None, "auto", None, str(target))
self.assertIn("not enough free disk space", short["disk_short"])
def test_the_install_plan_for_deepseek_on_a_mac_is_text_only_at_8k(self):
"""(with an engine that has no Metal picture tower)"""
s, hw = self.hw(128)
s.dsv41_engine_exe = lambda: self.engine(False)
s.hardware = lambda fresh=False: hw
s.disk_free = lambda p: 1000.0
with tempfile.TemporaryDirectory() as own:
plan, args = M.Tools(s).install_plan("deepseek41", "IST-DAS-2.00bpw", None, None, None, None, None, None, None, None, None, None)
self.assertEqual(args[:9], ["--yes", "--no-start", "--family", "deepseek41", "--model", "IST-DAS-2.00bpw", "--context", "8192", "--vision"])
self.assertEqual(args[args.index("--vision") + 1], "no", "the installed engine has no Metal picture tower")
for flag in ("--kv", "--gpu", "--gpus", "--low-ram", "--backend"):
self.assertNotIn(flag, args)
self.assertTrue(plan["ram"].startswith("runs on this Mac's memory"))
with self.assertRaises(M.ToolError): # UD-Q8_K_XL (508 GB) and the 1.75 set were never run on a Mac
M.Tools(s).install_plan("deepseek41", "UD-Q8_K_XL", None, None, None, None, None, None, None, None, None, None)
with self.assertRaises(M.ToolError):
M.Tools(s).install_plan("deepseek41", "IST-DAS-2.25bpw", None, "yes", None, None, None, None, None, None, None, None)
def test_a_pc_is_unchanged(self):
s = M.Strata(HERE.parent)
r = s.recommend({"ram_gb": 96, "gpus": [{"index": 0, "name": "x", "vram_gb": 24.0, "usable": True, "vendor": "nvidia"}],
"cpu": {"avx2": True}})
self.assertEqual((r["family"], r["model"]), ("qwen", "IQ3_S"))
self.assertIn("unsloth", [f["family"] for f in s.model_table({"ram_gb": 96, "gpus": []})])
class MixedGraphics(unittest.TestCase):
def test_an_integrated_amd_gpu_beside_an_nvidia_card_is_not_offered(self):
s = M.Strata(HERE.parent)
S = s.setup_module()
nv = [{"index": 0, "name": "NVIDIA GeForce RTX 5090", "vram_gb": 31.8, "arch": "120", "driver": "580.95"}]
igpu = [{"index": 0, "name": "AMD Radeon Graphics", "vram_gb": 0.5, "arch": "gfx1036", "uma": True}]
with mock.patch.object(M.sys, "platform", "linux"), mock.patch.object(M, "WIN", False), mock.patch.object(S, "gpus", lambda: [dict(g) for g in nv]), mock.patch.object(S, "gpu_problem", lambda g: None), mock.patch.object(S, "amd_gpus", lambda: [dict(g) for g in igpu]), mock.patch.object(S, "amd_problem", lambda g: None):
hw = s._hardware()
by = {g["vendor"]: g for g in hw["gpus"]}
self.assertTrue(by["nvidia"]["usable"])
self.assertFalse(by["amd"]["usable"])
self.assertIn("NVIDIA card", by["amd"]["problem"])
# the RTX and the Ryzen iGPU both say index 0 (each make counts from 0), so the report gives each a stable id of its own
self.assertEqual((by["nvidia"]["index"], by["amd"]["index"]), (0, 0))
self.assertEqual(sorted(g["id"] for g in hw["gpus"]), ["amd:0", "nvidia:0"])
rec = s.recommend({**hw, "ram_gb": 92.0})
self.assertEqual((rec["backend"], rec["gpu"]["name"]), ("cuda", "NVIDIA GeForce RTX 5090"))
# with no NVIDIA card the integrated GPU stays what it was
with mock.patch.object(M.sys, "platform", "linux"), mock.patch.object(M, "WIN", False), mock.patch.object(S, "gpus", lambda: []), mock.patch.object(S, "amd_gpus", lambda: [dict(g) for g in igpu]), mock.patch.object(S, "amd_problem", lambda g: None):
self.assertTrue(s._hardware()["gpus"][0]["usable"])
def test_two_gtx_1080_are_a_working_pc_on_the_cuda_12_engine(self):
"""#3655: Pascal cards were flagged 'not supported' and both started Off, so the app said no card was usable. When Pascal is all the PC has
(and no AMD card), setup runs them with the CUDA 12 engine, and the hardware report now says so; a newer card keeps the old behaviour."""
s = M.Strata(HERE.parent)
S = s.setup_module()
pascal = [{"index": 0, "name": "NVIDIA GeForce GTX 1080", "vram_gb": 8.0, "arch": "61", "driver": "581.15"},
{"index": 1, "name": "NVIDIA GeForce GTX 1080", "vram_gb": 8.0, "arch": "61", "driver": "581.15"}]
igpu = [{"index": 0, "name": "AMD Radeon(TM) Graphics", "vram_gb": 0.5, "arch": "gfx90c", "uma": True}]
patches = (mock.patch.object(M.sys, "platform", "linux"), mock.patch.object(M, "WIN", False),
mock.patch.object(S, "amd_gpus", lambda: [dict(g) for g in igpu]), mock.patch.object(S, "amd_problem", lambda g: "integrated graphics"),
mock.patch.dict(M.os.environ, {"STRATA_EXPERIMENTAL_SM60": ""}), mock.patch.object(S, "OLD_GPUS", None))
with mock.patch.object(S, "gpus", lambda: [dict(g) for g in pascal]):
for p in patches:
p.start()
try:
hw = s._hardware()
finally:
for p in reversed(patches):
p.stop()
nv = [g for g in hw["gpus"] if g["vendor"] == "nvidia"]
self.assertEqual([(g["usable"], g["problem"], g.get("engine_variant")) for g in nv], [(True, None, "cuda12")] * 2)
# a newer card in the PC: Pascal stays an opt-in, the ready-made engine is recommended
mixed = [{"index": 0, "name": "NVIDIA GeForce GTX 1080", "vram_gb": 8.0, "arch": "61", "driver": "581.15"},
{"index": 1, "name": "NVIDIA GeForce RTX 3060", "vram_gb": 12.0, "arch": "86", "driver": "581.15"}]
with mock.patch.object(S, "gpus", lambda: [dict(g) for g in mixed]):
for p in patches:
p.start()
try:
hw = s._hardware()
finally:
for p in reversed(patches):
p.stop()
by = {g["name"]: g for g in hw["gpus"] if g["vendor"] == "nvidia"}
self.assertFalse(by["NVIDIA GeForce GTX 1080"]["usable"])
self.assertTrue(by["NVIDIA GeForce RTX 3060"]["usable"])
def test_an_amd_card_the_installed_engine_has_no_code_for_is_not_usable(self):
"""#3203: the engine package lists its GPU code; a card outside it is flagged unusable with the plain reason, so no list offers it."""
status = {"usable": True, "engine": {"backend": "hip", "archs": ["gfx1200", "gfx1201"]}}
hw = {"gpus": [{"vendor": "amd", "index": 0, "name": "AMD Radeon 760M", "arch": "gfx1103", "usable": False, "problem": "integrated"},
{"vendor": "amd", "index": 1, "name": "AMD Radeon RX 6800 XT", "arch": "gfx1030", "usable": True, "problem": None},
{"vendor": "amd", "index": 2, "name": "AMD Radeon RX 9070 XT", "arch": "gfx1201", "usable": True, "problem": None},
{"vendor": "nvidia", "index": 0, "name": "NVIDIA GeForce RTX 3060", "arch": "86", "usable": True, "problem": None}]}
with mock.patch("strata_control.engine_component.status", lambda: status):
M.Strata._engine_code(hw)
by = {g["name"]: g for g in hw["gpus"]}
self.assertFalse(by["AMD Radeon RX 6800 XT"]["usable"])
self.assertIn("no code for gfx1030", by["AMD Radeon RX 6800 XT"]["problem"])
self.assertEqual(by["AMD Radeon 760M"]["problem"], "integrated", "an earlier reason stays")
self.assertTrue(by["AMD Radeon RX 9070 XT"]["usable"])
self.assertTrue(by["NVIDIA GeForce RTX 3060"]["usable"])
# no engine package that lists archs (a source build, no engine yet): nothing is judged
for other in ({"usable": False}, {"usable": True, "engine": {"backend": "cuda", "archs": ["sm_86"]}}):
again = {"gpus": [{"vendor": "amd", "index": 1, "name": "x", "arch": "gfx1030", "usable": True, "problem": None}]}
with mock.patch("strata_control.engine_component.status", lambda other=other: other):
M.Strata._engine_code(again)
self.assertTrue(again["gpus"][0]["usable"])
@mock.patch("strata_control.engine_component.status", lambda: {"usable": False}) # not this PC's installed (CUDA) engine
def test_windows_lists_an_amd_card_and_not_the_integrated_radeon(self):
s = M.Strata(HERE.parent)
S = s.setup_module()
cards = [{"index": 0, "name": "AMD Radeon RX 9070 XT", "vram_gb": 15.9, "arch": "gfx1201", "driver": "32.0.1"},
{"index": 1, "name": "AMD Radeon(TM) Graphics", "vram_gb": 0.5, "arch": "unknown (PCI 164E)", "driver": "32.0.1"}]
with mock.patch.object(M, "WIN", True), mock.patch.object(S, "gpus", lambda: []), mock.patch.object(S, "amd_gpus", lambda: [dict(g) for g in cards]), mock.patch.object(M, "windows_video_controllers", lambda: [{"name": "AMD Radeon RX 9070 XT", "driver": "32"}]), mock.patch.object(S, "ram_gb", lambda: 64.0), mock.patch.object(S, "page_file_gb", lambda: 10.0):
hw = s._hardware()
by = {g["name"]: g for g in hw["gpus"]}
self.assertTrue(by["AMD Radeon RX 9070 XT"]["usable"])
self.assertFalse(by["AMD Radeon(TM) Graphics"]["usable"])
rec = s.recommend({**hw, "ram_gb": 64.0})
self.assertEqual((rec["backend"], rec["gpu"]["name"]), ("hip", "AMD Radeon RX 9070 XT"))
if __name__ == "__main__":
unittest.main()
class RemoveMissingFilesTest(unittest.TestCase):
"""Deleting a model whose plan lists files that are already gone (or inside a folder removed earlier) is a success, not 'Some files could not be removed'."""
def test_missing_paths_are_already_removed(self):
import importlib.util, tempfile, threading
from pathlib import Path
spec = importlib.util.spec_from_file_location("strata_mcp_rm", Path(__file__).with_name("strata_mcp.py"))
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
with tempfile.TemporaryDirectory() as d:
root = Path(d)
folder = root / "Gyro-M"
folder.mkdir()
(folder / "a.gguf").write_bytes(b"x")
(folder / "b.gguf").write_bytes(b"y")
gone = root / "already-gone.gguf"
cfg = root / "model.json"
cfg.write_text("{}")
plan = {"model": "gyro-m", "gb": 0.1, "remove": [
{"path": str(folder)}, {"path": str(folder / "a.gguf")}, {"path": str(gone)}, {"path": str(cfg)}]}
class S:
lock = threading.RLock()
def find_config(self, model): return cfg
def removal_plan(self, config): return plan
def install_job(self): return None
def tracked_server(self): return None
def model_paths(self, c): return ([], [])
def read_config(self, c): return {}
result = mod.Tools(S()).strata_remove(model="gyro-m", confirm=True)
self.assertEqual(result["failed"], [], result)
self.assertFalse(folder.exists()); self.assertFalse(cfg.exists())
again = mod.Tools(S()).strata_remove(model="gyro-m", confirm=True)
self.assertEqual(again["failed"], [], "a second delete of the same model finds nothing left and still succeeds")
class DiskUsageTest(unittest.TestCase):
"""QA 2026-10-18 (F02): Storage showed IQ3_S as 0.0 GB while it uses 84 GB, and Gyro-S as 119 GB while it is 59 GB. The sizes come from the real
files: every part of a model in parts, the picture reader, the packs; a file one config names through several flags counts once; a
file two models share counts once in the total; a model's own figure leaves out another model's files."""
def setUp(self):
self.tmp = tempfile.TemporaryDirectory()
self.addCleanup(self.tmp.cleanup)
d = Path(self.tmp.name)
self.root, self.data, self.own = d / "install", d / "data", d / "owner-folder"
for p in (self.root, self.data / "models" / "gyro-Gyro-S", self.data / "packs" / "swift-iq2_xs", self.data / "mtp" / "rt", self.own):
p.mkdir(parents=True)
(d / "settings.json").write_text(json.dumps({"data_dir": str(self.data)}), encoding="utf-8")
env = mock.patch.dict(os.environ, {"STRATA_SETTINGS_FILE": str(d / "settings.json")})
env.start()
self.addCleanup(env.stop)
def blob(self, path: Path, size: int) -> str:
path.write_bytes(b"x" * size)
return str(path)
def write_config(self, name: str, args: list, vision=None):
cfg = {"exe": sys.executable, "args": args, "port": 8080}
if vision:
cfg["vision"] = {"mmproj": vision}
(self.root / f"strata-{name}.json").write_text(json.dumps(cfg), encoding="utf-8")
def test_sizes_come_from_the_files_not_from_what_may_be_deleted(self):
gyro = self.blob(self.data / "models" / "gyro-Gyro-S" / "Gyro-S.gguf", 59_000)
reader = self.blob(self.data / "models" / "mmproj.gguf", 900)
part1 = self.blob(self.own / "Model-IQ3_S-00001-of-00002.gguf", 30_000)
self.blob(self.own / "Model-IQ3_S-00002-of-00002.gguf", 54_000)
# Gyro: the one file is --native, --ple-gguf, --embd-gguf and --native-dense-gguf at once
self.write_config("gyro-gyro-s", ["--native", gyro, "--ple-gguf", gyro, "--embd-gguf", gyro, "--native-dense-gguf", gyro], reader)
# IQ3_S: adopted from the person's own folder, the config names the first part only
self.write_config("iq3_s", ["--native", part1], reader)
s = M.Strata(self.root)
use = s.disk_usage()
self.assertEqual(use["models"]["gyro-gyro-s"]["bytes"], 59_000, "the Gyro file is counted once, not four times")
self.assertEqual(use["models"]["iq3_s"]["bytes"], 84_000, "both parts of IQ3_S, although the config names the first")
self.assertEqual(use["shared_bytes"], 900, "the picture reader both use is one file")
self.assertEqual(use["total_bytes"], 59_000 + 84_000 + 900, "rows plus the shared files add up to the total")
self.assertEqual(use["models"]["iq3_s"]["shared_bytes"], 900)
# deleting IQ3_S would remove nothing: its files are the person's own
by = {d["model"]: d for d in (s.describe_config(c, use) for c in s.configs())}
self.assertEqual(by["iq3_s"]["disk_bytes"], 84_000)
self.assertEqual(by["iq3_s"]["removable_gb"], 0.0)
self.assertEqual(by["gyro-gyro-s"]["disk_bytes"], 59_000)
def test_a_pack_folder_and_the_shared_draft_layer_count_once(self):
gguf = self.blob(self.data / "models" / "gyro-Gyro-S" / "m.gguf", 10_000)
pack = self.data / "packs" / "swift-iq2_xs"
self.blob(pack / "experts.bin", 40_000)
self.blob(pack / "index.txt", 100)
mtp = self.data / "mtp" / "rt"
self.blob(mtp / "experts.bin", 5_000)
self.write_config("swift-iq2_xs", ["--native", gguf, "--pack", str(pack), "--mtp", str(mtp)])
link_target = self.data / "models" / "gyro-Gyro-S" / "m2.gguf"
try:
os.link(gguf, link_target) # a hard link: the same bytes under another name
except OSError:
self.skipTest("no hard links here")
self.write_config("other", ["--native", str(link_target), "--mtp", str(mtp)])
use = M.Strata(self.root).disk_usage()
self.assertEqual(use["models"]["swift-iq2_xs"]["bytes"], 40_100)
self.assertEqual(use["models"]["other"]["bytes"], 0)
self.assertEqual(use["shared_bytes"], 10_000 + 5_000, "the hard-linked GGUF and the draft layer are shared")
self.assertEqual(use["total_bytes"], 55_100)
def test_a_model_with_a_part_missing_is_not_ready(self):
part1 = self.blob(self.own / "Model-00001-of-00003.gguf", 10)
self.blob(self.own / "Model-00002-of-00003.gguf", 10)
self.write_config("three-parts", ["--native", part1])
s = M.Strata(self.root)
desc = s.describe_config(s.configs()[0])
self.assertFalse(desc["ready"], "one part of three is on disk: not downloaded")
self.assertTrue(any(m.endswith("Model-00003-of-00003.gguf") for m in desc["missing_files"]), desc["missing_files"])
self.blob(self.own / "Model-00003-of-00003.gguf", 10)
desc = s.describe_config(s.configs()[0])
self.assertEqual([m for m in desc["missing_files"] if m.endswith(".gguf")], [])
class DraftLayerAndCancel(unittest.TestCase):
"""#3257: the draft layer's download shows real progress, and a cancel ends the whole tree."""
def test_step_6_shows_the_draft_layer_download_added_to_the_finished_model_files(self):
lines = ["=== Step 6: preparing the model for Strata ===", " > python mtp_fetch.py fetch",
" MTP draft layer: 2.00 / 5.00 GB (40%)"]
with tempfile.TemporaryDirectory() as d:
shard = Path(d) / "m-00001-of-00001.gguf"
shard.write_bytes(b"x" * 20_000_000)
job = {"files": [{"path": str(shard), "bytes": None, "role": "model"}], "total_gb": 60}
prog = M.combined_progress(M.install_progress(lines), job)
self.assertEqual(prog["download"]["file"], "Draft layer")
self.assertEqual([p["kind"] for p in prog["parts"]], ["model", "draft"])
self.assertEqual(prog["parts"][0]["state"], "done")
self.assertAlmostEqual(prog["parts"][1]["done_gb"], 2.0)
self.assertAlmostEqual(prog["parts"][1]["total_gb"], 5.0)
self.assertGreater(prog["download"]["total_gb"], 5.0)
self.assertEqual(prog["download"]["percent"], min(99, int(100 * prog["download"]["done_gb"] / prog["download"]["total_gb"])))
def test_without_a_file_list_the_draft_layer_alone_is_shown(self):
prog = M.combined_progress(M.install_progress(["=== Step 6: x ===", " MTP draft layer: 5.00 / 5.00 GB (100%)"]), {})
self.assertEqual([(p["kind"], p["state"]) for p in prog["parts"]], [("draft", "done")])
def test_other_step_6_output_still_shows_no_download(self):
prog = M.combined_progress(M.install_progress(["=== Step 6: x ===", " IQ2_XS: 0.00 / 0.00 GB (0%)"]), {})
self.assertNotIn("download", prog)
@unittest.skipUnless(M.WIN, "Windows process trees")
def test_cancel_ends_a_grandchild_even_when_taskkill_does_not_reach_it(self):
"""setup.py -> tools/*.py: taskkill /T walks parent ids; a snapshot taken first still finds the grandchild."""
code = ("import subprocess,sys,time; c=subprocess.Popen([sys.executable,'-c','import time; time.sleep(120)']);"
"print(c.pid, flush=True); time.sleep(120)")
top = subprocess.Popen([sys.executable, "-c", code], stdout=subprocess.PIPE, text=True)
grand = int(top.stdout.readline())
try:
ident, gident = M.proc_identity(top.pid), M.proc_identity(grand)
self.assertTrue(ident and gident)
self.assertIn((grand, gident), M.proc_tree_snapshot(top.pid))
real_run = subprocess.run
def no_taskkill(cmd, *a, **kw): # the case of #3257: taskkill ends the parent only
if cmd and cmd[0] == "taskkill":
return real_run(["taskkill", "/PID", str(top.pid), "/F"], capture_output=True)
return real_run(cmd, *a, **kw)
with mock.patch.object(M.subprocess, "run", no_taskkill):
M.proc_kill_tree(top.pid, ident)
M.wait_gone(grand, gident, 10)
self.assertFalse(M.proc_alive(grand, gident), "the grandchild kept running")
self.assertFalse(M.proc_alive(top.pid, ident))
finally:
for pid in (grand, top.pid):
subprocess.run(["taskkill", "/PID", str(pid), "/T", "/F"], capture_output=True)
top.wait(10)