"""
-------------------------------------------------------------------------
This file is part of the RAGSDK project.
Copyright (c) 2025 Huawei Technologies Co.,Ltd.
RAGSDK is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
-------------------------------------------------------------------------
"""
import unittest
from unittest.mock import MagicMock, call, patch
from paddle.base import libpaddle
from mx_rag.graphrag.graphs.opengauss_graph import OpenGaussGraph
class TestOpenGaussGraph(unittest.TestCase):
def setUp(self):
patcher_adapter = patch('mx_rag.graphrag.graphs.opengauss_graph.OpenGaussAGEAdapter', autospec=True)
patcher_settings = patch('mx_rag.graphrag.graphs.opengauss_graph.openGaussAGEGraph', autospec=True)
self.mock_adapter_cls = patcher_adapter.start()
self.mock_settings_cls = patcher_settings.start()
self.addCleanup(patcher_adapter.stop)
self.addCleanup(patcher_settings.stop)
self.mock_adapter = self.mock_adapter_cls.return_value
self.mock_adapter.connection = MagicMock()
self.age_graph = self.mock_settings_cls.return_value
self.graph = OpenGaussGraph('test_graph', self.age_graph)
def test_add_node_calls_adapter(self):
self.mock_adapter.execute_cypher_query.reset_mock()
self.graph.has_node = MagicMock(side_effect=[False])
self.graph.add_node("foo", foo_attr=1)
self.mock_adapter.execute_cypher_query.assert_called_once()
args = self.mock_adapter.execute_cypher_query.call_args[0][0]
self.assertIn("CREATE (n:Node", args)
self.assertIn("foo_attr", args)
def test_save_writes_json(self):
self.graph.get_nodes = MagicMock(return_value=[("foo", {"id": "id1", "text": "foo"})])
self.graph.get_edges = MagicMock(return_value=[("foo", "bar", {"start_id": "id1", "end_id": "id2"})])
with patch("os.fdopen", unittest.mock.mock_open()) as m:
self.graph.save("dummy.json")
handle = m()
written = "".join(call.args[0] for call in handle.write.call_args_list)
self.assertIn('"nodes"', written)
self.assertIn('"links"', written)
self.assertIn('"foo"', written)
def test_add_nodes_from_tuple_and_str(self):
self.graph.has_node = MagicMock(side_effect=[False, False])
self.graph.add_node = MagicMock()
self.graph.add_nodes_from([("foo", {"a": 1}), "bar"], common=2)
self.graph.add_node.assert_any_call("foo", a=1, common=2)
self.graph.add_node.assert_any_call("bar", common=2)
self.assertEqual(self.graph.add_node.call_count, 2)
def test_remove_node_calls_adapter_if_exists(self):
self.graph.has_node = MagicMock(return_value=True)
self.mock_adapter.execute_cypher_query.reset_mock()
self.graph.remove_node("foo")
self.mock_adapter.execute_cypher_query.assert_called_once()
def test_remove_node_does_nothing_if_not_exists(self):
self.graph.has_node = MagicMock(return_value=False)
self.mock_adapter.execute_cypher_query.reset_mock()
self.graph.remove_node("foo")
self.mock_adapter.execute_cypher_query.assert_not_called()
def test_has_node_true_false(self):
self.mock_adapter.execute_cypher_query.return_value = [{}]
self.assertTrue(self.graph.has_node("foo"))
self.mock_adapter.execute_cypher_query.return_value = []
self.assertFalse(self.graph.has_node("foo"))
def test_has_node_type_error(self):
self.mock_adapter.execute_cypher_query.side_effect = TypeError("Type Error")
self.assertFalse(self.graph.has_node("foo"))
self.mock_adapter.execute_cypher_query.assert_called_once()
def test_has_node_attribute_error(self):
self.mock_adapter.execute_cypher_query.side_effect = AttributeError("Attribute Error")
self.assertFalse(self.graph.has_node("foo"))
self.mock_adapter.execute_cypher_query.assert_called_once()
def test_has_node_general_exception(self):
error_message = "does not exist"
self.mock_adapter.execute_cypher_query.side_effect = Exception(error_message)
self.assertFalse(self.graph.has_node("foo"))
self.mock_adapter.execute_cypher_query.assert_called_once()
def test_has_node_unexpected_exception(self):
self.mock_adapter.execute_cypher_query.side_effect = Exception("Unexpected Error")
with self.assertRaises(Exception):
self.graph.has_node("foo")
self.mock_adapter.execute_cypher_query.assert_called_once()
def test_get_node_attributes_all_and_key(self):
self.mock_adapter.execute_cypher_query.side_effect = [
[{"props": {"a": 1}}],
[{"value": 2}]
]
self.assertEqual(self.graph.get_node_attributes("foo"), {"a": 1})
self.assertEqual(self.graph.get_node_attributes("foo", "bar"), 2)
def test_set_node_attributes_empty(self):
self.mock_adapter.execute_cypher_query.reset_mock()
self.graph.set_node_attributes({}, "foo")
self.mock_adapter.execute_cypher_query.assert_not_called()
def test_set_node_attributes_nonempty(self):
self.mock_adapter.execute_cypher_query.reset_mock()
self.graph.set_node_attributes({"foo": 1, "bar": 2}, "baz")
self.mock_adapter.execute_cypher_query.assert_called_once()
arg = self.mock_adapter.execute_cypher_query.call_args[0][0]
self.assertIn("UNWIND", arg)
self.assertIn("SET n.baz = item.value", arg)
def test_update_node_attribute_append_false(self):
self.mock_adapter.execute_cypher_query.reset_mock()
self.graph.get_node_attributes = MagicMock()
self.graph.update_node_attribute("foo", "bar", "baz", append=False)
self.mock_adapter.execute_cypher_query.assert_called_once()
def test_update_node_attribute_append_true(self):
self.graph.get_node_attributes = MagicMock(return_value="a,b")
self.mock_adapter.execute_cypher_query.reset_mock()
self.graph.update_node_attribute("foo", "bar", "c", append=True)
self.mock_adapter.execute_cypher_query.assert_called_once()
def test_update_node_attributes_batch_no_updates(self):
self.mock_adapter.execute_cypher_query.reset_mock()
self.graph.update_node_attributes_batch([])
self.mock_adapter.execute_cypher_query.assert_not_called()
def test_update_node_attributes_batch_append_false(self):
self.mock_adapter.execute_cypher_query.reset_mock()
updates = [("foo", {"a": "1"}), ("bar", {"a": "2"})]
with patch("mx_rag.graphrag.graphs.opengauss_graph.tqdm", lambda x, **k: x):
self.graph.update_node_attributes_batch(updates, batch_size=1, append=False)
self.assertTrue(self.mock_adapter.execute_cypher_query.called)
def test_update_node_attributes_batch_append_true(self):
self.graph.get_node_attributes = MagicMock(return_value={"a": "1"})
updates = [("foo", {"a": "2"})]
with patch("mx_rag.graphrag.graphs.opengauss_graph.tqdm", lambda x, **k: x):
self.graph.update_node_attributes_batch(updates, batch_size=1, append=True)
self.assertTrue(self.mock_adapter.execute_cypher_query.called)
def test_update_edge_attributes_batch_no_updates(self):
self.mock_adapter.execute_cypher_query.reset_mock()
self.graph.update_edge_attributes_batch([])
self.mock_adapter.execute_cypher_query.assert_not_called()
def test_update_edge_attributes_batch_append_false(self):
self.mock_adapter.execute_cypher_query.reset_mock()
updates = [
("foo", "bar", {"a": "1"}),
("baz", "qux", {"a": "2", "b": "3"})
]
with patch("mx_rag.graphrag.graphs.opengauss_graph.tqdm", lambda x, **k: x):
self.graph.update_edge_attributes_batch(updates, batch_size=1, append=False)
self.assertTrue(self.mock_adapter.execute_cypher_query.called)
self.assertEqual(self.mock_adapter.execute_cypher_query.call_count, 2)
for call_args in self.mock_adapter.execute_cypher_query.call_args_list:
cypher = call_args[0][0]
self.assertIn("UNWIND", cypher)
self.assertIn("MATCH (a:Node)-[r]->(b:Node)", cypher)
self.assertIn("SET", cypher)
def test_update_edge_attributes_batch_append_true_merges(self):
self.graph.get_edge_attributes = MagicMock(side_effect=[
{"a": "1,2"}, {"a": "2,3", "b": "x"}
])
updates = [
("foo", "bar", {"a": "2,3"}),
("baz", "qux", {"a": "4", "b": "y"})
]
with patch("mx_rag.graphrag.graphs.opengauss_graph.tqdm", lambda x, **k: x):
self.graph.update_edge_attributes_batch(updates, batch_size=2, append=True)
self.assertTrue(self.mock_adapter.execute_cypher_query.called)
cypher = self.mock_adapter.execute_cypher_query.call_args[0][0]
self.assertIn('a: "1,2,3"', cypher)
self.assertIn('a: "2,3,4"', cypher)
self.assertIn('b: "x,y"', cypher)
def test_update_edge_attributes_batch_handles_empty_old_and_new(self):
self.graph.get_edge_attributes = MagicMock(return_value={})
updates = [("foo", "bar", {"a": ""})]
with patch("mx_rag.graphrag.graphs.opengauss_graph.tqdm", lambda x, **k: x):
self.graph.update_edge_attributes_batch(updates, batch_size=1, append=True)
cypher = self.mock_adapter.execute_cypher_query.call_args[0][0]
self.assertIn('a: ""', cypher)
def test_update_edge_attributes_batch_multiple_keys(self):
self.graph.get_edge_attributes = MagicMock(return_value={"a": "1", "b": "2"})
updates = [("foo", "bar", {"a": "2", "b": "3"})]
with patch("mx_rag.graphrag.graphs.opengauss_graph.tqdm", lambda x, **k: x):
self.graph.update_edge_attributes_batch(updates, batch_size=1, append=True)
cypher = self.mock_adapter.execute_cypher_query.call_args[0][0]
self.assertIn('a: "1,2"', cypher)
self.assertIn('b: "2,3"', cypher)
def test_get_nodes_with_data(self):
self.mock_adapter.execute_cypher_query.return_value = [
{"label": "node1", "props": {"key1": "value1"}},
{"label": "node2", "props": {"key2": "value2"}}
]
result = self.graph.get_nodes(with_data=True)
self.mock_adapter.execute_cypher_query.assert_called_once_with(
"MATCH (n:Node) RETURN n.text AS label, properties(n) AS props")
self.assertEqual(result, [("node1", {"key1": "value1"}), ("node2", {"key2": "value2"})])
def test_get_nodes_without_data(self):
self.mock_adapter.execute_cypher_query.return_value = [
{"label": "node1"},
{"label": "node2"}
]
result = self.graph.get_nodes(with_data=False)
self.mock_adapter.execute_cypher_query.assert_called_once_with("MATCH (n:Node) RETURN n.text AS label")
self.assertEqual(result, ["node1", "node2"])
def test_get_nodes_by_attribute(self):
self.mock_adapter.execute_cypher_query.return_value = [
{"props": {"text": "node1"}},
{"props": {"text": "node2"}}
]
result = self.graph.get_nodes_by_attribute("key", "value")
self.mock_adapter.execute_cypher_query.assert_called_once_with(
"MATCH (n:Node) WHERE n.key = 'value' RETURN properties(n) AS props")
self.assertEqual(result, ["node1", "node2"])
def test_get_nodes_containing_attribute_value(self):
self.mock_adapter.execute_cypher_query.return_value = [
{"props": {"text": "node1"}},
{"props": {"text": "node2"}}
]
result = self.graph.get_nodes_containing_attribute_value("key", "substring")
self.mock_adapter.execute_cypher_query.assert_called_once_with(
'MATCH (n:Node) WHERE toString(n.key) CONTAINS \'substring\' RETURN properties(n) AS props'
)
self.assertEqual(result, ["node1", "node2"])
def test_add_edge(self):
self.graph.has_node = MagicMock(side_effect=[True, False])
self.graph.has_edge = MagicMock(side_effect=[False])
self.graph.add_node = MagicMock()
self.graph.add_edge("node1", "node2", relation="KNOWS")
self.graph.has_node.assert_any_call("node1")
self.graph.has_node.assert_any_call("node2")
self.graph.add_node.assert_called_once_with("node2")
self.mock_adapter.execute_cypher_query.assert_called_once()
query = self.mock_adapter.execute_cypher_query.call_args[0][0]
self.assertIn("MERGE (a)-[r:`'KNOWS'`", query)
def test_add_edge_syntax_error(self):
self.graph.has_node = MagicMock(side_effect=[True, True])
self.graph.has_edge = MagicMock(side_effect=[False])
self.mock_adapter.execute_cypher_query.side_effect = SyntaxError("Syntax Error")
with self.assertRaises(SyntaxError):
self.graph.add_edge("node1", "node2", relation="KNOWS")
self.mock_adapter.execute_cypher_query.assert_called_once()
def test_add_edge_connection_error(self):
self.graph.has_node = MagicMock(side_effect=[True, True])
self.graph.has_edge = MagicMock(side_effect=[False])
self.mock_adapter.execute_cypher_query.side_effect = ConnectionError("Connection Error")
with self.assertRaises(ConnectionError):
self.graph.add_edge("node1", "node2", relation="KNOWS")
self.mock_adapter.execute_cypher_query.assert_called_once()
def test_add_edge_general_exception(self):
self.graph.has_node = MagicMock(side_effect=[True, True])
self.graph.has_edge = MagicMock(side_effect=[False])
self.mock_adapter.execute_cypher_query.side_effect = Exception("General Error")
with self.assertRaises(Exception):
self.graph.add_edge("node1", "node2", relation="KNOWS")
self.mock_adapter.execute_cypher_query.assert_called_once()
def test_add_edges_from(self):
self.graph.add_edge = MagicMock()
edges = [("node1", "node2"), ("node3", "node4", {"relation": "KNOWS"})]
self.graph.add_edges_from(edges)
self.graph.add_edge.assert_any_call("node1", "node2")
self.graph.add_edge.assert_any_call("node3", "node4", relation="KNOWS")
self.assertEqual(self.graph.add_edge.call_count, 2)
def test_remove_edge(self):
self.graph.has_edge = MagicMock(return_value=True)
self.graph.remove_edge("node1", "node2")
self.graph.has_edge.assert_called_once_with("node1", "node2")
self.mock_adapter.execute_cypher_query.assert_called_once()
query = self.mock_adapter.execute_cypher_query.call_args[0][0]
self.assertIn("DELETE r", query)
def test_has_edge(self):
self.mock_adapter.execute_cypher_query.return_value = [{}]
result = self.graph.has_edge("node1", "node2")
self.mock_adapter.execute_cypher_query.assert_called_once()
self.assertTrue(result)
self.mock_adapter.execute_cypher_query.return_value = []
result = self.graph.has_edge("node1", "node2")
self.assertFalse(result)
def test_has_edge_syntax_error(self):
self.mock_adapter.execute_cypher_query.side_effect = SyntaxError("Syntax Error")
with self.assertRaises(SyntaxError):
self.graph.has_edge("node1", "node2")
self.mock_adapter.execute_cypher_query.assert_called_once()
def test_has_edge_value_error(self):
self.mock_adapter.execute_cypher_query.side_effect = ValueError("Invalid Value")
with self.assertRaises(ValueError):
self.graph.has_edge("node1", "node2")
self.mock_adapter.execute_cypher_query.assert_called_once()
def test_has_edge_general_exception(self):
error_message = "does not exist"
self.mock_adapter.execute_cypher_query.side_effect = Exception(error_message)
result = self.graph.has_edge("node1", "node2")
self.assertFalse(result)
self.mock_adapter.execute_cypher_query.assert_called_once()
def test_get_edge_attributes_with_key(self):
self.mock_adapter.execute_cypher_query.return_value = [{'value': 'test_value'}]
result = self.graph.get_edge_attributes('node1', 'node2', 'key1')
self.mock_adapter.execute_cypher_query.assert_called_once()
self.assertEqual(result, 'test_value')
def test_get_edge_attributes_without_key(self):
self.mock_adapter.execute_cypher_query.return_value = [{'props': {'key1': 'value1', 'key2': 'value2'}}]
result = self.graph.get_edge_attributes('node1', 'node2')
self.mock_adapter.execute_cypher_query.assert_called_once()
self.assertEqual(result, {'key1': 'value1', 'key2': 'value2'})
def test_update_edge_attribute_append_false(self):
self.mock_adapter.execute_cypher_query.reset_mock()
self.graph.has_edge = MagicMock(return_value=True)
self.graph.update_edge_attribute('node1', 'node2', 'key1', 'value1', append=False)
self.mock_adapter.execute_cypher_query.assert_called_once()
def test_update_edge_attribute_append_true(self):
self.mock_adapter.execute_cypher_query.reset_mock()
self.graph.has_edge = MagicMock(return_value=True)
self.graph.update_edge_attribute('node1', 'node2', 'key1', 'value1', append=True)
self.mock_adapter.execute_cypher_query.assert_called_once()
def test_get_edges_with_data(self):
self.mock_adapter.execute_cypher_query.return_value = [
{
"source": "node1",
"target": "node2",
"start_id": "id1",
"end_id": "id2",
"props": {"key1": "value1"}
}
]
result = self.graph.get_edges(with_data=True)
self.mock_adapter.execute_cypher_query.assert_called_once()
self.assertEqual(result, [('node1', 'node2', {'start_id': 'id1', 'end_id': 'id2', 'key1': 'value1'})])
def test_get_edges_without_data(self):
self.mock_adapter.execute_cypher_query.return_value = [
{
"source": "node1",
"target": "node2",
"start_id": "id1",
"end_id": "id2"
}
]
result = self.graph.get_edges(with_data=False)
self.mock_adapter.execute_cypher_query.assert_called_once()
self.assertEqual(result, [('node1', 'node2', {'start_id': 'id1', 'end_id': 'id2'})])
def test_get_edge_attribute_values(self):
self.mock_adapter.execute_cypher_query.return_value = [
{'props': {'key1': 'value1'}},
{'props': {'key1': 'value2'}}
]
result = self.graph.get_edge_attribute_values('key1')
self.mock_adapter.execute_cypher_query.assert_called_once()
self.assertEqual(result, ['value1', 'value2'])
def test_in_degree(self):
self.mock_adapter.execute_cypher_query.return_value = [{'deg': 3}]
result = self.graph.in_degree('node1')
self.mock_adapter.execute_cypher_query.assert_called_once()
self.assertEqual(result, 3)
def test_out_degree(self):
self.mock_adapter.execute_cypher_query.return_value = [{'deg': 2}]
result = self.graph.out_degree('node1')
self.mock_adapter.execute_cypher_query.assert_called_once()
self.assertEqual(result, 2)
def test_neighbors(self):
self.mock_adapter.execute_cypher_query.return_value = [{'label': 'node2'}, {'label': 'node3'}]
result = self.graph.neighbors('node1')
self.mock_adapter.execute_cypher_query.assert_called_once()
self.assertEqual(result, ['node2', 'node3'])
def test_successors(self):
self.mock_adapter.execute_cypher_query.return_value = [{'label': 'node2'}, {'label': 'node3'}]
result = self.graph.successors('node1')
self.mock_adapter.execute_cypher_query.assert_called_once()
self.assertEqual(result, ['node2', 'node3'])
def test_predecessors(self):
self.mock_adapter.execute_cypher_query.return_value = [{'label': 'node2'}, {'label': 'node3'}]
result = self.graph.predecessors('node1')
self.mock_adapter.execute_cypher_query.assert_called_once()
self.assertEqual(result, ['node2', 'node3'])
def test_number_of_nodes(self):
self.mock_adapter.execute_cypher_query.return_value = [{'cnt': 5}]
result = self.graph.number_of_nodes()
self.mock_adapter.execute_cypher_query.assert_called_once_with("MATCH (n:Node) RETURN count(n) AS cnt")
self.assertEqual(result, 5)
def test_number_of_edges(self):
self.mock_adapter.execute_cypher_query.return_value = [{'cnt': 10}]
result = self.graph.number_of_edges()
self.mock_adapter.execute_cypher_query.assert_called_once_with("MATCH ()-[r]->() RETURN count(r) AS cnt")
self.assertEqual(result, 10)
def test_density(self):
self.graph.number_of_nodes = MagicMock(return_value=5)
self.graph.number_of_edges = MagicMock(return_value=10)
result = self.graph.density()
self.assertEqual(result, 0.5)
def test_density_with_one_node(self):
self.graph.number_of_nodes = MagicMock(return_value=1)
self.graph.number_of_edges = MagicMock(return_value=0)
result = self.graph.density()
self.assertEqual(result, 0.0)
def test_connected_components_weakly(self):
self.graph._find_weakly_connected_components = MagicMock(return_value=[{'A', 'B'}, {'C'}])
result = self.graph.connected_components(is_directed=True)
self.graph._find_weakly_connected_components.assert_called_once()
self.assertEqual(result, [{'A', 'B'}, {'C'}])
def test_connected_components_strongly(self):
self.graph._find_strongly_connected_components = MagicMock(return_value=[{'A'}, {'B', 'C'}])
result = self.graph.connected_components(is_directed=False)
self.graph._find_strongly_connected_components.assert_called_once()
self.assertEqual(result, [{'A'}, {'B', 'C'}])
def test_create_index_for_edge_no_relations(self):
self.graph.get_edge_attribute_values = MagicMock(return_value=[])
self.graph.create_index_for_edge()
self.graph.get_edge_attribute_values.assert_called_once_with("relation")
self.mock_adapter.execute_cypher_query.assert_not_called()
def test_create_index_for_edge_with_relations(self):
self.graph.get_edge_attribute_values = MagicMock(return_value=["relation1", "relation2"])
self.graph._create_relation_indexes = MagicMock(return_value=True)
self.graph.create_index_for_edge()
self.graph._create_relation_indexes.assert_any_call("relation1", [], [])
self.graph._create_relation_indexes.assert_any_call("relation2", [], [])
self.assertEqual(self.graph._create_relation_indexes.call_count, 2)
def test_create_index_for_node(self):
self.graph._get_node_index_definitions = MagicMock(return_value=[
("index1", "CREATE INDEX index1 ON Node(id);", False),
("index2", "CREATE INDEX index2 ON Node(properties);", True)
])
self.graph._create_single_node_index = MagicMock(return_value=True)
self.graph.create_index_for_node()
self.graph._create_single_node_index.assert_any_call("CREATE INDEX index1 ON Node(id);", False, "index1")
self.graph._create_single_node_index.assert_any_call("CREATE INDEX index2 ON Node(properties);", True, "index2")
self.assertEqual(self.graph._create_single_node_index.call_count, 2)
def test_reset(self):
mock_cursor = MagicMock()
mock_connection = MagicMock()
self.mock_adapter.get_cursor.return_value.__enter__.return_value = mock_cursor
self.mock_adapter.connection = mock_connection
self.graph.reset()
mock_cursor.execute.assert_any_call("SELECT * FROM ag_catalog.drop_graph(%s, true)", ('test_graph',))
self.assertEqual(mock_connection.commit.call_count, 1)
self.assertEqual(mock_cursor.execute.call_count, 1)
def test_subgraph(self):
self.mock_adapter.execute_cypher_query.return_value = [
{'source': 'A', 'relation': 'KNOWS', 'target': 'B'},
{'source': 'B', 'relation': 'FRIENDS', 'target': 'C'}
]
result = self.graph.subgraph(['A', 'B'], depth=2)
self.mock_adapter.execute_cypher_query.assert_called_once()
self.assertEqual(result, [('A', 'KNOWS', 'B'), ('B', 'FRIENDS', 'C')])
def test_get_node_index_definitions(self):
index_definitions = self.graph._get_node_index_definitions()
self.assertEqual(len(index_definitions), 3)
self.assertEqual(index_definitions[0][0], "index_graph_node_id")
self.assertIn("CREATE INDEX IF NOT EXISTS", index_definitions[0][1])
self.assertFalse(index_definitions[0][2])
def test_create_single_node_index_success(self):
self.mock_adapter.connection = MagicMock()
self.graph._execute_regular_index = MagicMock()
self.graph._execute_concurrent_index = MagicMock()
result = self.graph._create_single_node_index("CREATE INDEX", False, "index_name")
self.assertTrue(result)
self.graph._execute_regular_index.assert_called_once_with("CREATE INDEX")
def test_create_single_node_index_failure(self):
self.mock_adapter.connection = MagicMock()
self.graph._execute_regular_index = MagicMock(side_effect=Exception("Error"))
self.graph._execute_concurrent_index = MagicMock()
result = self.graph._create_single_node_index("CREATE INDEX", False, "index_name")
self.assertFalse(result)
def test_create_single_node_index_syntax_error(self):
self.mock_adapter.connection = MagicMock()
self.graph._execute_regular_index = MagicMock(side_effect=SyntaxError("Syntax Error"))
self.graph._execute_concurrent_index = MagicMock()
result = self.graph._create_single_node_index("CREATE INDEX", False, "index_name")
self.assertFalse(result)
def test_create_single_node_index_value_error(self):
self.mock_adapter.connection = MagicMock()
self.graph._execute_regular_index = MagicMock(side_effect=ValueError("Value Error"))
self.graph._execute_concurrent_index = MagicMock()
result = self.graph._create_single_node_index("CREATE INDEX", False, "index_name")
self.assertFalse(result)
def test_execute_concurrent_index(self):
mock_conn = MagicMock()
self.mock_adapter.connection = mock_conn
mock_cursor = MagicMock()
mock_conn.cursor.return_value.__enter__.return_value = mock_cursor
self.graph._execute_concurrent_index("CREATE INDEX")
mock_conn.cursor.assert_called_once()
mock_cursor.execute.assert_called_once_with("CREATE INDEX")
self.assertTrue(mock_conn.autocommit)
def test_execute_regular_index(self):
mock_cursor = MagicMock()
self.mock_adapter.get_cursor.return_value.__enter__.return_value = mock_cursor
self.graph._execute_regular_index("CREATE INDEX")
mock_cursor.execute.assert_called_once_with("CREATE INDEX")
self.mock_adapter.connection.commit.assert_called_once()
def test_execute_regular_index_syntax_error(self):
mock_cursor = MagicMock()
mock_cursor.execute.side_effect = SyntaxError("Syntax Error")
self.mock_adapter.get_cursor.return_value.__enter__.return_value = mock_cursor
with self.assertRaises(SyntaxError):
self.graph._execute_regular_index("CREATE INDEX")
mock_cursor.execute.assert_called_once_with("CREATE INDEX")
self.mock_adapter.connection.rollback.assert_called_once()
self.mock_adapter.connection.commit.assert_not_called()
def test_execute_regular_index_connection_error(self):
self.mock_adapter.get_cursor.side_effect = ConnectionError("Connection Error")
with self.assertRaises(ConnectionError):
self.graph._execute_regular_index("CREATE INDEX")
self.mock_adapter.connection.rollback.assert_called_once()
self.mock_adapter.connection.commit.assert_not_called()
def test_execute_regular_index_general_exception(self):
mock_cursor = MagicMock()
mock_cursor.execute.side_effect = Exception("General Error")
self.mock_adapter.get_cursor.return_value.__enter__.return_value = mock_cursor
with self.assertRaises(Exception):
self.graph._execute_regular_index("CREATE INDEX")
mock_cursor.execute.assert_called_once_with("CREATE INDEX")
self.mock_adapter.connection.rollback.assert_called_once()
self.mock_adapter.connection.commit.assert_not_called()
def test_generate_safe_index_prefix(self):
prefix = self.graph._generate_safe_index_prefix("relation-name")
self.assertTrue(prefix.startswith("relation_name_"))
self.assertEqual(len(prefix.split("_")[-1]), 8)
def test_build_index_queries(self):
queries = self.graph._build_index_queries("relation", "prefix")
self.assertEqual(len(queries), 2)
self.assertIn("CREATE INDEX IF NOT EXISTS index_prefix_start", queries[0])
self.assertIn("CREATE INDEX IF NOT EXISTS index_prefix_end", queries[1])
def test_create_relation_indexes_success(self):
self.graph._execute_index_queries = MagicMock()
successful_indexes = []
failed_relations = []
result = self.graph._create_relation_indexes("relation", successful_indexes, failed_relations)
self.assertTrue(result)
self.assertEqual(len(successful_indexes), 2)
self.assertEqual(len(failed_relations), 0)
def test_create_relation_indexes_value_error(self):
self.graph._execute_index_queries = MagicMock(side_effect=ValueError("Invalid value"))
successful_indexes = []
failed_relations = []
result = self.graph._create_relation_indexes("relation", successful_indexes, failed_relations)
self.assertFalse(result)
self.assertEqual(len(successful_indexes), 0)
self.assertEqual(len(failed_relations), 1)
def test_create_relation_indexes_attribute_error(self):
self.graph._execute_index_queries = MagicMock(side_effect=AttributeError("Attribute not found"))
successful_indexes = []
failed_relations = []
result = self.graph._create_relation_indexes("relation", successful_indexes, failed_relations)
self.assertFalse(result)
self.assertEqual(len(successful_indexes), 0)
self.assertEqual(len(failed_relations), 1)
def test_create_relation_indexes_failure(self):
self.graph._execute_index_queries = MagicMock(side_effect=Exception("Error"))
successful_indexes = []
failed_relations = []
result = self.graph._create_relation_indexes("relation", successful_indexes, failed_relations)
self.assertFalse(result)
self.assertEqual(len(successful_indexes), 0)
self.assertEqual(len(failed_relations), 1)
def test_execute_index_queries(self):
mock_cursor = MagicMock()
self.mock_adapter.get_cursor.return_value.__enter__.return_value = mock_cursor
self.graph._execute_index_queries(["QUERY1", "QUERY2"])
mock_cursor.execute.assert_has_calls([call("QUERY1"), call("QUERY2")])
self.mock_adapter.connection.commit.assert_called_once()
def test_find_weakly_connected_components(self):
self.graph.get_nodes = MagicMock(return_value=["node1", "node2"])
self.mock_adapter.execute_cypher_query.side_effect = [
[{"label": "node2"}],
[]
]
components = self.graph._find_weakly_connected_components()
self.assertEqual(len(components), 1)
self.assertIn("node1", components[0])
self.assertIn("node2", components[0])
def test_find_strongly_connected_components(self):
self.graph.get_nodes = MagicMock(return_value=["node1", "node2"])
self.graph.get_edges = MagicMock(return_value=[("node1", "node2"), ("node2", "node1")])
components = self.graph._find_strongly_connected_components()
self.assertEqual(len(components), 1)
self.assertIn("node1", components[0])
self.assertIn("node2", components[0])
if __name__ == "__main__":
unittest.main()