Skip to content

Commit cbb212a

Browse files
authored
test: Qdrant - add more unit tests (#3221)
1 parent 3d6fa1f commit cbb212a

4 files changed

Lines changed: 103 additions & 0 deletions

File tree

integrations/qdrant/tests/test_converters.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
from types import SimpleNamespace
2+
13
import numpy as np
4+
import pytest
25
from haystack.dataclasses import Document, SparseEmbedding
36
from qdrant_client.http import models as rest
47

@@ -124,3 +127,18 @@ def test_convert_haystack_documents_to_qdrant_points_with_sparse_no_vectors():
124127
doc = Document(content="hello")
125128
points = convert_haystack_documents_to_qdrant_points([doc], use_sparse_embeddings=True)
126129
assert points[0].vector == {}
130+
131+
132+
@pytest.mark.parametrize(
133+
"vector",
134+
[
135+
{DENSE_VECTORS_NAME: [0.1, 0.2]},
136+
{DENSE_VECTORS_NAME: [0.1, 0.2], SPARSE_VECTORS_NAME: {"indices": [0], "values": [0.5]}},
137+
],
138+
ids=["no_sparse_key", "sparse_value_not_sparse_vector_instance"],
139+
)
140+
def test_point_to_document_sparse_vector_edge_cases(vector):
141+
point = SimpleNamespace(id="x", payload={"id": "x", "content": "x"}, vector=vector)
142+
document = convert_qdrant_point_to_haystack_document(point, use_sparse_embeddings=True)
143+
assert document.embedding == [0.1, 0.2]
144+
assert document.sparse_embedding is None

integrations/qdrant/tests/test_document_store.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,34 @@ def test_get_batches_from_generator(self):
342342
assert batches == [(1, 2), (3, 4), (5,)]
343343
assert list(get_batches_from_generator([], 2)) == []
344344

345+
def test_query_by_sparse_raises_when_sparse_disabled(self):
346+
document_store = QdrantDocumentStore(location=":memory:", use_sparse_embeddings=False)
347+
sparse_embedding = SparseEmbedding(indices=[0, 1], values=[0.1, 0.2])
348+
with pytest.raises(QdrantStoreError, match="use_sparse_embeddings=False"):
349+
document_store._query_by_sparse(query_sparse_embedding=sparse_embedding)
350+
351+
@pytest.mark.parametrize(
352+
("method_name", "args", "expected"),
353+
[
354+
("count_documents", (), 0),
355+
("count_documents_by_filter", ({},), 0),
356+
("get_metadata_fields_info", (), {}),
357+
("get_metadata_field_min_max", ("score",), {}),
358+
("count_unique_metadata_by_filter", ({}, ["category"]), {"category": 0}),
359+
("get_metadata_field_unique_values", ("category",), []),
360+
],
361+
)
362+
def test_metadata_methods_swallow_client_errors(self, method_name, args, expected):
363+
document_store = QdrantDocumentStore(location=":memory:")
364+
document_store._initialize_client()
365+
err = ValueError("boom")
366+
with (
367+
patch.object(document_store._client, "count", side_effect=err),
368+
patch.object(document_store._client, "scroll", side_effect=err),
369+
patch.object(document_store._client, "get_collection", side_effect=err),
370+
):
371+
assert getattr(document_store, method_name)(*args) == expected
372+
345373

346374
@pytest.mark.integration
347375
class TestQdrantDocumentStore(

integrations/qdrant/tests/test_document_store_async.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,43 @@ async def test_set_up_collection_with_distance_mismatch_async(self):
110110
with pytest.raises(ValueError, match="different similarity"):
111111
await document_store._set_up_collection_async("test_collection", 768, False, "cosine", False, False)
112112

113+
async def test_query_by_sparse_async_raises_when_sparse_disabled(self):
114+
document_store = QdrantDocumentStore(location=":memory:", use_sparse_embeddings=False)
115+
sparse_embedding = SparseEmbedding(indices=[0, 1], values=[0.1, 0.2])
116+
with pytest.raises(QdrantStoreError, match="use_sparse_embeddings=False"):
117+
await document_store._query_by_sparse_async(query_sparse_embedding=sparse_embedding)
118+
119+
async def test_delete_documents_async_invokes_client_and_handles_key_error(self):
120+
document_store = QdrantDocumentStore(location=":memory:")
121+
await document_store._initialize_async_client()
122+
with patch.object(document_store._async_client, "delete") as mock_delete:
123+
await document_store.delete_documents_async(["doc-1", "doc-2"])
124+
mock_delete.assert_awaited_once()
125+
with patch.object(document_store._async_client, "delete", side_effect=KeyError("missing")):
126+
await document_store.delete_documents_async(["doc-1"])
127+
128+
@pytest.mark.parametrize(
129+
("method_name", "args", "expected"),
130+
[
131+
("count_documents_async", (), 0),
132+
("count_documents_by_filter_async", ({},), 0),
133+
("get_metadata_fields_info_async", (), {}),
134+
("get_metadata_field_min_max_async", ("score",), {}),
135+
("count_unique_metadata_by_filter_async", ({}, ["category"]), {"category": 0}),
136+
("get_metadata_field_unique_values_async", ("category",), []),
137+
],
138+
)
139+
async def test_metadata_methods_async_absorb_client_errors(self, method_name, args, expected):
140+
document_store = QdrantDocumentStore(location=":memory:")
141+
await document_store._initialize_async_client()
142+
err = ValueError("boom")
143+
with (
144+
patch.object(document_store._async_client, "count", side_effect=err),
145+
patch.object(document_store._async_client, "scroll", side_effect=err),
146+
patch.object(document_store._async_client, "get_collection", side_effect=err),
147+
):
148+
assert await getattr(document_store, method_name)(*args) == expected
149+
113150

114151
@pytest.mark.integration
115152
@pytest.mark.asyncio

integrations/qdrant/tests/test_embedding_retriever.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,26 @@ def test_from_dict(self):
126126
assert retriever._group_by is None
127127
assert retriever._group_size is None
128128

129+
def test_from_dict_no_filter_policy(self):
130+
data = {
131+
"type": "haystack_integrations.components.retrievers.qdrant.retriever.QdrantEmbeddingRetriever",
132+
"init_parameters": {
133+
"document_store": {
134+
"init_parameters": {"location": ":memory:", "index": "test"},
135+
"type": "haystack_integrations.document_stores.qdrant.document_store.QdrantDocumentStore",
136+
},
137+
"filters": None,
138+
"top_k": 5,
139+
"scale_score": False,
140+
"return_embedding": True,
141+
"score_threshold": None,
142+
"group_by": None,
143+
"group_size": None,
144+
},
145+
}
146+
retriever = QdrantEmbeddingRetriever.from_dict(data)
147+
assert retriever._filter_policy == FilterPolicy.REPLACE # defaults to REPLACE
148+
129149
def test_run(self):
130150
mock_store = Mock(spec=QdrantDocumentStore)
131151
mock_store._query_by_embedding.return_value = [Document(content="doc", embedding=[0.1, 0.2])]

0 commit comments

Comments
 (0)