From a94ebe837728ff07363cb1adf6c444413d9ed29a Mon Sep 17 00:00:00 2001 From: Cyber MacGeddon Date: Tue, 30 Sep 2025 15:34:39 +0100 Subject: [PATCH] Fixing tests --- .../test_doc_embeddings_pinecone_storage.py | 60 ++++------- .../test_doc_embeddings_qdrant_storage.py | 102 ++++++++---------- .../test_graph_embeddings_pinecone_storage.py | 60 ++++------- .../test_graph_embeddings_qdrant_storage.py | 69 +++++------- ...test_memgraph_user_collection_isolation.py | 50 +++++---- .../test_neo4j_user_collection_isolation.py | 30 ++++-- .../test_objects_cassandra_storage.py | 13 +-- 7 files changed, 170 insertions(+), 214 deletions(-) diff --git a/tests/unit/test_storage/test_doc_embeddings_pinecone_storage.py b/tests/unit/test_storage/test_doc_embeddings_pinecone_storage.py index 113a75cb..848916f5 100644 --- a/tests/unit/test_storage/test_doc_embeddings_pinecone_storage.py +++ b/tests/unit/test_storage/test_doc_embeddings_pinecone_storage.py @@ -178,37 +178,24 @@ class TestPineconeDocEmbeddingsStorageProcessor: assert calls[2][1]['vectors'][0]['metadata']['doc'] == "This is the second document chunk" @pytest.mark.asyncio - async def test_store_document_embeddings_index_creation(self, processor): - """Test automatic index creation when index doesn't exist""" + async def test_store_document_embeddings_index_validation(self, processor): + """Test that writing to non-existent index raises ValueError""" message = MagicMock() message.metadata = MagicMock() message.metadata.user = 'test_user' message.metadata.collection = 'test_collection' - + chunk = ChunkEmbeddings( chunk=b"Test document content", vectors=[[0.1, 0.2, 0.3]] ) message.chunks = [chunk] - - # Mock index doesn't exist initially + + # Mock index doesn't exist processor.pinecone.has_index.return_value = False - mock_index = MagicMock() - processor.pinecone.Index.return_value = mock_index - - # Mock index creation - processor.pinecone.describe_index.return_value.status = {"ready": True} - - with patch('uuid.uuid4', return_value='test-id'): + + with pytest.raises(ValueError, match="Collection .* does not exist"): await processor.store_document_embeddings(message) - - # Verify index creation was called - expected_index_name = "d-test_user-test_collection" - processor.pinecone.create_index.assert_called_once() - create_call = processor.pinecone.create_index.call_args - assert create_call[1]['name'] == expected_index_name - assert create_call[1]['dimension'] == 3 - assert create_call[1]['metric'] == "cosine" @pytest.mark.asyncio async def test_store_document_embeddings_empty_chunk(self, processor): @@ -357,47 +344,44 @@ class TestPineconeDocEmbeddingsStorageProcessor: mock_index.upsert.assert_not_called() @pytest.mark.asyncio - async def test_store_document_embeddings_index_creation_failure(self, processor): - """Test handling of index creation failure""" + async def test_store_document_embeddings_validation_before_creation(self, processor): + """Test that validation error occurs before creation attempts""" message = MagicMock() message.metadata = MagicMock() message.metadata.user = 'test_user' message.metadata.collection = 'test_collection' - + chunk = ChunkEmbeddings( chunk=b"Test document content", vectors=[[0.1, 0.2, 0.3]] ) message.chunks = [chunk] - - # Mock index doesn't exist and creation fails + + # Mock index doesn't exist processor.pinecone.has_index.return_value = False - processor.pinecone.create_index.side_effect = Exception("Index creation failed") - - with pytest.raises(Exception, match="Index creation failed"): + + with pytest.raises(ValueError, match="Collection .* does not exist"): await processor.store_document_embeddings(message) @pytest.mark.asyncio - async def test_store_document_embeddings_index_creation_timeout(self, processor): - """Test handling of index creation timeout""" + async def test_store_document_embeddings_validates_before_timeout(self, processor): + """Test that validation error occurs before timeout checks""" message = MagicMock() message.metadata = MagicMock() message.metadata.user = 'test_user' message.metadata.collection = 'test_collection' - + chunk = ChunkEmbeddings( chunk=b"Test document content", vectors=[[0.1, 0.2, 0.3]] ) message.chunks = [chunk] - - # Mock index doesn't exist and never becomes ready + + # Mock index doesn't exist processor.pinecone.has_index.return_value = False - processor.pinecone.describe_index.return_value.status = {"ready": False} - - with patch('time.sleep'): # Speed up the test - with pytest.raises(RuntimeError, match="Gave up waiting for index creation"): - await processor.store_document_embeddings(message) + + with pytest.raises(ValueError, match="Collection .* does not exist"): + await processor.store_document_embeddings(message) @pytest.mark.asyncio async def test_store_document_embeddings_unicode_content(self, processor): diff --git a/tests/unit/test_storage/test_doc_embeddings_qdrant_storage.py b/tests/unit/test_storage/test_doc_embeddings_qdrant_storage.py index 021b5d96..ef00c3f9 100644 --- a/tests/unit/test_storage/test_doc_embeddings_qdrant_storage.py +++ b/tests/unit/test_storage/test_doc_embeddings_qdrant_storage.py @@ -43,8 +43,6 @@ class TestQdrantDocEmbeddingsStorage(IsolatedAsyncioTestCase): # Verify processor attributes assert hasattr(processor, 'qdrant') assert processor.qdrant == mock_qdrant_instance - assert hasattr(processor, 'last_collection') - assert processor.last_collection is None @patch('trustgraph.storage.doc_embeddings.qdrant.write.QdrantClient') @patch('trustgraph.base.DocumentEmbeddingsStoreService.__init__') @@ -245,8 +243,9 @@ class TestQdrantDocEmbeddingsStorage(IsolatedAsyncioTestCase): # Arrange mock_base_init.return_value = None mock_qdrant_instance = MagicMock() + mock_qdrant_instance.collection_exists.return_value = True # Collection exists mock_qdrant_client.return_value = mock_qdrant_instance - + config = { 'store_uri': 'http://localhost:6333', 'api_key': 'test-api-key', @@ -255,36 +254,37 @@ class TestQdrantDocEmbeddingsStorage(IsolatedAsyncioTestCase): } processor = Processor(**config) - + # Create mock message with empty chunk mock_message = MagicMock() mock_message.metadata.user = 'empty_user' mock_message.metadata.collection = 'empty_collection' - + mock_chunk_empty = MagicMock() mock_chunk_empty.chunk.decode.return_value = "" # Empty string mock_chunk_empty.vectors = [[0.1, 0.2]] - + mock_message.chunks = [mock_chunk_empty] - + # Act await processor.store_document_embeddings(mock_message) # Assert # Should not call upsert for empty chunks mock_qdrant_instance.upsert.assert_not_called() - mock_qdrant_instance.collection_exists.assert_not_called() + # But collection_exists should be called for validation + mock_qdrant_instance.collection_exists.assert_called_once() @patch('trustgraph.storage.doc_embeddings.qdrant.write.QdrantClient') @patch('trustgraph.base.DocumentEmbeddingsStoreService.__init__') async def test_collection_creation_when_not_exists(self, mock_base_init, mock_qdrant_client): - """Test collection creation when it doesn't exist""" + """Test that writing to non-existent collection raises ValueError""" # Arrange mock_base_init.return_value = None mock_qdrant_instance = MagicMock() mock_qdrant_instance.collection_exists.return_value = False # Collection doesn't exist mock_qdrant_client.return_value = mock_qdrant_instance - + config = { 'store_uri': 'http://localhost:6333', 'api_key': 'test-api-key', @@ -293,46 +293,32 @@ class TestQdrantDocEmbeddingsStorage(IsolatedAsyncioTestCase): } processor = Processor(**config) - + # Create mock message mock_message = MagicMock() mock_message.metadata.user = 'new_user' mock_message.metadata.collection = 'new_collection' - + mock_chunk = MagicMock() mock_chunk.chunk.decode.return_value = 'test chunk' mock_chunk.vectors = [[0.1, 0.2, 0.3, 0.4, 0.5]] # 5 dimensions - - mock_message.chunks = [mock_chunk] - - # Act - await processor.store_document_embeddings(mock_message) - # Assert - expected_collection = 'd_new_user_new_collection' - - # Verify collection existence check and creation - mock_qdrant_instance.collection_exists.assert_called_once_with(expected_collection) - mock_qdrant_instance.create_collection.assert_called_once() - - # Verify create_collection was called with correct parameters - create_call_args = mock_qdrant_instance.create_collection.call_args - assert create_call_args[1]['collection_name'] == expected_collection - - # Verify upsert was still called after collection creation - mock_qdrant_instance.upsert.assert_called_once() + mock_message.chunks = [mock_chunk] + + # Act & Assert + with pytest.raises(ValueError, match="Collection .* does not exist"): + await processor.store_document_embeddings(mock_message) @patch('trustgraph.storage.doc_embeddings.qdrant.write.QdrantClient') @patch('trustgraph.base.DocumentEmbeddingsStoreService.__init__') async def test_collection_creation_exception(self, mock_base_init, mock_qdrant_client): - """Test collection creation handles exceptions""" + """Test that validation error occurs before connection errors""" # Arrange mock_base_init.return_value = None mock_qdrant_instance = MagicMock() - mock_qdrant_instance.collection_exists.return_value = False - mock_qdrant_instance.create_collection.side_effect = Exception("Qdrant connection failed") + mock_qdrant_instance.collection_exists.return_value = False # Collection doesn't exist mock_qdrant_client.return_value = mock_qdrant_instance - + config = { 'store_uri': 'http://localhost:6333', 'api_key': 'test-api-key', @@ -341,32 +327,35 @@ class TestQdrantDocEmbeddingsStorage(IsolatedAsyncioTestCase): } processor = Processor(**config) - + # Create mock message mock_message = MagicMock() mock_message.metadata.user = 'error_user' mock_message.metadata.collection = 'error_collection' - + mock_chunk = MagicMock() mock_chunk.chunk.decode.return_value = 'test chunk' mock_chunk.vectors = [[0.1, 0.2]] - + mock_message.chunks = [mock_chunk] - + # Act & Assert - with pytest.raises(Exception, match="Qdrant connection failed"): + with pytest.raises(ValueError, match="Collection .* does not exist"): await processor.store_document_embeddings(mock_message) @patch('trustgraph.storage.doc_embeddings.qdrant.write.QdrantClient') @patch('trustgraph.base.DocumentEmbeddingsStoreService.__init__') - async def test_collection_caching_behavior(self, mock_base_init, mock_qdrant_client): - """Test collection caching with last_collection""" + @patch('trustgraph.storage.doc_embeddings.qdrant.write.uuid') + async def test_collection_validation_on_write(self, mock_uuid, mock_base_init, mock_qdrant_client): + """Test collection validation checks collection exists before writing""" # Arrange mock_base_init.return_value = None mock_qdrant_instance = MagicMock() mock_qdrant_instance.collection_exists.return_value = True mock_qdrant_client.return_value = mock_qdrant_instance - + mock_uuid.uuid4.return_value = MagicMock() + mock_uuid.uuid4.return_value.__str__ = MagicMock(return_value='test-uuid') + config = { 'store_uri': 'http://localhost:6333', 'api_key': 'test-api-key', @@ -375,46 +364,45 @@ class TestQdrantDocEmbeddingsStorage(IsolatedAsyncioTestCase): } processor = Processor(**config) - + # Create first mock message mock_message1 = MagicMock() mock_message1.metadata.user = 'cache_user' mock_message1.metadata.collection = 'cache_collection' - + mock_chunk1 = MagicMock() mock_chunk1.chunk.decode.return_value = 'first chunk' mock_chunk1.vectors = [[0.1, 0.2, 0.3]] - + mock_message1.chunks = [mock_chunk1] - + # First call await processor.store_document_embeddings(mock_message1) - + # Reset mock to track second call mock_qdrant_instance.reset_mock() - + mock_qdrant_instance.collection_exists.return_value = True + # Create second mock message with same dimensions mock_message2 = MagicMock() mock_message2.metadata.user = 'cache_user' mock_message2.metadata.collection = 'cache_collection' - + mock_chunk2 = MagicMock() mock_chunk2.chunk.decode.return_value = 'second chunk' mock_chunk2.vectors = [[0.4, 0.5, 0.6]] # Same dimension (3) - + mock_message2.chunks = [mock_chunk2] - + # Act - Second call with same collection await processor.store_document_embeddings(mock_message2) # Assert expected_collection = 'd_cache_user_cache_collection' - assert processor.last_collection == expected_collection - - # Verify second call skipped existence check (cached) - mock_qdrant_instance.collection_exists.assert_not_called() - mock_qdrant_instance.create_collection.assert_not_called() - + + # Verify collection existence is checked on each write + mock_qdrant_instance.collection_exists.assert_called_once_with(expected_collection) + # But upsert should still be called mock_qdrant_instance.upsert.assert_called_once() diff --git a/tests/unit/test_storage/test_graph_embeddings_pinecone_storage.py b/tests/unit/test_storage/test_graph_embeddings_pinecone_storage.py index cf83e2ed..854a03b2 100644 --- a/tests/unit/test_storage/test_graph_embeddings_pinecone_storage.py +++ b/tests/unit/test_storage/test_graph_embeddings_pinecone_storage.py @@ -178,37 +178,24 @@ class TestPineconeGraphEmbeddingsStorageProcessor: assert calls[2][1]['vectors'][0]['metadata']['entity'] == "entity2" @pytest.mark.asyncio - async def test_store_graph_embeddings_index_creation(self, processor): - """Test automatic index creation when index doesn't exist""" + async def test_store_graph_embeddings_index_validation(self, processor): + """Test that writing to non-existent index raises ValueError""" message = MagicMock() message.metadata = MagicMock() message.metadata.user = 'test_user' message.metadata.collection = 'test_collection' - + entity = EntityEmbeddings( entity=Value(value="test_entity", is_uri=False), vectors=[[0.1, 0.2, 0.3]] ) message.entities = [entity] - - # Mock index doesn't exist initially + + # Mock index doesn't exist processor.pinecone.has_index.return_value = False - mock_index = MagicMock() - processor.pinecone.Index.return_value = mock_index - - # Mock index creation - processor.pinecone.describe_index.return_value.status = {"ready": True} - - with patch('uuid.uuid4', return_value='test-id'): + + with pytest.raises(ValueError, match="Collection .* does not exist"): await processor.store_graph_embeddings(message) - - # Verify index creation was called - expected_index_name = "t-test_user-test_collection" - processor.pinecone.create_index.assert_called_once() - create_call = processor.pinecone.create_index.call_args - assert create_call[1]['name'] == expected_index_name - assert create_call[1]['dimension'] == 3 - assert create_call[1]['metric'] == "cosine" @pytest.mark.asyncio async def test_store_graph_embeddings_empty_entity_value(self, processor): @@ -328,47 +315,44 @@ class TestPineconeGraphEmbeddingsStorageProcessor: mock_index.upsert.assert_not_called() @pytest.mark.asyncio - async def test_store_graph_embeddings_index_creation_failure(self, processor): - """Test handling of index creation failure""" + async def test_store_graph_embeddings_validation_before_creation(self, processor): + """Test that validation error occurs before any creation attempts""" message = MagicMock() message.metadata = MagicMock() message.metadata.user = 'test_user' message.metadata.collection = 'test_collection' - + entity = EntityEmbeddings( entity=Value(value="test_entity", is_uri=False), vectors=[[0.1, 0.2, 0.3]] ) message.entities = [entity] - - # Mock index doesn't exist and creation fails + + # Mock index doesn't exist processor.pinecone.has_index.return_value = False - processor.pinecone.create_index.side_effect = Exception("Index creation failed") - - with pytest.raises(Exception, match="Index creation failed"): + + with pytest.raises(ValueError, match="Collection .* does not exist"): await processor.store_graph_embeddings(message) @pytest.mark.asyncio - async def test_store_graph_embeddings_index_creation_timeout(self, processor): - """Test handling of index creation timeout""" + async def test_store_graph_embeddings_validates_before_timeout(self, processor): + """Test that validation error occurs before timeout checks""" message = MagicMock() message.metadata = MagicMock() message.metadata.user = 'test_user' message.metadata.collection = 'test_collection' - + entity = EntityEmbeddings( entity=Value(value="test_entity", is_uri=False), vectors=[[0.1, 0.2, 0.3]] ) message.entities = [entity] - - # Mock index doesn't exist and never becomes ready + + # Mock index doesn't exist processor.pinecone.has_index.return_value = False - processor.pinecone.describe_index.return_value.status = {"ready": False} - - with patch('time.sleep'): # Speed up the test - with pytest.raises(RuntimeError, match="Gave up waiting for index creation"): - await processor.store_graph_embeddings(message) + + with pytest.raises(ValueError, match="Collection .* does not exist"): + await processor.store_graph_embeddings(message) def test_add_args_method(self): """Test that add_args properly configures argument parser""" diff --git a/tests/unit/test_storage/test_graph_embeddings_qdrant_storage.py b/tests/unit/test_storage/test_graph_embeddings_qdrant_storage.py index ee9fc0fc..4e7b492d 100644 --- a/tests/unit/test_storage/test_graph_embeddings_qdrant_storage.py +++ b/tests/unit/test_storage/test_graph_embeddings_qdrant_storage.py @@ -43,19 +43,17 @@ class TestQdrantGraphEmbeddingsStorage(IsolatedAsyncioTestCase): # Verify processor attributes assert hasattr(processor, 'qdrant') assert processor.qdrant == mock_qdrant_instance - assert hasattr(processor, 'last_collection') - assert processor.last_collection is None @patch('trustgraph.storage.graph_embeddings.qdrant.write.QdrantClient') @patch('trustgraph.base.GraphEmbeddingsStoreService.__init__') - async def test_get_collection_creates_new_collection(self, mock_base_init, mock_qdrant_client): - """Test get_collection creates a new collection when it doesn't exist""" + async def test_get_collection_validates_existence(self, mock_base_init, mock_qdrant_client): + """Test get_collection validates that collection exists""" # Arrange mock_base_init.return_value = None mock_qdrant_instance = MagicMock() mock_qdrant_instance.collection_exists.return_value = False mock_qdrant_client.return_value = mock_qdrant_instance - + config = { 'store_uri': 'http://localhost:6333', 'api_key': 'test-api-key', @@ -64,22 +62,10 @@ class TestQdrantGraphEmbeddingsStorage(IsolatedAsyncioTestCase): } processor = Processor(**config) - - # Act - collection_name = processor.get_collection(dim=512, user='test_user', collection='test_collection') - # Assert - expected_name = 't_test_user_test_collection' - assert collection_name == expected_name - assert processor.last_collection == expected_name - - # Verify collection existence check and creation - mock_qdrant_instance.collection_exists.assert_called_once_with(expected_name) - mock_qdrant_instance.create_collection.assert_called_once() - - # Verify create_collection was called with correct parameters - create_call_args = mock_qdrant_instance.create_collection.call_args - assert create_call_args[1]['collection_name'] == expected_name + # Act & Assert + with pytest.raises(ValueError, match="Collection .* does not exist"): + processor.get_collection(user='test_user', collection='test_collection') @patch('trustgraph.storage.graph_embeddings.qdrant.write.QdrantClient') @patch('trustgraph.storage.graph_embeddings.qdrant.write.uuid') @@ -142,7 +128,7 @@ class TestQdrantGraphEmbeddingsStorage(IsolatedAsyncioTestCase): mock_qdrant_instance = MagicMock() mock_qdrant_instance.collection_exists.return_value = True # Collection exists mock_qdrant_client.return_value = mock_qdrant_instance - + config = { 'store_uri': 'http://localhost:6333', 'api_key': 'test-api-key', @@ -151,15 +137,14 @@ class TestQdrantGraphEmbeddingsStorage(IsolatedAsyncioTestCase): } processor = Processor(**config) - + # Act - collection_name = processor.get_collection(dim=256, user='existing_user', collection='existing_collection') + collection_name = processor.get_collection(user='existing_user', collection='existing_collection') # Assert expected_name = 't_existing_user_existing_collection' assert collection_name == expected_name - assert processor.last_collection == expected_name - + # Verify collection existence check was performed mock_qdrant_instance.collection_exists.assert_called_once_with(expected_name) # Verify create_collection was NOT called @@ -167,14 +152,14 @@ class TestQdrantGraphEmbeddingsStorage(IsolatedAsyncioTestCase): @patch('trustgraph.storage.graph_embeddings.qdrant.write.QdrantClient') @patch('trustgraph.base.GraphEmbeddingsStoreService.__init__') - async def test_get_collection_caches_last_collection(self, mock_base_init, mock_qdrant_client): - """Test get_collection skips checks when using same collection""" + async def test_get_collection_validates_on_each_call(self, mock_base_init, mock_qdrant_client): + """Test get_collection validates collection existence on each call""" # Arrange mock_base_init.return_value = None mock_qdrant_instance = MagicMock() mock_qdrant_instance.collection_exists.return_value = True mock_qdrant_client.return_value = mock_qdrant_instance - + config = { 'store_uri': 'http://localhost:6333', 'api_key': 'test-api-key', @@ -183,36 +168,36 @@ class TestQdrantGraphEmbeddingsStorage(IsolatedAsyncioTestCase): } processor = Processor(**config) - + # First call - collection_name1 = processor.get_collection(dim=128, user='cache_user', collection='cache_collection') - + collection_name1 = processor.get_collection(user='cache_user', collection='cache_collection') + # Reset mock to track second call mock_qdrant_instance.reset_mock() - + mock_qdrant_instance.collection_exists.return_value = True + # Act - Second call with same parameters - collection_name2 = processor.get_collection(dim=128, user='cache_user', collection='cache_collection') + collection_name2 = processor.get_collection(user='cache_user', collection='cache_collection') # Assert expected_name = 't_cache_user_cache_collection' assert collection_name1 == expected_name assert collection_name2 == expected_name - - # Verify second call skipped existence check (cached) - mock_qdrant_instance.collection_exists.assert_not_called() + + # Verify collection existence check happens on each call + mock_qdrant_instance.collection_exists.assert_called_once_with(expected_name) mock_qdrant_instance.create_collection.assert_not_called() @patch('trustgraph.storage.graph_embeddings.qdrant.write.QdrantClient') @patch('trustgraph.base.GraphEmbeddingsStoreService.__init__') async def test_get_collection_creation_exception(self, mock_base_init, mock_qdrant_client): - """Test get_collection handles collection creation exceptions""" + """Test get_collection raises ValueError when collection doesn't exist""" # Arrange mock_base_init.return_value = None mock_qdrant_instance = MagicMock() mock_qdrant_instance.collection_exists.return_value = False - mock_qdrant_instance.create_collection.side_effect = Exception("Qdrant connection failed") mock_qdrant_client.return_value = mock_qdrant_instance - + config = { 'store_uri': 'http://localhost:6333', 'api_key': 'test-api-key', @@ -221,10 +206,10 @@ class TestQdrantGraphEmbeddingsStorage(IsolatedAsyncioTestCase): } processor = Processor(**config) - + # Act & Assert - with pytest.raises(Exception, match="Qdrant connection failed"): - processor.get_collection(dim=512, user='error_user', collection='error_collection') + with pytest.raises(ValueError, match="Collection .* does not exist"): + processor.get_collection(user='error_user', collection='error_collection') @patch('trustgraph.storage.graph_embeddings.qdrant.write.QdrantClient') @patch('trustgraph.storage.graph_embeddings.qdrant.write.uuid') diff --git a/tests/unit/test_storage/test_memgraph_user_collection_isolation.py b/tests/unit/test_storage/test_memgraph_user_collection_isolation.py index fdc7fb4e..9c330b77 100644 --- a/tests/unit/test_storage/test_memgraph_user_collection_isolation.py +++ b/tests/unit/test_storage/test_memgraph_user_collection_isolation.py @@ -47,7 +47,7 @@ class TestMemgraphUserCollectionIsolation: mock_graph_db.driver.return_value = mock_driver mock_session = MagicMock() mock_driver.session.return_value.__enter__.return_value = mock_session - + # Mock execute_query response mock_result = MagicMock() mock_summary = MagicMock() @@ -55,28 +55,30 @@ class TestMemgraphUserCollectionIsolation: mock_summary.result_available_after = 10 mock_result.summary = mock_summary mock_driver.execute_query.return_value = mock_result - + processor = Processor(taskgroup=MagicMock()) - + # Create mock triple with URI object triple = MagicMock() triple.s.value = "http://example.com/subject" triple.p.value = "http://example.com/predicate" triple.o.value = "http://example.com/object" triple.o.is_uri = True - + # Create mock message with metadata mock_message = MagicMock() mock_message.triples = [triple] mock_message.metadata.user = "test_user" mock_message.metadata.collection = "test_collection" - - await processor.store_triples(mock_message) - + + # Mock collection_exists to bypass validation in unit tests + with patch.object(processor, 'collection_exists', return_value=True): + await processor.store_triples(mock_message) + # Verify user/collection parameters were passed to all operations # Should have: create_node (subject), create_node (object), relate_node = 3 calls assert mock_driver.execute_query.call_count == 3 - + # Check that user and collection were included in all calls for call in mock_driver.execute_query.call_args_list: call_kwargs = call.kwargs if hasattr(call, 'kwargs') else call[1] @@ -93,7 +95,7 @@ class TestMemgraphUserCollectionIsolation: mock_graph_db.driver.return_value = mock_driver mock_session = MagicMock() mock_driver.session.return_value.__enter__.return_value = mock_session - + # Mock execute_query response mock_result = MagicMock() mock_summary = MagicMock() @@ -101,24 +103,26 @@ class TestMemgraphUserCollectionIsolation: mock_summary.result_available_after = 10 mock_result.summary = mock_summary mock_driver.execute_query.return_value = mock_result - + processor = Processor(taskgroup=MagicMock()) - + # Create mock triple triple = MagicMock() triple.s.value = "http://example.com/subject" triple.p.value = "http://example.com/predicate" triple.o.value = "literal_value" triple.o.is_uri = False - + # Create mock message without user/collection metadata mock_message = MagicMock() mock_message.triples = [triple] mock_message.metadata.user = None mock_message.metadata.collection = None - - await processor.store_triples(mock_message) - + + # Mock collection_exists to bypass validation in unit tests + with patch.object(processor, 'collection_exists', return_value=True): + await processor.store_triples(mock_message) + # Verify defaults were used for call in mock_driver.execute_query.call_args_list: call_kwargs = call.kwargs if hasattr(call, 'kwargs') else call[1] @@ -295,7 +299,7 @@ class TestMemgraphUserCollectionRegression: mock_graph_db.driver.return_value = mock_driver mock_session = MagicMock() mock_driver.session.return_value.__enter__.return_value = mock_session - + # Mock execute_query response mock_result = MagicMock() mock_summary = MagicMock() @@ -303,23 +307,25 @@ class TestMemgraphUserCollectionRegression: mock_summary.result_available_after = 10 mock_result.summary = mock_summary mock_driver.execute_query.return_value = mock_result - + processor = Processor(taskgroup=MagicMock()) - + # Store data for user1 triple = MagicMock() triple.s.value = "http://example.com/subject" triple.p.value = "http://example.com/predicate" triple.o.value = "user1_data" triple.o.is_uri = False - + message_user1 = MagicMock() message_user1.triples = [triple] message_user1.metadata.user = "user1" message_user1.metadata.collection = "collection1" - - await processor.store_triples(message_user1) - + + # Mock collection_exists to bypass validation in unit tests + with patch.object(processor, 'collection_exists', return_value=True): + await processor.store_triples(message_user1) + # Verify that all storage operations included user1/collection1 parameters for call in mock_driver.execute_query.call_args_list: call_kwargs = call.kwargs if hasattr(call, 'kwargs') else call[1] diff --git a/tests/unit/test_storage/test_neo4j_user_collection_isolation.py b/tests/unit/test_storage/test_neo4j_user_collection_isolation.py index b3d5c79a..bc8bb03f 100644 --- a/tests/unit/test_storage/test_neo4j_user_collection_isolation.py +++ b/tests/unit/test_storage/test_neo4j_user_collection_isolation.py @@ -75,8 +75,10 @@ class TestNeo4jUserCollectionIsolation: mock_summary.counters.nodes_created = 1 mock_summary.result_available_after = 10 mock_driver.execute_query.return_value.summary = mock_summary - - await processor.store_triples(message) + + # Mock collection_exists to bypass validation in unit tests + with patch.object(processor, 'collection_exists', return_value=True): + await processor.store_triples(message) # Verify nodes and relationships were created with user/collection properties expected_calls = [ @@ -141,8 +143,10 @@ class TestNeo4jUserCollectionIsolation: mock_summary.counters.nodes_created = 1 mock_summary.result_available_after = 10 mock_driver.execute_query.return_value.summary = mock_summary - - await processor.store_triples(message) + + # Mock collection_exists to bypass validation in unit tests + with patch.object(processor, 'collection_exists', return_value=True): + await processor.store_triples(message) # Verify defaults were used mock_driver.execute_query.assert_any_call( @@ -273,10 +277,12 @@ class TestNeo4jUserCollectionIsolation: mock_summary.counters.nodes_created = 1 mock_summary.result_available_after = 10 mock_driver.execute_query.return_value.summary = mock_summary - - # Store data for both users - await processor.store_triples(message_user1) - await processor.store_triples(message_user2) + + # Mock collection_exists to bypass validation in unit tests + with patch.object(processor, 'collection_exists', return_value=True): + # Store data for both users + await processor.store_triples(message_user1) + await processor.store_triples(message_user2) # Verify user1 data was stored with user1/coll1 mock_driver.execute_query.assert_any_call( @@ -446,9 +452,11 @@ class TestNeo4jUserCollectionRegression: mock_summary.counters.nodes_created = 1 mock_summary.result_available_after = 10 mock_driver.execute_query.return_value.summary = mock_summary - - await processor.store_triples(message_user1) - await processor.store_triples(message_user2) + + # Mock collection_exists to bypass validation in unit tests + with patch.object(processor, 'collection_exists', return_value=True): + await processor.store_triples(message_user1) + await processor.store_triples(message_user2) # Verify two separate nodes were created with same URI but different user/collection user1_node_call = call( diff --git a/tests/unit/test_storage/test_objects_cassandra_storage.py b/tests/unit/test_storage/test_objects_cassandra_storage.py index 072c2a86..48812955 100644 --- a/tests/unit/test_storage/test_objects_cassandra_storage.py +++ b/tests/unit/test_storage/test_objects_cassandra_storage.py @@ -293,18 +293,19 @@ class TestObjectsCassandraStorageLogic: """Test that secondary indexes are created for indexed fields""" processor = MagicMock() processor.schemas = {} - processor.known_keyspaces = set() - processor.known_tables = {} + processor.known_keyspaces = {"test_user"} # Pre-populate to skip validation query + processor.known_tables = {"test_user": set()} # Pre-populate processor.session = MagicMock() processor.sanitize_name = Processor.sanitize_name.__get__(processor, Processor) processor.sanitize_table = Processor.sanitize_table.__get__(processor, Processor) processor.get_cassandra_type = Processor.get_cassandra_type.__get__(processor, Processor) def mock_ensure_keyspace(keyspace): processor.known_keyspaces.add(keyspace) - processor.known_tables[keyspace] = set() + if keyspace not in processor.known_tables: + processor.known_tables[keyspace] = set() processor.ensure_keyspace = mock_ensure_keyspace processor.ensure_table = Processor.ensure_table.__get__(processor, Processor) - + # Create schema with indexed field schema = RowSchema( name="products", @@ -315,10 +316,10 @@ class TestObjectsCassandraStorageLogic: Field(name="price", type="float", size=8, indexed=True) ] ) - + # Call ensure_table processor.ensure_table("test_user", "products", schema) - + # Should have 3 calls: create table + 2 indexes assert processor.session.execute.call_count == 3