chore: restore original directory structure (project under code-review-graph-main/)
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
"""Tests for SQLite transaction robustness and nesting scenarios."""
|
||||
|
||||
import sqlite3
|
||||
import tempfile
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
from code_review_graph.graph import GraphStore
|
||||
from code_review_graph.parser import NodeInfo, EdgeInfo
|
||||
from code_review_graph.communities import store_communities
|
||||
from code_review_graph.flows import store_flows
|
||||
|
||||
@pytest.fixture
|
||||
def store():
|
||||
"""Create a temporary GraphStore for testing."""
|
||||
with tempfile.NamedTemporaryFile(suffix=".db", delete=False) as tmp:
|
||||
db_path = tmp.name
|
||||
store = GraphStore(db_path)
|
||||
yield store
|
||||
store.close()
|
||||
Path(db_path).unlink(missing_ok=True)
|
||||
|
||||
class TestTransactionRobustness:
|
||||
def test_nested_transaction_guard_in_store_file(self, store, caplog):
|
||||
"""Test that store_file_nodes_edges handles an already open transaction."""
|
||||
# Manually open a transaction
|
||||
store._conn.execute("BEGIN")
|
||||
store._conn.execute("INSERT INTO metadata (key, value) VALUES (?, ?)", ("test", "val"))
|
||||
assert store._conn.in_transaction
|
||||
|
||||
# This should trigger the guard, rollback the uncommitted insert, and start a new transaction
|
||||
with caplog.at_level(logging.WARNING):
|
||||
store.store_file_nodes_edges("test.py", [], [])
|
||||
|
||||
assert "Rolling back uncommitted transaction before BEGIN IMMEDIATE" in caplog.text
|
||||
assert not store._conn.in_transaction
|
||||
|
||||
# Verify the "val" was rolled back
|
||||
assert store.get_metadata("test") is None
|
||||
|
||||
def test_atomic_community_storage(self, store):
|
||||
"""Test that store_communities is atomic and handles existing transactions."""
|
||||
communities = [
|
||||
{"name": "comm1", "size": 1, "members": ["node1"]}
|
||||
]
|
||||
|
||||
# Leave a transaction open
|
||||
store._conn.execute("BEGIN")
|
||||
store._conn.execute("INSERT INTO metadata (key, value) VALUES ('leak', 'stale')")
|
||||
|
||||
# Should rollback the 'leak' and successfully store communities
|
||||
store_communities(store, communities)
|
||||
|
||||
assert store.get_metadata("leak") is None
|
||||
|
||||
# Verify communities table
|
||||
count = store._conn.execute("SELECT count(*) FROM communities").fetchone()[0]
|
||||
assert count == 1
|
||||
|
||||
def test_atomic_flow_storage(self, store):
|
||||
"""Test that store_flows is atomic and handles existing transactions."""
|
||||
flows = [
|
||||
{
|
||||
"name": "flow1", "entry_point_id": 1, "depth": 1,
|
||||
"node_count": 1, "file_count": 1, "criticality": 0.5,
|
||||
"path": [1]
|
||||
}
|
||||
]
|
||||
|
||||
# Leave a transaction open
|
||||
store._conn.execute("BEGIN")
|
||||
store._conn.execute("INSERT INTO metadata (key, value) VALUES ('leak', 'stale')")
|
||||
|
||||
# Should rollback and store flows
|
||||
store_flows(store, flows)
|
||||
|
||||
assert store.get_metadata("leak") is None
|
||||
count = store._conn.execute("SELECT count(*) FROM flows").fetchone()[0]
|
||||
assert count == 1
|
||||
|
||||
def test_rollback_on_failure_in_batch_ops(self, store):
|
||||
"""Verify that store_file_nodes_edges rolls back if an operation fails inside."""
|
||||
# Pre-seed some data
|
||||
node_keep = NodeInfo(
|
||||
kind="File", name="keep", file_path="keep.py",
|
||||
line_start=1, line_end=10, language="python"
|
||||
)
|
||||
store.store_file_nodes_edges("keep.py", [node_keep], [])
|
||||
|
||||
# Attempt to store new file but force a failure
|
||||
node_fail = NodeInfo(
|
||||
kind="File", name="fail", file_path="fail.py",
|
||||
line_start=1, line_end=10, language="python"
|
||||
)
|
||||
|
||||
with patch.object(store, 'upsert_node', side_effect=Exception("Simulated failure")):
|
||||
with pytest.raises(Exception, match="Simulated failure"):
|
||||
store.store_file_nodes_edges("fail.py", [node_fail], [])
|
||||
|
||||
# Verify 'fail.py' data is NOT present
|
||||
assert len(store.get_nodes_by_file("fail.py")) == 0
|
||||
# Verify 'keep.py' data IS still present
|
||||
assert len(store.get_nodes_by_file("keep.py")) == 1
|
||||
|
||||
def test_public_rollback_api(self, store):
|
||||
"""Verify the new GraphStore.rollback() public method works."""
|
||||
store._conn.execute("BEGIN")
|
||||
store._conn.execute("INSERT INTO metadata (key, value) VALUES ('rollback', 'me')")
|
||||
assert store._conn.in_transaction
|
||||
|
||||
store.rollback()
|
||||
assert not store._conn.in_transaction
|
||||
assert store.get_metadata("rollback") is None
|
||||
Reference in New Issue
Block a user