Fix tests broken by the recent RabbitMQ/Cassandra async fixes (#815)

- Fix invalid key in config causing rogue warning
- Fix asyncio test tags
This commit is contained in:
cybermaggedon 2026-04-16 10:00:18 +01:00 committed by GitHub
parent fdb52a6bfc
commit 22096e07e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 76 additions and 43 deletions

View file

@ -18,6 +18,20 @@ from trustgraph.schema import ExtractedObject, Metadata, RowSchema, Field
class TestRowsCassandraIntegration: class TestRowsCassandraIntegration:
"""Integration tests for Cassandra row storage with unified table""" """Integration tests for Cassandra row storage with unified table"""
@pytest.fixture(autouse=True)
def patch_async_execute(self):
"""Route async_execute through session.execute so the mock's
side_effect handles all CQL (DDL and DML) uniformly and every
call lands in mock_session.execute.call_args_list."""
async def _fake(session, query, params=None):
session.execute(query, params)
return []
with patch(
'trustgraph.storage.rows.cassandra.write.async_execute',
new=_fake,
):
yield
@pytest.fixture @pytest.fixture
def mock_cassandra_session(self): def mock_cassandra_session(self):
"""Mock Cassandra session for integration tests""" """Mock Cassandra session for integration tests"""

View file

@ -1,6 +1,5 @@
[pytest] [pytest]
testpaths = tests testpaths = tests
python_paths = .
python_files = test_*.py python_files = test_*.py
python_classes = Test* python_classes = Test*
python_functions = test_* python_functions = test_*
@ -8,7 +7,7 @@ addopts =
-v -v
--tb=short --tb=short
--strict-markers --strict-markers
--disable-warnings # --disable-warnings
# --cov-fail-under=80 # --cov-fail-under=80
asyncio_mode = auto asyncio_mode = auto
markers = markers =

View file

@ -9,6 +9,7 @@ tool usage patterns.
import pytest import pytest
from unittest.mock import Mock, AsyncMock from unittest.mock import Mock, AsyncMock
import asyncio import asyncio
import inspect
from collections import defaultdict from collections import defaultdict
@ -133,7 +134,7 @@ class TestToolCoordinationLogic:
resolved_params[key] = value resolved_params[key] = value
# Execute tool # Execute tool
if asyncio.iscoroutinefunction(tool_function): if inspect.iscoroutinefunction(tool_function):
result = await tool_function(**resolved_params) result = await tool_function(**resolved_params)
else: else:
result = tool_function(**resolved_params) result = tool_function(**resolved_params)
@ -227,7 +228,7 @@ class TestToolCoordinationLogic:
# Simulate async execution with delay # Simulate async execution with delay
await asyncio.sleep(0.001) # Small delay to simulate work await asyncio.sleep(0.001) # Small delay to simulate work
if asyncio.iscoroutinefunction(tool_function): if inspect.iscoroutinefunction(tool_function):
result = await tool_function(**parameters) result = await tool_function(**parameters)
else: else:
result = tool_function(**parameters) result = tool_function(**parameters)
@ -337,7 +338,7 @@ class TestToolCoordinationLogic:
if attempt > 0: if attempt > 0:
await asyncio.sleep(0.001 * (self.backoff_factor ** attempt)) await asyncio.sleep(0.001 * (self.backoff_factor ** attempt))
if asyncio.iscoroutinefunction(tool_function): if inspect.iscoroutinefunction(tool_function):
result = await tool_function(**parameters) result = await tool_function(**parameters)
else: else:
result = tool_function(**parameters) result = tool_function(**parameters)

View file

@ -45,7 +45,7 @@ def test_setup_logging_without_loki_configures_console(monkeypatch):
kwargs = basic_config.call_args.kwargs kwargs = basic_config.call_args.kwargs
assert kwargs["level"] == logging.DEBUG assert kwargs["level"] == logging.DEBUG
assert kwargs["force"] is True assert kwargs["force"] is True
assert "processor-1" in kwargs["format"] assert "%(processor_id)s" in kwargs["format"]
assert len(kwargs["handlers"]) == 1 assert len(kwargs["handlers"]) == 1
logger.info.assert_called_once_with("Logging configured with level: debug") logger.info.assert_called_once_with("Logging configured with level: debug")
@ -60,11 +60,14 @@ def test_setup_logging_with_loki_enables_queue_listener(monkeypatch):
queue_listener = MagicMock() queue_listener = MagicMock()
loki_handler = MagicMock() loki_handler = MagicMock()
noisy_logger = MagicMock()
logger_map = { logger_map = {
None: root_logger, None: root_logger,
"trustgraph.base.logging": module_logger, "trustgraph.base.logging": module_logger,
"urllib3": urllib3_logger, "urllib3": urllib3_logger,
"urllib3.connectionpool": connectionpool_logger, "urllib3.connectionpool": connectionpool_logger,
"pika": noisy_logger,
"cassandra": noisy_logger,
} }
monkeypatch.setattr(logging, "basicConfig", basic_config) monkeypatch.setattr(logging, "basicConfig", basic_config)

View file

@ -330,7 +330,8 @@ class TestUnifiedTableQueries:
"""Test queries against the unified rows table""" """Test queries against the unified rows table"""
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_query_with_index_match(self): @patch('trustgraph.query.rows.cassandra.service.async_execute', new_callable=AsyncMock)
async def test_query_with_index_match(self, mock_async_execute):
"""Test query execution with matching index""" """Test query execution with matching index"""
processor = MagicMock() processor = MagicMock()
processor.session = MagicMock() processor.session = MagicMock()
@ -340,10 +341,10 @@ class TestUnifiedTableQueries:
processor.find_matching_index = Processor.find_matching_index.__get__(processor, Processor) processor.find_matching_index = Processor.find_matching_index.__get__(processor, Processor)
processor.query_cassandra = Processor.query_cassandra.__get__(processor, Processor) processor.query_cassandra = Processor.query_cassandra.__get__(processor, Processor)
# Mock session execute to return test data # Mock async_execute to return test data
mock_row = MagicMock() mock_row = MagicMock()
mock_row.data = {"id": "123", "name": "Test Product", "category": "electronics"} mock_row.data = {"id": "123", "name": "Test Product", "category": "electronics"}
processor.session.execute.return_value = [mock_row] mock_async_execute.return_value = [mock_row]
schema = RowSchema( schema = RowSchema(
name="products", name="products",
@ -366,12 +367,12 @@ class TestUnifiedTableQueries:
# Verify Cassandra was connected and queried # Verify Cassandra was connected and queried
processor.connect_cassandra.assert_called_once() processor.connect_cassandra.assert_called_once()
processor.session.execute.assert_called_once() mock_async_execute.assert_called_once()
# Verify query structure - should query unified rows table # Verify query structure - should query unified rows table
call_args = processor.session.execute.call_args call_args = mock_async_execute.call_args
query = call_args[0][0] query = call_args[0][1]
params = call_args[0][1] params = call_args[0][2]
assert "SELECT data, source FROM test_user.rows" in query assert "SELECT data, source FROM test_user.rows" in query
assert "collection = %s" in query assert "collection = %s" in query
@ -390,7 +391,8 @@ class TestUnifiedTableQueries:
assert results[0]["category"] == "electronics" assert results[0]["category"] == "electronics"
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_query_without_index_match(self): @patch('trustgraph.query.rows.cassandra.service.async_execute', new_callable=AsyncMock)
async def test_query_without_index_match(self, mock_async_execute):
"""Test query execution without matching index (scan mode)""" """Test query execution without matching index (scan mode)"""
processor = MagicMock() processor = MagicMock()
processor.session = MagicMock() processor.session = MagicMock()
@ -401,12 +403,12 @@ class TestUnifiedTableQueries:
processor._matches_filters = Processor._matches_filters.__get__(processor, Processor) processor._matches_filters = Processor._matches_filters.__get__(processor, Processor)
processor.query_cassandra = Processor.query_cassandra.__get__(processor, Processor) processor.query_cassandra = Processor.query_cassandra.__get__(processor, Processor)
# Mock session execute to return test data # Mock async_execute to return test data
mock_row1 = MagicMock() mock_row1 = MagicMock()
mock_row1.data = {"id": "1", "name": "Product A", "price": "100"} mock_row1.data = {"id": "1", "name": "Product A", "price": "100"}
mock_row2 = MagicMock() mock_row2 = MagicMock()
mock_row2.data = {"id": "2", "name": "Product B", "price": "200"} mock_row2.data = {"id": "2", "name": "Product B", "price": "200"}
processor.session.execute.return_value = [mock_row1, mock_row2] mock_async_execute.return_value = [mock_row1, mock_row2]
schema = RowSchema( schema = RowSchema(
name="products", name="products",
@ -428,8 +430,8 @@ class TestUnifiedTableQueries:
) )
# Query should use ALLOW FILTERING for scan # Query should use ALLOW FILTERING for scan
call_args = processor.session.execute.call_args call_args = mock_async_execute.call_args
query = call_args[0][0] query = call_args[0][1]
assert "ALLOW FILTERING" in query assert "ALLOW FILTERING" in query

View file

@ -72,7 +72,6 @@ def processor(mock_pulsar_client, sample_schemas):
return proc return proc
@pytest.mark.asyncio
class TestNLPQueryProcessor: class TestNLPQueryProcessor:
"""Test NLP Query service processor""" """Test NLP Query service processor"""

View file

@ -36,7 +36,6 @@ def processor(mock_pulsar_client):
return proc return proc
@pytest.mark.asyncio
class TestStructuredQueryProcessor: class TestStructuredQueryProcessor:
"""Test Structured Query service processor""" """Test Structured Query service processor"""

View file

@ -160,7 +160,8 @@ class TestRowsCassandraStorageLogic:
assert id_field.primary is True assert id_field.primary is True
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_object_processing_stores_data_map(self): @patch('trustgraph.storage.rows.cassandra.write.async_execute', new_callable=AsyncMock)
async def test_object_processing_stores_data_map(self, mock_async_execute):
"""Test that row processing stores data as map<text, text>""" """Test that row processing stores data as map<text, text>"""
processor = MagicMock() processor = MagicMock()
processor.schemas = { processor.schemas = {
@ -184,6 +185,8 @@ class TestRowsCassandraStorageLogic:
processor.collection_exists = MagicMock(return_value=True) processor.collection_exists = MagicMock(return_value=True)
processor.on_object = Processor.on_object.__get__(processor, Processor) processor.on_object = Processor.on_object.__get__(processor, Processor)
mock_async_execute.return_value = []
# Create test object # Create test object
test_obj = ExtractedObject( test_obj = ExtractedObject(
metadata=Metadata( metadata=Metadata(
@ -205,10 +208,10 @@ class TestRowsCassandraStorageLogic:
await processor.on_object(msg, None, None) await processor.on_object(msg, None, None)
# Verify insert was executed # Verify insert was executed
processor.session.execute.assert_called() mock_async_execute.assert_called()
insert_call = processor.session.execute.call_args insert_call = mock_async_execute.call_args
insert_cql = insert_call[0][0] insert_cql = insert_call[0][1]
values = insert_call[0][1] values = insert_call[0][2]
# Verify using unified rows table # Verify using unified rows table
assert "INSERT INTO test_user.rows" in insert_cql assert "INSERT INTO test_user.rows" in insert_cql
@ -222,7 +225,8 @@ class TestRowsCassandraStorageLogic:
assert values[5] == "" # source assert values[5] == "" # source
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_object_processing_multiple_indexes(self): @patch('trustgraph.storage.rows.cassandra.write.async_execute', new_callable=AsyncMock)
async def test_object_processing_multiple_indexes(self, mock_async_execute):
"""Test that row is written once per indexed field""" """Test that row is written once per indexed field"""
processor = MagicMock() processor = MagicMock()
processor.schemas = { processor.schemas = {
@ -246,6 +250,8 @@ class TestRowsCassandraStorageLogic:
processor.collection_exists = MagicMock(return_value=True) processor.collection_exists = MagicMock(return_value=True)
processor.on_object = Processor.on_object.__get__(processor, Processor) processor.on_object = Processor.on_object.__get__(processor, Processor)
mock_async_execute.return_value = []
test_obj = ExtractedObject( test_obj = ExtractedObject(
metadata=Metadata( metadata=Metadata(
id="test-001", id="test-001",
@ -264,12 +270,12 @@ class TestRowsCassandraStorageLogic:
await processor.on_object(msg, None, None) await processor.on_object(msg, None, None)
# Should have 3 inserts (one per indexed field: id, category, status) # Should have 3 inserts (one per indexed field: id, category, status)
assert processor.session.execute.call_count == 3 assert mock_async_execute.call_count == 3
# Check that different index_names were used # Check that different index_names were used
index_names_used = set() index_names_used = set()
for call in processor.session.execute.call_args_list: for call in mock_async_execute.call_args_list:
values = call[0][1] values = call[0][2]
index_names_used.add(values[2]) # index_name is 3rd value index_names_used.add(values[2]) # index_name is 3rd value
assert index_names_used == {"id", "category", "status"} assert index_names_used == {"id", "category", "status"}
@ -279,7 +285,8 @@ class TestRowsCassandraStorageBatchLogic:
"""Test batch processing logic for unified table implementation""" """Test batch processing logic for unified table implementation"""
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_batch_object_processing(self): @patch('trustgraph.storage.rows.cassandra.write.async_execute', new_callable=AsyncMock)
async def test_batch_object_processing(self, mock_async_execute):
"""Test processing of batch ExtractedObjects""" """Test processing of batch ExtractedObjects"""
processor = MagicMock() processor = MagicMock()
processor.schemas = { processor.schemas = {
@ -302,6 +309,8 @@ class TestRowsCassandraStorageBatchLogic:
processor.collection_exists = MagicMock(return_value=True) processor.collection_exists = MagicMock(return_value=True)
processor.on_object = Processor.on_object.__get__(processor, Processor) processor.on_object = Processor.on_object.__get__(processor, Processor)
mock_async_execute.return_value = []
# Create batch object with multiple values # Create batch object with multiple values
batch_obj = ExtractedObject( batch_obj = ExtractedObject(
metadata=Metadata( metadata=Metadata(
@ -325,12 +334,12 @@ class TestRowsCassandraStorageBatchLogic:
await processor.on_object(msg, None, None) await processor.on_object(msg, None, None)
# Should have 3 inserts (one per row, one index per row since only primary key) # Should have 3 inserts (one per row, one index per row since only primary key)
assert processor.session.execute.call_count == 3 assert mock_async_execute.call_count == 3
# Check each insert has different id # Check each insert has different id
ids_inserted = set() ids_inserted = set()
for call in processor.session.execute.call_args_list: for call in mock_async_execute.call_args_list:
values = call[0][1] values = call[0][2]
ids_inserted.add(tuple(values[3])) # index_value is 4th value ids_inserted.add(tuple(values[3])) # index_value is 4th value
assert ids_inserted == {("001",), ("002",), ("003",)} assert ids_inserted == {("001",), ("002",), ("003",)}

View file

@ -9,7 +9,7 @@ with hand-built fake rows.
""" """
import pytest import pytest
from unittest.mock import Mock from unittest.mock import Mock, AsyncMock, patch
from trustgraph.tables.knowledge import KnowledgeTableStore from trustgraph.tables.knowledge import KnowledgeTableStore
from trustgraph.schema import ( from trustgraph.schema import (
@ -35,7 +35,10 @@ def _make_store():
class TestGetGraphEmbeddings: class TestGetGraphEmbeddings:
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_row_converts_to_entity_embeddings_with_singular_vector(self): @patch('trustgraph.tables.knowledge.async_execute', new_callable=AsyncMock)
async def test_row_converts_to_entity_embeddings_with_singular_vector(
self, mock_async_execute
):
""" """
Cassandra rows return entities as a list of [entity_tuple, vector] Cassandra rows return entities as a list of [entity_tuple, vector]
pairs in row[3]. The deserializer must construct EntityEmbeddings pairs in row[3]. The deserializer must construct EntityEmbeddings
@ -56,8 +59,8 @@ class TestGetGraphEmbeddings:
store = _make_store() store = _make_store()
store.cassandra = Mock() store.cassandra = Mock()
store.cassandra.execute = Mock(return_value=[fake_row])
store.get_graph_embeddings_stmt = Mock() store.get_graph_embeddings_stmt = Mock()
mock_async_execute.return_value = [fake_row]
received = [] received = []
@ -72,7 +75,8 @@ class TestGetGraphEmbeddings:
) )
# Assert # Assert
store.cassandra.execute.assert_called_once_with( mock_async_execute.assert_called_once_with(
store.cassandra,
store.get_graph_embeddings_stmt, store.get_graph_embeddings_stmt,
("alice", "doc-1"), ("alice", "doc-1"),
) )
@ -102,15 +106,16 @@ class TestGetGraphEmbeddings:
assert ge.entities[2].entity.value == "a literal entity" assert ge.entities[2].entity.value == "a literal entity"
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_empty_entities_blob_yields_empty_list(self): @patch('trustgraph.tables.knowledge.async_execute', new_callable=AsyncMock)
async def test_empty_entities_blob_yields_empty_list(self, mock_async_execute):
"""row[3] being None / empty must produce a GraphEmbeddings with """row[3] being None / empty must produce a GraphEmbeddings with
no entities, not raise.""" no entities, not raise."""
fake_row = (None, None, None, None) fake_row = (None, None, None, None)
store = _make_store() store = _make_store()
store.cassandra = Mock() store.cassandra = Mock()
store.cassandra.execute = Mock(return_value=[fake_row])
store.get_graph_embeddings_stmt = Mock() store.get_graph_embeddings_stmt = Mock()
mock_async_execute.return_value = [fake_row]
received = [] received = []
@ -123,7 +128,8 @@ class TestGetGraphEmbeddings:
assert received[0].entities == [] assert received[0].entities == []
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_multiple_rows_each_emit_one_message(self): @patch('trustgraph.tables.knowledge.async_execute', new_callable=AsyncMock)
async def test_multiple_rows_each_emit_one_message(self, mock_async_execute):
fake_rows = [ fake_rows = [
(None, None, None, [ (None, None, None, [
(("http://example.org/a", True), [1.0]), (("http://example.org/a", True), [1.0]),
@ -135,8 +141,8 @@ class TestGetGraphEmbeddings:
store = _make_store() store = _make_store()
store.cassandra = Mock() store.cassandra = Mock()
store.cassandra.execute = Mock(return_value=fake_rows)
store.get_graph_embeddings_stmt = Mock() store.get_graph_embeddings_stmt = Mock()
mock_async_execute.return_value = fake_rows
received = [] received = []
@ -157,7 +163,8 @@ class TestGetTriples:
the same Metadata construction. Cover it for parity.""" the same Metadata construction. Cover it for parity."""
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_row_converts_to_triples(self): @patch('trustgraph.tables.knowledge.async_execute', new_callable=AsyncMock)
async def test_row_converts_to_triples(self, mock_async_execute):
# row[3] is a list of (s_val, s_uri, p_val, p_uri, o_val, o_uri) # row[3] is a list of (s_val, s_uri, p_val, p_uri, o_val, o_uri)
fake_row = ( fake_row = (
None, None, None, None, None, None,
@ -172,8 +179,8 @@ class TestGetTriples:
store = _make_store() store = _make_store()
store.cassandra = Mock() store.cassandra = Mock()
store.cassandra.execute = Mock(return_value=[fake_row])
store.get_triples_stmt = Mock() store.get_triples_stmt = Mock()
mock_async_execute.return_value = [fake_row]
received = [] received = []