Files
nix-estimator/tests/test_graph.py
T
Oleks ffc4494486 graph: prefer nix build --dry-run --json, fall back to text scraper (#8)
Probe --json support via nix build --help and parse structured output
when available (robust across Nix versions and locales). Falls back to
the #5 text scraper on older Nix or unexpected payloads, feeding the
same tri-state contract.
2026-07-08 16:25:29 +03:00

96 lines
2.7 KiB
Python

"""Tests for dry-run parsing and DAG restriction in :mod:`nix_estimator.graph`."""
from nix_estimator import graph
# --- captured `nix build --dry-run` text (issue #5) ------------------------
WARM = """\
this path will be fetched (0.02 MiB download, 0.10 MiB unpacked):
/nix/store/aaa-hello-2.12.1
"""
PARTIAL = """\
these 2 derivations will be built:
/nix/store/bbb-foo-1.0.drv
/nix/store/ccc-bar-2.0.drv
these 3 paths will be fetched (1.0 MiB download):
/nix/store/ddd-baz-3.0
"""
GARBAGE = """\
error: some totally unrelated failure with no dry-run structure
traceback blah blah
"""
def test_warm_cache_only_fetched_is_empty_set():
# dry-run succeeded, nothing to build: distinct from a parse failure
result = graph.parse_dry_run_text(WARM, returncode=0)
assert result == set()
def test_partial_returns_only_built_drvs():
result = graph.parse_dry_run_text(PARTIAL, returncode=0)
assert result == {"bbb-foo-1.0.drv", "ccc-bar-2.0.drv"}
def test_garbage_without_header_and_failure_is_none():
assert graph.parse_dry_run_text(GARBAGE, returncode=1) is None
def test_clean_exit_without_header_is_empty_not_none():
# exit 0 but no recognizable header still counts as "nothing to build"
assert graph.parse_dry_run_text("", returncode=0) == set()
# --- structured `nix build --dry-run --json` output (issue #8) -------------
JSON_PARTIAL = """\
[
{"drvPath": "/nix/store/bbb-foo-1.0.drv", "outputs": {"out": "/nix/store/e-foo"}},
{"drvPath": "/nix/store/ccc-bar-2.0.drv", "outputs": {"out": "/nix/store/f-bar"}}
]
"""
JSON_WARM = "[]"
JSON_ALT_KEY = '[{"drv": "/nix/store/ggg-qux-9.drv"}]'
def test_json_partial_returns_built_drvs():
assert graph.parse_dry_run_json(JSON_PARTIAL) == {
"bbb-foo-1.0.drv",
"ccc-bar-2.0.drv",
}
def test_json_warm_cache_is_empty_set():
assert graph.parse_dry_run_json(JSON_WARM) == set()
def test_json_alternate_drv_key():
assert graph.parse_dry_run_json(JSON_ALT_KEY) == {"ggg-qux-9.drv"}
def test_json_non_structured_is_none():
# human text or an unexpected shape must fall back (None), not crash
assert graph.parse_dry_run_json(WARM) is None
assert graph.parse_dry_run_json('{"not": "a list"}') is None
assert graph.parse_dry_run_json("not json at all") is None
def test_build_dag_empty_set_yields_no_nodes():
closure = {"a.drv": {"inputDrvs": {}}, "b.drv": {"inputDrvs": {"a.drv": {}}}}
preds, nodes = graph.build_dag(closure, set())
assert nodes == set()
assert preds == {}
def test_build_dag_none_costs_whole_closure():
closure = {
"a.drv": {"inputDrvs": {}},
"b.drv": {"inputDrvs": {"/nix/store/x-a.drv": {}}},
}
_, nodes = graph.build_dag(closure, None)
assert nodes == {"a.drv", "b.drv"}