Skip to content

Commit e246266

Browse files
committed
WIP
1 parent 74afd41 commit e246266

2 files changed

Lines changed: 86 additions & 2 deletions

File tree

graphbench/engines/issundb_engine.py

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,29 @@
2424
from ..schema import Schema
2525

2626

27+
def _verify_import_counts(payload: dict, expected: dict[str, tuple[str, int]]) -> None:
28+
"""Check IMPORT DATABASE's per-file report against the prepared row counts.
29+
30+
Since IssunDB 0.1.0a16 the import returns one `(target, kind, count)` row
31+
per COPY statement; a mismatch (for example an edge file misclassified as
32+
nodes) previously surfaced only as silently empty query results. Older
33+
versions return `{"imported": true}` and cannot be verified, so the check
34+
is skipped for them.
35+
"""
36+
if payload.get("columns") != ["target", "kind", "count"]:
37+
return
38+
imported = {
39+
rec["values"][0]: (rec["values"][1], rec["values"][2])
40+
for rec in payload["records"]
41+
}
42+
for target, want in expected.items():
43+
got = imported.get(target)
44+
if got != want:
45+
raise RuntimeError(
46+
f"IMPORT DATABASE ingested {got} for '{target}', expected {want}"
47+
)
48+
49+
2750
class IssunDBEngine(Engine):
2851
name = "issundb"
2952
kind = "embedded"
@@ -68,11 +91,13 @@ def build(self, data_dir: Path) -> BuildResult:
6891

6992
# 3. Process and write node Parquet files with _id column
7093
n_node_rows = 0
94+
expected_counts: dict[str, tuple[str, int]] = {}
7195
for label in self.schema.nodes:
7296
parquet_path = data_dir / "nodes" / f"{label.name}.parquet"
7397
dst_parquet = import_dir / f"{label.name}.parquet"
7498
df = pl.read_parquet(parquet_path)
7599
n_node_rows += df.height
100+
expected_counts[label.name] = ("nodes", df.height)
76101
df = df.with_columns(
77102
(
78103
pl.col(self.schema.id_column).cast(pl.Int64) + offsets[label.name]
@@ -89,6 +114,7 @@ def build(self, data_dir: Path) -> BuildResult:
89114
jsonl_path = import_dir / f"{rel.name}.jsonl"
90115
df = pl.read_parquet(parquet_path)
91116
n_edge_rows += df.height
117+
expected_counts[rel.name] = ("relationships", df.height)
92118
df = df.with_columns(
93119
[
94120
(
@@ -118,10 +144,11 @@ def build(self, data_dir: Path) -> BuildResult:
118144

119145
(import_dir / "copy.cypher").write_text("\n".join(copy_lines))
120146

121-
# 6. Execute IMPORT DATABASE
147+
# 6. Execute IMPORT DATABASE and verify the per-file report
122148
query_start = time.perf_counter()
123-
self._db.query(f"IMPORT DATABASE '{import_dir}'")
149+
payload = json.loads(self._db.query(f"IMPORT DATABASE '{import_dir}'"))
124150
query_time = time.perf_counter() - query_start
151+
_verify_import_counts(payload, expected_counts)
125152

126153
# Clean up import temp files
127154
shutil.rmtree(import_dir)

tests/test_issundb_import.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
"""Unit tests for the IssunDB import-report verification.
2+
3+
The check guards against the silent misclassification found in 0.1.0a15,
4+
where an edge file with legacy endpoint keys imported as nodes and the
5+
benchmark ran against an edgeless graph.
6+
"""
7+
8+
import pytest
9+
10+
from graphbench.engines.issundb_engine import _verify_import_counts
11+
12+
EXPECTED = {
13+
"Person": ("nodes", 3),
14+
"FOLLOWS": ("relationships", 2),
15+
}
16+
17+
18+
def payload(records):
19+
return {
20+
"columns": ["target", "kind", "count"],
21+
"records": [{"values": list(v)} for v in records],
22+
}
23+
24+
25+
def test_matching_report_passes():
26+
_verify_import_counts(
27+
payload([("Person", "nodes", 3), ("FOLLOWS", "relationships", 2)]),
28+
EXPECTED,
29+
)
30+
31+
32+
def test_misclassified_edge_file_raises():
33+
with pytest.raises(RuntimeError, match="FOLLOWS"):
34+
_verify_import_counts(
35+
payload([("Person", "nodes", 3), ("FOLLOWS", "nodes", 2)]),
36+
EXPECTED,
37+
)
38+
39+
40+
def test_short_count_raises():
41+
with pytest.raises(RuntimeError, match="FOLLOWS"):
42+
_verify_import_counts(
43+
payload([("Person", "nodes", 3), ("FOLLOWS", "relationships", 0)]),
44+
EXPECTED,
45+
)
46+
47+
48+
def test_missing_target_raises():
49+
with pytest.raises(RuntimeError, match="FOLLOWS"):
50+
_verify_import_counts(payload([("Person", "nodes", 3)]), EXPECTED)
51+
52+
53+
def test_legacy_result_shape_is_skipped():
54+
_verify_import_counts(
55+
{"columns": ["imported"], "records": [{"values": [True]}]},
56+
EXPECTED,
57+
)

0 commit comments

Comments
 (0)