Skip to content

Commit 0aab281

Browse files
committed
test(integration): verify get_labels, get_edge_types, traverse via live server
5 integration tests: LabelInfo list non-empty, EdgeTypeInfo list includes created type, TraverseResult returns outbound and inbound neighbours.
1 parent 4163364 commit 0aab281

1 file changed

Lines changed: 93 additions & 1 deletion

File tree

tests/integration/test_sdk.py

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
import pytest
1414

15-
from coordinode import AsyncCoordinodeClient, CoordinodeClient
15+
from coordinode import AsyncCoordinodeClient, CoordinodeClient, LabelInfo, EdgeTypeInfo, TraverseResult
1616

1717
ADDR = os.environ.get("COORDINODE_ADDR", "localhost:7080")
1818

@@ -208,6 +208,98 @@ def test_get_schema_text(client):
208208
client.cypher("MATCH (n:SchemaTestLabel {tag: $tag}) DETACH DELETE n", params={"tag": tag})
209209

210210

211+
# ── get_labels / get_edge_types / traverse ────────────────────────────────────
212+
213+
214+
def test_get_labels_returns_list(client):
215+
"""get_labels() returns a non-empty list of LabelInfo after data is present."""
216+
tag = uid()
217+
client.cypher("CREATE (n:GetLabelsTest {tag: $tag})", params={"tag": tag})
218+
try:
219+
labels = client.get_labels()
220+
assert isinstance(labels, list)
221+
assert len(labels) > 0
222+
assert all(isinstance(l, LabelInfo) for l in labels)
223+
names = [l.name for l in labels]
224+
assert "GetLabelsTest" in names, f"GetLabelsTest not in {names}"
225+
finally:
226+
client.cypher("MATCH (n:GetLabelsTest {tag: $tag}) DELETE n", params={"tag": tag})
227+
228+
229+
def test_get_labels_has_property_definitions(client):
230+
"""LabelInfo.properties is a list (may be empty for schema-free labels)."""
231+
client.cypher("MERGE (n:PropLabel {name: 'probe'})")
232+
try:
233+
labels = client.get_labels()
234+
found = next((l for l in labels if l.name == "PropLabel"), None)
235+
assert found is not None, "PropLabel not returned by get_labels()"
236+
assert isinstance(found.properties, list)
237+
finally:
238+
client.cypher("MATCH (n:PropLabel {name: 'probe'}) DELETE n")
239+
240+
241+
def test_get_edge_types_returns_list(client):
242+
"""get_edge_types() returns a non-empty list of EdgeTypeInfo after data is present."""
243+
tag = uid()
244+
client.cypher(
245+
"CREATE (a:EdgeTypeTestNode {tag: $tag})-[:GET_EDGE_TYPE_TEST]->(b:EdgeTypeTestNode {tag: $tag})",
246+
params={"tag": tag},
247+
)
248+
try:
249+
edge_types = client.get_edge_types()
250+
assert isinstance(edge_types, list)
251+
assert len(edge_types) > 0
252+
assert all(isinstance(et, EdgeTypeInfo) for et in edge_types)
253+
type_names = [et.name for et in edge_types]
254+
assert "GET_EDGE_TYPE_TEST" in type_names, f"GET_EDGE_TYPE_TEST not in {type_names}"
255+
finally:
256+
client.cypher("MATCH (n:EdgeTypeTestNode {tag: $tag}) DETACH DELETE n", params={"tag": tag})
257+
258+
259+
def test_traverse_returns_neighbours(client):
260+
"""traverse() returns adjacent nodes reachable via the given edge type."""
261+
tag = uid()
262+
client.cypher(
263+
"CREATE (a:TraverseRPC {tag: $tag, role: 'hub'})"
264+
"-[:TRAVERSE_TEST]->(b:TraverseRPC {tag: $tag, role: 'leaf1'})",
265+
params={"tag": tag},
266+
)
267+
rows = client.cypher(
268+
"MATCH (a:TraverseRPC {tag: $tag, role: 'hub'}) RETURN a AS node_id",
269+
params={"tag": tag},
270+
)
271+
try:
272+
assert len(rows) >= 1, "hub node not found"
273+
start_id = rows[0]["node_id"]
274+
result = client.traverse(start_id, "TRAVERSE_TEST", direction="outbound", max_depth=1)
275+
assert isinstance(result, TraverseResult)
276+
assert len(result.nodes) >= 1, "traverse() returned no neighbour nodes"
277+
finally:
278+
client.cypher("MATCH (n:TraverseRPC {tag: $tag}) DETACH DELETE n", params={"tag": tag})
279+
280+
281+
def test_traverse_inbound_direction(client):
282+
"""traverse() with direction='inbound' reaches nodes that point TO start_id."""
283+
tag = uid()
284+
client.cypher(
285+
"CREATE (src:TraverseIn {tag: $tag})-[:INBOUND_TEST]->(dst:TraverseIn {tag: $tag})",
286+
params={"tag": tag},
287+
)
288+
# Get dst node id — traverse INBOUND from dst should reach src.
289+
rows = client.cypher(
290+
"MATCH (src:TraverseIn {tag: $tag})-[:INBOUND_TEST]->(dst:TraverseIn {tag: $tag}) RETURN dst AS node_id",
291+
params={"tag": tag},
292+
)
293+
try:
294+
assert len(rows) >= 1
295+
dst_id = rows[0]["node_id"]
296+
result = client.traverse(dst_id, "INBOUND_TEST", direction="inbound", max_depth=1)
297+
assert isinstance(result, TraverseResult)
298+
assert len(result.nodes) >= 1, "inbound traverse returned no nodes"
299+
finally:
300+
client.cypher("MATCH (n:TraverseIn {tag: $tag}) DETACH DELETE n", params={"tag": tag})
301+
302+
211303
# ── Hybrid search ─────────────────────────────────────────────────────────────
212304

213305

0 commit comments

Comments
 (0)