yangdx
commited on
Commit
·
d60bf1c
1
Parent(s):
32943a3
Update graph unit test
Browse files- tests/test_graph_storage.py +289 -4
tests/test_graph_storage.py
CHANGED
@@ -209,6 +209,21 @@ async def test_graph_basic(storage):
|
|
209 |
else:
|
210 |
print(f"读取边属性失败: {node1_id} -> {node2_id}")
|
211 |
assert False, f"未能读取边属性: {node1_id} -> {node2_id}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
212 |
|
213 |
print("基本测试完成,数据已保留在数据库中")
|
214 |
return True
|
@@ -293,6 +308,15 @@ async def test_graph_advanced(storage):
|
|
293 |
node1_degree = await storage.node_degree(node1_id)
|
294 |
print(f"节点 {node1_id} 的度数: {node1_degree}")
|
295 |
assert node1_degree == 1, f"节点 {node1_id} 的度数应为1,实际为 {node1_degree}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
296 |
|
297 |
# 3. 测试 edge_degree - 获取边的度数
|
298 |
print(f"== 测试 edge_degree: {node1_id} -> {node2_id}")
|
@@ -300,7 +324,14 @@ async def test_graph_advanced(storage):
|
|
300 |
print(f"边 {node1_id} -> {node2_id} 的度数: {edge_degree}")
|
301 |
assert (
|
302 |
edge_degree == 3
|
303 |
-
), f"边 {node1_id} -> {node2_id} 的度数应为
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
304 |
|
305 |
# 4. 测试 get_node_edges - 获取节点的所有边
|
306 |
print(f"== 测试 get_node_edges: {node2_id}")
|
@@ -309,6 +340,23 @@ async def test_graph_advanced(storage):
|
|
309 |
assert (
|
310 |
len(node2_edges) == 2
|
311 |
), f"节点 {node2_id} 应有2条边,实际有 {len(node2_edges)}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
312 |
|
313 |
# 5. 测试 get_all_labels - 获取所有标签
|
314 |
print("== 测试 get_all_labels")
|
@@ -345,6 +393,13 @@ async def test_graph_advanced(storage):
|
|
345 |
edge_props = await storage.get_edge(node2_id, node3_id)
|
346 |
print(f"删除后查询边属性 {node2_id} -> {node3_id}: {edge_props}")
|
347 |
assert edge_props is None, f"边 {node2_id} -> {node3_id} 应已被删除"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
348 |
|
349 |
# 9. 测试 remove_nodes - 批量删除节点
|
350 |
print(f"== 测试 remove_nodes: [{node2_id}, {node3_id}]")
|
@@ -602,6 +657,21 @@ async def test_graph_batch_operations(storage):
|
|
602 |
edges_dict[(node3_id, node4_id)]["relationship"]
|
603 |
== edge5_data["relationship"]
|
604 |
), f"边 {node3_id} -> {node4_id} 关系不匹配"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
605 |
|
606 |
# 6. 测试 get_nodes_edges_batch - 批量获取多个节点的所有边
|
607 |
print("== 测试 get_nodes_edges_batch")
|
@@ -618,6 +688,41 @@ async def test_graph_batch_operations(storage):
|
|
618 |
assert (
|
619 |
len(nodes_edges[node3_id]) == 3
|
620 |
), f"{node3_id} 应有3条边,实际有 {len(nodes_edges[node3_id])} 条"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
621 |
|
622 |
# 7. 清理数据
|
623 |
print("== 测试 drop")
|
@@ -635,6 +740,179 @@ async def test_graph_batch_operations(storage):
|
|
635 |
return False
|
636 |
|
637 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
638 |
async def main():
|
639 |
"""主函数"""
|
640 |
# 显示程序标题
|
@@ -670,9 +948,10 @@ async def main():
|
|
670 |
ASCIIColors.white("1. 基本测试 (节点和边的插入、读取)")
|
671 |
ASCIIColors.white("2. 高级测试 (度数、标签、知识图谱、删除操作等)")
|
672 |
ASCIIColors.white("3. 批量操作测试 (批量获取节点、边属性和度数等)")
|
673 |
-
ASCIIColors.white("4.
|
|
|
674 |
|
675 |
-
choice = input("\n请输入选项 (1/2/3/4): ")
|
676 |
|
677 |
if choice == "1":
|
678 |
await test_graph_basic(storage)
|
@@ -681,6 +960,8 @@ async def main():
|
|
681 |
elif choice == "3":
|
682 |
await test_graph_batch_operations(storage)
|
683 |
elif choice == "4":
|
|
|
|
|
684 |
ASCIIColors.cyan("\n=== 开始基本测试 ===")
|
685 |
basic_result = await test_graph_basic(storage)
|
686 |
|
@@ -690,7 +971,11 @@ async def main():
|
|
690 |
|
691 |
if advanced_result:
|
692 |
ASCIIColors.cyan("\n=== 开始批量操作测试 ===")
|
693 |
-
await test_graph_batch_operations(storage)
|
|
|
|
|
|
|
|
|
694 |
else:
|
695 |
ASCIIColors.red("无效的选项")
|
696 |
|
|
|
209 |
else:
|
210 |
print(f"读取边属性失败: {node1_id} -> {node2_id}")
|
211 |
assert False, f"未能读取边属性: {node1_id} -> {node2_id}"
|
212 |
+
|
213 |
+
# 5.1 验证无向图特性 - 读取反向边属性
|
214 |
+
print(f"读取反向边属性: {node2_id} -> {node1_id}")
|
215 |
+
reverse_edge_props = await storage.get_edge(node2_id, node1_id)
|
216 |
+
if reverse_edge_props:
|
217 |
+
print(f"成功读取反向边属性: {node2_id} -> {node1_id}")
|
218 |
+
print(f"反向边关系: {reverse_edge_props.get('relationship', '无关系')}")
|
219 |
+
print(f"反向边描述: {reverse_edge_props.get('description', '无描述')}")
|
220 |
+
print(f"反向边权重: {reverse_edge_props.get('weight', '无权重')}")
|
221 |
+
# 验证正向和反向边属性是否相同
|
222 |
+
assert edge_props == reverse_edge_props, "正向和反向边属性不一致,无向图特性验证失败"
|
223 |
+
print("无向图特性验证成功:正向和反向边属性一致")
|
224 |
+
else:
|
225 |
+
print(f"读取反向边属性失败: {node2_id} -> {node1_id}")
|
226 |
+
assert False, f"未能读取反向边属性: {node2_id} -> {node1_id},无向图特性验证失败"
|
227 |
|
228 |
print("基本测试完成,数据已保留在数据库中")
|
229 |
return True
|
|
|
308 |
node1_degree = await storage.node_degree(node1_id)
|
309 |
print(f"节点 {node1_id} 的度数: {node1_degree}")
|
310 |
assert node1_degree == 1, f"节点 {node1_id} 的度数应为1,实际为 {node1_degree}"
|
311 |
+
|
312 |
+
# 2.1 测试所有节点的度数
|
313 |
+
print("== 测试所有节点的度数")
|
314 |
+
node2_degree = await storage.node_degree(node2_id)
|
315 |
+
node3_degree = await storage.node_degree(node3_id)
|
316 |
+
print(f"节点 {node2_id} 的度数: {node2_degree}")
|
317 |
+
print(f"节点 {node3_id} 的度数: {node3_degree}")
|
318 |
+
assert node2_degree == 2, f"节点 {node2_id} 的度数应为2,实际为 {node2_degree}"
|
319 |
+
assert node3_degree == 1, f"节点 {node3_id} 的度数应为1,实际为 {node3_degree}"
|
320 |
|
321 |
# 3. 测试 edge_degree - 获取边的度数
|
322 |
print(f"== 测试 edge_degree: {node1_id} -> {node2_id}")
|
|
|
324 |
print(f"边 {node1_id} -> {node2_id} 的度数: {edge_degree}")
|
325 |
assert (
|
326 |
edge_degree == 3
|
327 |
+
), f"边 {node1_id} -> {node2_id} 的度数应为3,实际为 {edge_degree}"
|
328 |
+
|
329 |
+
# 3.1 测试反向边的度数 - 验证无向图特性
|
330 |
+
print(f"== 测试反向边的度数: {node2_id} -> {node1_id}")
|
331 |
+
reverse_edge_degree = await storage.edge_degree(node2_id, node1_id)
|
332 |
+
print(f"反向边 {node2_id} -> {node1_id} 的度数: {reverse_edge_degree}")
|
333 |
+
assert edge_degree == reverse_edge_degree, f"正向边和反向边的度数不一致,无向图特性验证失败"
|
334 |
+
print("无向图特性验证成功:正向边和反向边的度数一致")
|
335 |
|
336 |
# 4. 测试 get_node_edges - 获取节点的所有边
|
337 |
print(f"== 测试 get_node_edges: {node2_id}")
|
|
|
340 |
assert (
|
341 |
len(node2_edges) == 2
|
342 |
), f"节点 {node2_id} 应有2条边,实际有 {len(node2_edges)}"
|
343 |
+
|
344 |
+
# 4.1 验证节点边的无向图特性
|
345 |
+
print("== 验证节点边的无向图特性")
|
346 |
+
# 检查是否包含与node1和node3的连接关系(无论方向)
|
347 |
+
has_connection_with_node1 = False
|
348 |
+
has_connection_with_node3 = False
|
349 |
+
for edge in node2_edges:
|
350 |
+
# 检查是否有与node1的连接(无论方向)
|
351 |
+
if (edge[0] == node1_id and edge[1] == node2_id) or (edge[0] == node2_id and edge[1] == node1_id):
|
352 |
+
has_connection_with_node1 = True
|
353 |
+
# 检查是否有与node3的连接(无论方向)
|
354 |
+
if (edge[0] == node2_id and edge[1] == node3_id) or (edge[0] == node3_id and edge[1] == node2_id):
|
355 |
+
has_connection_with_node3 = True
|
356 |
+
|
357 |
+
assert has_connection_with_node1, f"节点 {node2_id} 的边列表中应包含与 {node1_id} 的连接"
|
358 |
+
assert has_connection_with_node3, f"节点 {node2_id} 的边列表中应包含与 {node3_id} 的连接"
|
359 |
+
print(f"无向图特性验证成功:节点 {node2_id} 的边列表包含所有相关的边")
|
360 |
|
361 |
# 5. 测试 get_all_labels - 获取所有标签
|
362 |
print("== 测试 get_all_labels")
|
|
|
393 |
edge_props = await storage.get_edge(node2_id, node3_id)
|
394 |
print(f"删除后查询边属性 {node2_id} -> {node3_id}: {edge_props}")
|
395 |
assert edge_props is None, f"边 {node2_id} -> {node3_id} 应已被删除"
|
396 |
+
|
397 |
+
# 8.1 验证删除边的无向图特性
|
398 |
+
print(f"== 验证删��边的无向图特性: {node3_id} -> {node2_id}")
|
399 |
+
reverse_edge_props = await storage.get_edge(node3_id, node2_id)
|
400 |
+
print(f"删除后查询反向边属性 {node3_id} -> {node2_id}: {reverse_edge_props}")
|
401 |
+
assert reverse_edge_props is None, f"反向边 {node3_id} -> {node2_id} 也应被删除,无向图特性验证失败"
|
402 |
+
print("无向图特性验证成功:删除一个方向的边后,反向边也被删除")
|
403 |
|
404 |
# 9. 测试 remove_nodes - 批量删除节点
|
405 |
print(f"== 测试 remove_nodes: [{node2_id}, {node3_id}]")
|
|
|
657 |
edges_dict[(node3_id, node4_id)]["relationship"]
|
658 |
== edge5_data["relationship"]
|
659 |
), f"边 {node3_id} -> {node4_id} 关系不匹配"
|
660 |
+
|
661 |
+
# 5.1 测试反向边的批量获取 - 验证无向图特性
|
662 |
+
print("== 测试反向边的批量获取")
|
663 |
+
# 创建反向边的字典列表
|
664 |
+
reverse_edge_dicts = [{"src": tgt, "tgt": src} for src, tgt in edges]
|
665 |
+
reverse_edges_dict = await storage.get_edges_batch(reverse_edge_dicts)
|
666 |
+
print(f"批量获取反向边属性结果: {reverse_edges_dict.keys()}")
|
667 |
+
assert len(reverse_edges_dict) == 3, f"应返回3条反向边的属性,实际返回 {len(reverse_edges_dict)} 条"
|
668 |
+
|
669 |
+
# 验证正向和反向边的属性是否一致
|
670 |
+
for (src, tgt), props in edges_dict.items():
|
671 |
+
assert (tgt, src) in reverse_edges_dict, f"反向边 {tgt} -> {src} 应在返回结果中"
|
672 |
+
assert props == reverse_edges_dict[(tgt, src)], f"边 {src} -> {tgt} 和反向边 {tgt} -> {src} 的属性不一致"
|
673 |
+
|
674 |
+
print("无向图特性验证成功:批量获取的正向和反向边属性一致")
|
675 |
|
676 |
# 6. 测试 get_nodes_edges_batch - 批量获取多个节点的所有边
|
677 |
print("== 测试 get_nodes_edges_batch")
|
|
|
688 |
assert (
|
689 |
len(nodes_edges[node3_id]) == 3
|
690 |
), f"{node3_id} 应有3条边,实际有 {len(nodes_edges[node3_id])} 条"
|
691 |
+
|
692 |
+
# 6.1 验证批量获取节点边的无向图特性
|
693 |
+
print("== 验证批量获取节点边的无向图特性")
|
694 |
+
|
695 |
+
# 检查节点1的边是否包含所有相关的边(无论方向)
|
696 |
+
node1_outgoing_edges = [(src, tgt) for src, tgt in nodes_edges[node1_id] if src == node1_id]
|
697 |
+
node1_incoming_edges = [(src, tgt) for src, tgt in nodes_edges[node1_id] if tgt == node1_id]
|
698 |
+
print(f"节点 {node1_id} 的出边: {node1_outgoing_edges}")
|
699 |
+
print(f"节点 {node1_id} 的入边: {node1_incoming_edges}")
|
700 |
+
|
701 |
+
# 检查是否包含到机器学习、自然语言处理和计算机视觉的边
|
702 |
+
has_edge_to_node2 = any(tgt == node2_id for _, tgt in node1_outgoing_edges)
|
703 |
+
has_edge_to_node4 = any(tgt == node4_id for _, tgt in node1_outgoing_edges)
|
704 |
+
has_edge_to_node5 = any(tgt == node5_id for _, tgt in node1_outgoing_edges)
|
705 |
+
|
706 |
+
assert has_edge_to_node2, f"节点 {node1_id} 的边列表中应包含到 {node2_id} 的边"
|
707 |
+
assert has_edge_to_node4, f"节点 {node1_id} 的边列表中应包含到 {node4_id} 的边"
|
708 |
+
assert has_edge_to_node5, f"节点 {node1_id} 的边列表中应包含到 {node5_id} 的边"
|
709 |
+
|
710 |
+
# 检查节点3的边是否包含所有相关的边(无论方向)
|
711 |
+
node3_outgoing_edges = [(src, tgt) for src, tgt in nodes_edges[node3_id] if src == node3_id]
|
712 |
+
node3_incoming_edges = [(src, tgt) for src, tgt in nodes_edges[node3_id] if tgt == node3_id]
|
713 |
+
print(f"节点 {node3_id} 的出边: {node3_outgoing_edges}")
|
714 |
+
print(f"节点 {node3_id} 的入边: {node3_incoming_edges}")
|
715 |
+
|
716 |
+
# 检查是否包含从机器学习来的边,以及到自然语言处理和计算机视觉的边
|
717 |
+
has_edge_from_node2 = any(src == node2_id for src, _ in node3_incoming_edges)
|
718 |
+
has_edge_to_node4 = any(tgt == node4_id for _, tgt in node3_outgoing_edges)
|
719 |
+
has_edge_to_node5 = any(tgt == node5_id for _, tgt in node3_outgoing_edges)
|
720 |
+
|
721 |
+
assert has_edge_from_node2, f"节点 {node3_id} 的边列表中应包含从 {node2_id} 来的边"
|
722 |
+
assert has_edge_to_node4, f"节点 {node3_id} 的边列表中应包含到 {node4_id} 的边"
|
723 |
+
assert has_edge_to_node5, f"节点 {node3_id} 的边列表中应包含到 {node5_id} 的边"
|
724 |
+
|
725 |
+
print("无向图特性验证成功:批量获取的节点边包含所有相关的边(无论方向)")
|
726 |
|
727 |
# 7. 清理数据
|
728 |
print("== 测试 drop")
|
|
|
740 |
return False
|
741 |
|
742 |
|
743 |
+
async def test_graph_undirected_property(storage):
|
744 |
+
"""
|
745 |
+
专门测试图存储的无向图特性:
|
746 |
+
1. 验证插入一个方向的边后,反向查询是否能获得相同的结果
|
747 |
+
2. 验证边的属性在正向和反向查询中是否一致
|
748 |
+
3. 验证删除一个方向的边后��另一个方向的边是否也被删除
|
749 |
+
4. 验证批量操作中的无向图特性
|
750 |
+
"""
|
751 |
+
try:
|
752 |
+
# 清理之前的测试数据
|
753 |
+
print("清理之前的测试数据...\n")
|
754 |
+
await storage.drop()
|
755 |
+
|
756 |
+
# 1. 插入测试数据
|
757 |
+
# 插入节点1: 计算机科学
|
758 |
+
node1_id = "计算机科学"
|
759 |
+
node1_data = {
|
760 |
+
"entity_id": node1_id,
|
761 |
+
"description": "计算机科学是研究计算机及其应用的科学。",
|
762 |
+
"keywords": "计算机,科学,技术",
|
763 |
+
"entity_type": "学科",
|
764 |
+
}
|
765 |
+
print(f"插入节点1: {node1_id}")
|
766 |
+
await storage.upsert_node(node1_id, node1_data)
|
767 |
+
|
768 |
+
# 插入节点2: 数据结构
|
769 |
+
node2_id = "数据结构"
|
770 |
+
node2_data = {
|
771 |
+
"entity_id": node2_id,
|
772 |
+
"description": "数据结构是计算机科学中的一个基础概念,用于组织和存储数据。",
|
773 |
+
"keywords": "数据,结构,组织",
|
774 |
+
"entity_type": "概念",
|
775 |
+
}
|
776 |
+
print(f"插入节点2: {node2_id}")
|
777 |
+
await storage.upsert_node(node2_id, node2_data)
|
778 |
+
|
779 |
+
# 插入节点3: 算法
|
780 |
+
node3_id = "算法"
|
781 |
+
node3_data = {
|
782 |
+
"entity_id": node3_id,
|
783 |
+
"description": "算法是解决问题的步骤和方法。",
|
784 |
+
"keywords": "算法,步骤,方法",
|
785 |
+
"entity_type": "概念",
|
786 |
+
}
|
787 |
+
print(f"插入节点3: {node3_id}")
|
788 |
+
await storage.upsert_node(node3_id, node3_data)
|
789 |
+
|
790 |
+
# 2. 测试插入边后的无向图特性
|
791 |
+
print("\n== 测试插入边后的无向图特性")
|
792 |
+
|
793 |
+
# 插入边1: 计算机科学 -> 数据结构
|
794 |
+
edge1_data = {
|
795 |
+
"relationship": "包含",
|
796 |
+
"weight": 1.0,
|
797 |
+
"description": "计算机科学包含数据结构这个概念",
|
798 |
+
}
|
799 |
+
print(f"插入边1: {node1_id} -> {node2_id}")
|
800 |
+
await storage.upsert_edge(node1_id, node2_id, edge1_data)
|
801 |
+
|
802 |
+
# 验证正向查询
|
803 |
+
forward_edge = await storage.get_edge(node1_id, node2_id)
|
804 |
+
print(f"正向边属性: {forward_edge}")
|
805 |
+
assert forward_edge is not None, f"未能读取正向边属性: {node1_id} -> {node2_id}"
|
806 |
+
|
807 |
+
# 验证反向查询
|
808 |
+
reverse_edge = await storage.get_edge(node2_id, node1_id)
|
809 |
+
print(f"反向边属性: {reverse_edge}")
|
810 |
+
assert reverse_edge is not None, f"未能读取反向边属性: {node2_id} -> {node1_id}"
|
811 |
+
|
812 |
+
# 验证正向和反向边属性是否一致
|
813 |
+
assert forward_edge == reverse_edge, "正向和反向边属性不一致,无向图特性验证失败"
|
814 |
+
print("无向图特性验证成功:正向和反向边属性一致")
|
815 |
+
|
816 |
+
# 3. 测试边的度数的无向图特性
|
817 |
+
print("\n== 测试边的度数的无向图特性")
|
818 |
+
|
819 |
+
# 插入边2: 计算机科学 -> 算法
|
820 |
+
edge2_data = {
|
821 |
+
"relationship": "包含",
|
822 |
+
"weight": 1.0,
|
823 |
+
"description": "计算机科学包含算法这个概念",
|
824 |
+
}
|
825 |
+
print(f"插入边2: {node1_id} -> {node3_id}")
|
826 |
+
await storage.upsert_edge(node1_id, node3_id, edge2_data)
|
827 |
+
|
828 |
+
# 验证正向和反向边的度数
|
829 |
+
forward_degree = await storage.edge_degree(node1_id, node2_id)
|
830 |
+
reverse_degree = await storage.edge_degree(node2_id, node1_id)
|
831 |
+
print(f"正向边 {node1_id} -> {node2_id} 的度数: {forward_degree}")
|
832 |
+
print(f"反向边 {node2_id} -> {node1_id} 的度数: {reverse_degree}")
|
833 |
+
assert forward_degree == reverse_degree, "正向和反向边的度数不一致,无向图特性验证失败"
|
834 |
+
print("无向图特性验证成功:正向和反向边的度数一致")
|
835 |
+
|
836 |
+
# 4. 测试删除边的无向图特性
|
837 |
+
print("\n== 测试删除边的无向图特性")
|
838 |
+
|
839 |
+
# 删除正向边
|
840 |
+
print(f"删除边: {node1_id} -> {node2_id}")
|
841 |
+
await storage.remove_edges([(node1_id, node2_id)])
|
842 |
+
|
843 |
+
# 验证正向边是否被删除
|
844 |
+
forward_edge = await storage.get_edge(node1_id, node2_id)
|
845 |
+
print(f"删除后查询正向边属性 {node1_id} -> {node2_id}: {forward_edge}")
|
846 |
+
assert forward_edge is None, f"边 {node1_id} -> {node2_id} 应已被删除"
|
847 |
+
|
848 |
+
# 验证反向边是否也被删除
|
849 |
+
reverse_edge = await storage.get_edge(node2_id, node1_id)
|
850 |
+
print(f"删除后查询反向边属性 {node2_id} -> {node1_id}: {reverse_edge}")
|
851 |
+
assert reverse_edge is None, f"反向边 {node2_id} -> {node1_id} 也应被删除,无向图特性验证失败"
|
852 |
+
print("无向图特性验证成功:删除一个方向的边后,反向边也被删除")
|
853 |
+
|
854 |
+
# 5. 测试批量操作中的无向图特性
|
855 |
+
print("\n== 测试批量操作中的无向图特性")
|
856 |
+
|
857 |
+
# 重新插入边
|
858 |
+
await storage.upsert_edge(node1_id, node2_id, edge1_data)
|
859 |
+
|
860 |
+
# 批量获取边属性
|
861 |
+
edge_dicts = [{"src": node1_id, "tgt": node2_id}, {"src": node1_id, "tgt": node3_id}]
|
862 |
+
reverse_edge_dicts = [{"src": node2_id, "tgt": node1_id}, {"src": node3_id, "tgt": node1_id}]
|
863 |
+
|
864 |
+
edges_dict = await storage.get_edges_batch(edge_dicts)
|
865 |
+
reverse_edges_dict = await storage.get_edges_batch(reverse_edge_dicts)
|
866 |
+
|
867 |
+
print(f"批量获取正向边属性结果: {edges_dict.keys()}")
|
868 |
+
print(f"批量获取反向边属性结果: {reverse_edges_dict.keys()}")
|
869 |
+
|
870 |
+
# 验证正向和反向边的属性是否一致
|
871 |
+
for (src, tgt), props in edges_dict.items():
|
872 |
+
assert (tgt, src) in reverse_edges_dict, f"反向边 {tgt} -> {src} 应在返回结果中"
|
873 |
+
assert props == reverse_edges_dict[(tgt, src)], f"边 {src} -> {tgt} 和反向边 {tgt} -> {src} 的属性不一致"
|
874 |
+
|
875 |
+
print("无向图特性验证成功:批量获取的正向和反向边属性一致")
|
876 |
+
|
877 |
+
# 6. 测试批量获取节点边的无向图特性
|
878 |
+
print("\n== 测试批量获取节点边的无向图特性")
|
879 |
+
|
880 |
+
nodes_edges = await storage.get_nodes_edges_batch([node1_id, node2_id])
|
881 |
+
print(f"批量获取节点边结果: {nodes_edges.keys()}")
|
882 |
+
|
883 |
+
# 检查节点1的边是否包含所有相关的边(无论方向)
|
884 |
+
node1_edges = nodes_edges[node1_id]
|
885 |
+
node2_edges = nodes_edges[node2_id]
|
886 |
+
|
887 |
+
# 检查节点1是否有到节点2和节点3的边
|
888 |
+
has_edge_to_node2 = any((src == node1_id and tgt == node2_id) for src, tgt in node1_edges)
|
889 |
+
has_edge_to_node3 = any((src == node1_id and tgt == node3_id) for src, tgt in node1_edges)
|
890 |
+
|
891 |
+
assert has_edge_to_node2, f"节点 {node1_id} 的边列表中应包含到 {node2_id} 的边"
|
892 |
+
assert has_edge_to_node3, f"节点 {node1_id} 的边列表中应包含到 {node3_id} 的边"
|
893 |
+
|
894 |
+
# 检查节点2是否有到节点1的边
|
895 |
+
has_edge_to_node1 = any((src == node2_id and tgt == node1_id) or (src == node1_id and tgt == node2_id) for src, tgt in node2_edges)
|
896 |
+
assert has_edge_to_node1, f"节点 {node2_id} 的边列表中应包含与 {node1_id} 的连接"
|
897 |
+
|
898 |
+
print("无向图特性验证成功:批量获取的节点边包含所有相关的边(无论方向)")
|
899 |
+
|
900 |
+
# 7. 清理数据
|
901 |
+
print("== 测试 drop")
|
902 |
+
result = await storage.drop()
|
903 |
+
print(f"清理结果: {result}")
|
904 |
+
assert (
|
905 |
+
result["status"] == "success"
|
906 |
+
), f"清理应成功,实际状态为 {result['status']}"
|
907 |
+
|
908 |
+
print("\n无向图特性测试完成")
|
909 |
+
return True
|
910 |
+
|
911 |
+
except Exception as e:
|
912 |
+
ASCIIColors.red(f"测试过程中发生错误: {str(e)}")
|
913 |
+
return False
|
914 |
+
|
915 |
+
|
916 |
async def main():
|
917 |
"""主函数"""
|
918 |
# 显示程序标题
|
|
|
948 |
ASCIIColors.white("1. 基本测试 (节点和边的插入、读取)")
|
949 |
ASCIIColors.white("2. 高级测试 (度数、标签、知识图谱、删除操作等)")
|
950 |
ASCIIColors.white("3. 批量操作测试 (批量获取节点、边属性和度数等)")
|
951 |
+
ASCIIColors.white("4. 无向图特性测试 (验证存储的无向图特性)")
|
952 |
+
ASCIIColors.white("5. 全部测试")
|
953 |
|
954 |
+
choice = input("\n请输入选项 (1/2/3/4/5): ")
|
955 |
|
956 |
if choice == "1":
|
957 |
await test_graph_basic(storage)
|
|
|
960 |
elif choice == "3":
|
961 |
await test_graph_batch_operations(storage)
|
962 |
elif choice == "4":
|
963 |
+
await test_graph_undirected_property(storage)
|
964 |
+
elif choice == "5":
|
965 |
ASCIIColors.cyan("\n=== 开始基本测试 ===")
|
966 |
basic_result = await test_graph_basic(storage)
|
967 |
|
|
|
971 |
|
972 |
if advanced_result:
|
973 |
ASCIIColors.cyan("\n=== 开始批量操作测试 ===")
|
974 |
+
batch_result = await test_graph_batch_operations(storage)
|
975 |
+
|
976 |
+
if batch_result:
|
977 |
+
ASCIIColors.cyan("\n=== 开始无向图特性测试 ===")
|
978 |
+
await test_graph_undirected_property(storage)
|
979 |
else:
|
980 |
ASCIIColors.red("无效的选项")
|
981 |
|