52fc3e1ecf
_recommend assumes sorted, deduped grids (core_grid[-1] = biggest, knee sweeps run low->high). The CLI parsed --nodes/--cores in raw order, so e.g. --cores 32,8,16 yielded nonsense. Sort+dedupe in cli.py and reject non-positive/non-integer values; also normalize defensively inside estimate() so the function is correct for any caller. Add estimate/cli tests.
77 lines
2.6 KiB
Python
77 lines
2.6 KiB
Python
"""CLI-level tests for grid parsing / normalization (issue #11)."""
|
|
|
|
import json
|
|
|
|
import pytest
|
|
|
|
from nix_estimator import cli
|
|
|
|
|
|
def _p(name):
|
|
return f"/nix/store/{'0' * 32}-{name}.drv"
|
|
|
|
|
|
@pytest.fixture
|
|
def stub_graph(monkeypatch, tmp_path):
|
|
"""Stub out the nix-invoking graph layer with a deterministic toy DAG."""
|
|
leaves = [_p(f"heavylib{i}") for i in range(4)]
|
|
root, sink = _p("root"), _p("sink")
|
|
closure = {d: {} for d in [root, *leaves, sink]}
|
|
preds = {root: [], sink: leaves, **{leaf: [root] for leaf in leaves}}
|
|
nodes = set(closure)
|
|
|
|
monkeypatch.setattr(cli.graph, "derivation_closure", lambda *a, **k: closure)
|
|
monkeypatch.setattr(cli.graph, "to_build_set", lambda *a, **k: nodes)
|
|
monkeypatch.setattr(cli.graph, "build_dag", lambda *a, **k: (preds, nodes))
|
|
|
|
hist = tmp_path / "history.json"
|
|
hist.write_text(json.dumps({"root": 1.0, "sink": 1.0,
|
|
**{f"heavylib{i}": 20.0 for i in range(4)}}))
|
|
return str(hist)
|
|
|
|
|
|
def _run_json(capsys, argv):
|
|
assert cli.main(argv) == 0
|
|
return json.loads(capsys.readouterr().out)
|
|
|
|
|
|
def test_unsorted_cores_match_sorted(stub_graph, capsys):
|
|
sorted_out = _run_json(
|
|
capsys, [".#x", "--history", stub_graph, "--cores", "8,16,32", "--json"]
|
|
)
|
|
unsorted_out = _run_json(
|
|
capsys, [".#x", "--history", stub_graph, "--cores", "32,8,16", "--json"]
|
|
)
|
|
assert unsorted_out["recommendation"] == sorted_out["recommendation"]
|
|
assert unsorted_out["grid"] == sorted_out["grid"]
|
|
|
|
|
|
def test_unsorted_nodes_match_sorted(stub_graph, capsys):
|
|
sorted_out = _run_json(
|
|
capsys, [".#x", "--history", stub_graph, "--nodes", "1,2,4,8", "--json"]
|
|
)
|
|
unsorted_out = _run_json(
|
|
capsys, [".#x", "--history", stub_graph, "--nodes", "8,2,1,4", "--json"]
|
|
)
|
|
assert unsorted_out["recommendation"] == sorted_out["recommendation"]
|
|
|
|
|
|
def test_non_positive_cores_rejected(stub_graph, capsys):
|
|
with pytest.raises(SystemExit) as exc:
|
|
cli.main([".#x", "--history", stub_graph, "--cores", "8,0,16", "--json"])
|
|
assert exc.value.code != 0
|
|
assert "positive" in capsys.readouterr().err
|
|
|
|
|
|
def test_negative_nodes_rejected(stub_graph, capsys):
|
|
with pytest.raises(SystemExit) as exc:
|
|
cli.main([".#x", "--history", stub_graph, "--nodes", "1,-2,4", "--json"])
|
|
assert exc.value.code != 0
|
|
|
|
|
|
def test_non_integer_cores_rejected(stub_graph, capsys):
|
|
with pytest.raises(SystemExit) as exc:
|
|
cli.main([".#x", "--history", stub_graph, "--cores", "8,abc", "--json"])
|
|
assert exc.value.code != 0
|
|
assert "integer" in capsys.readouterr().err
|