fix: close task3 qdrant and config quality gaps
This commit is contained in:
@@ -5,7 +5,17 @@ import requests
|
||||
from qdrant_test_helpers import FakeQdrantHttp, FakeResponse, _write_record
|
||||
|
||||
from tht.adapters.vector.qdrant import QdrantVectorStore, point_id
|
||||
from tht.ports.vector import VectorStoreError
|
||||
from tht.ports.vector import (
|
||||
SemanticIndexIncompatibleError,
|
||||
VectorResponseError,
|
||||
VectorStoreError,
|
||||
VectorTransportError,
|
||||
)
|
||||
|
||||
_REQUIRED_INDEXES = {
|
||||
"content_hash", "document_id", "kind", "record_key", "record_kind",
|
||||
"vector_generation", "workspace_id", "workspace_revision",
|
||||
}
|
||||
|
||||
|
||||
def _store(fake: FakeQdrantHttp, *, collection_lifecycle="create_if_missing") -> QdrantVectorStore:
|
||||
@@ -51,29 +61,7 @@ def test_require_existing_refuses_missing_collection_without_mutations():
|
||||
assert [call for call in fake.calls if call[0] == "PUT"] == []
|
||||
|
||||
|
||||
def test_require_existing_preflights_before_existing_hash_scroll():
|
||||
fake = FakeQdrantHttp()
|
||||
original_request = fake.request
|
||||
|
||||
def request(method, url, **kwargs):
|
||||
if method == "POST" and url.endswith("/points/scroll"):
|
||||
return FakeResponse(404, {"status": "error"})
|
||||
return original_request(method, url, **kwargs)
|
||||
|
||||
store = QdrantVectorStore(
|
||||
base_url="http://qdrant:6333", collection="workspace-semantic", workspace_id="demo",
|
||||
workspace_revision="a" * 40, expected_dimension=1024,
|
||||
collection_lifecycle="require_existing", request=request,
|
||||
)
|
||||
|
||||
with pytest.raises(VectorStoreError, match="semantic_index_incompatible"):
|
||||
store.existing_hashes("memory", ["memory"])
|
||||
|
||||
assert [call for call in fake.calls if call[1].endswith("/points/scroll")] == []
|
||||
assert [call for call in fake.calls if call[0] == "PUT"] == []
|
||||
|
||||
|
||||
def test_require_existing_delete_maps_collection_404_after_preflight():
|
||||
def test_require_existing_maps_scroll_404_after_compatible_preflight():
|
||||
fake = FakeQdrantHttp()
|
||||
fake.collection = {"vectors": {"size": 1024, "distance": "Cosine"}}
|
||||
fake.payload_indexes = {
|
||||
@@ -81,16 +69,9 @@ def test_require_existing_delete_maps_collection_404_after_preflight():
|
||||
"vector_generation", "workspace_id", "workspace_revision",
|
||||
}
|
||||
original_request = fake.request
|
||||
deleted = False
|
||||
|
||||
def request(method, url, **kwargs):
|
||||
nonlocal deleted
|
||||
if method == "GET" and url.endswith("/collections/workspace-semantic") and not deleted:
|
||||
response = original_request(method, url, **kwargs)
|
||||
deleted = True
|
||||
fake.collection = None
|
||||
return response
|
||||
if method == "POST" and url.endswith("/points/delete?wait=true"):
|
||||
if method == "POST" and url.endswith("/points/scroll"):
|
||||
original_request(method, url, **kwargs)
|
||||
return FakeResponse(404, {"status": "error"})
|
||||
return original_request(method, url, **kwargs)
|
||||
@@ -101,8 +82,79 @@ def test_require_existing_delete_maps_collection_404_after_preflight():
|
||||
collection_lifecycle="require_existing", request=request,
|
||||
)
|
||||
|
||||
with pytest.raises(VectorStoreError, match="semantic_index_incompatible"):
|
||||
store.delete_kinds("memory", ["memory"])
|
||||
with pytest.raises(SemanticIndexIncompatibleError):
|
||||
store.existing_hashes("memory", ["memory"])
|
||||
|
||||
assert [call for call in fake.calls if call[1].endswith("/points/scroll")]
|
||||
assert [call for call in fake.calls if call[0] == "PUT"] == []
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("operation", "generation"),
|
||||
[("delete_kinds", None), ("delete_generation", "gen:" + "a" * 32)],
|
||||
)
|
||||
def test_require_existing_maps_delete_scroll_404_after_compatible_preflight(operation, generation):
|
||||
fake = FakeQdrantHttp()
|
||||
fake.collection = {"vectors": {"size": 1024, "distance": "Cosine"}}
|
||||
fake.payload_indexes = {
|
||||
"content_hash", "document_id", "kind", "record_key", "record_kind",
|
||||
"vector_generation", "workspace_id", "workspace_revision",
|
||||
}
|
||||
original_request = fake.request
|
||||
|
||||
def request(method, url, **kwargs):
|
||||
if method == "POST" and url.endswith("/points/scroll"):
|
||||
original_request(method, url, **kwargs)
|
||||
return FakeResponse(404, {"status": "error"})
|
||||
return original_request(method, url, **kwargs)
|
||||
|
||||
store = QdrantVectorStore(
|
||||
base_url="http://qdrant:6333", collection="workspace-semantic", workspace_id="demo",
|
||||
workspace_revision="a" * 40, expected_dimension=1024,
|
||||
collection_lifecycle="require_existing", request=request,
|
||||
)
|
||||
|
||||
with pytest.raises(SemanticIndexIncompatibleError):
|
||||
if operation == "delete_kinds":
|
||||
store.delete_kinds("memory", ["memory"])
|
||||
else:
|
||||
store.delete_generation("evidence", generation, "demo")
|
||||
|
||||
assert [call for call in fake.calls if call[1].endswith("/points/scroll")]
|
||||
assert [call for call in fake.calls if call[0] == "POST" and "delete" in call[1]] == []
|
||||
|
||||
|
||||
def test_require_existing_scroll_non_404_remains_transport_error():
|
||||
fake = FakeQdrantHttp()
|
||||
fake.collection = {"vectors": {"size": 1024, "distance": "Cosine"}}
|
||||
fake.payload_indexes = set(_REQUIRED_INDEXES)
|
||||
original_request = fake.request
|
||||
|
||||
def request(method, url, **kwargs):
|
||||
if method == "POST" and url.endswith("/points/scroll"):
|
||||
original_request(method, url, **kwargs)
|
||||
return FakeResponse(503, {"status": "error"})
|
||||
return original_request(method, url, **kwargs)
|
||||
|
||||
store = QdrantVectorStore(
|
||||
base_url="http://qdrant:6333", collection="workspace-semantic", workspace_id="demo",
|
||||
workspace_revision="a" * 40, expected_dimension=1024,
|
||||
collection_lifecycle="require_existing", request=request,
|
||||
)
|
||||
with pytest.raises(VectorTransportError) as caught:
|
||||
store.existing_hashes("memory", ["memory"])
|
||||
assert caught.value.status_code == 503
|
||||
|
||||
|
||||
def test_require_existing_scroll_malformed_remains_response_error():
|
||||
fake = FakeQdrantHttp()
|
||||
fake.collection = {"vectors": {"size": 1024, "distance": "Cosine"}}
|
||||
fake.payload_indexes = set(_REQUIRED_INDEXES)
|
||||
fake.malformed_scroll = True
|
||||
store = _store(fake, collection_lifecycle="require_existing")
|
||||
with pytest.raises(VectorResponseError):
|
||||
store.existing_hashes("memory", ["memory"])
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("dimension", "distance", "indexes", "index_types"),
|
||||
@@ -581,6 +633,7 @@ def test_upsert_payload_keeps_canonical_identity_when_metadata_collides():
|
||||
|
||||
def test_scroll_based_operations_paginate_until_next_page_offset_is_absent():
|
||||
fake = FakeQdrantHttp()
|
||||
fake.collection = {"vectors": {"size": 1024, "distance": "Cosine"}}
|
||||
generation_a = "gen:" + "1" * 32
|
||||
generation_b = "gen:" + "2" * 32
|
||||
fake.scroll_pages = [
|
||||
|
||||
Reference in New Issue
Block a user