rmi-backend/tests/integration/test_qdrant_cleanup.py
opencode c762564d40 style(rmi-backend): complete lint cleanup — 1175→0 ruff errors
- Fix 71 invalid-syntax files (class-body newline-broken assignments)
- Add from/None chain to 307 B904 raise-without-from sites
- Add B008 ignore to ruff.toml (already in pyproject.toml)
- Noqa F401 on __init__.py re-exports (137 sites)
- Noqa E402 on deferred imports (63 sites)
- Bulk-add stdlib/FastAPI/project imports for F821 (127 sites)
- Replace ×→x, –→-, …→... in docstrings (4093 chars)
- Manual refactor of 5 SIM103/SIM116 patterns

Tests: 791 passed (66 deselected due to pre-existing Redis issues in test_rag.py)
Co-authored-by: opencode <opencode@rugmunch.io>
2026-07-06 15:43:20 +02:00

93 lines
3.3 KiB
Python

"""T15 - Qdrant test_col_* cleanup guard.
CI runs this after integration tests to verify no test_col_* collections
are left behind. Test fixtures SHOULD use unique names (uuid-based) and
clean up in teardown - this test catches regressions where they don't.
Also includes a pytest fixture that creates a unique test collection,
yields its name, and drops it on teardown - even on test failure.
"""
from __future__ import annotations
import os
import uuid
import httpx
import pytest
QDRANT_URL = os.getenv("QDRANT_URL", "http://localhost:6333")
def _list_collections() -> list[str]:
"""Fetch all Qdrant collection names."""
r = httpx.get(f"{QDRANT_URL}/collections", timeout=5.0)
r.raise_for_status()
return [c["name"] for c in r.json().get("result", {}).get("collections", [])]
def test_no_test_col_artifacts_after_test_run() -> None:
"""No test_col_* collections may exist after integration tests run.
A test_col_* artifact means a test forgot to clean up. With many
integration tests over time these accumulate (memory waste, query
slowdown, MCP agent confusion). This test catches any regression
where new tests don't clean up after themselves.
"""
names = _list_collections()
leaked = [n for n in names if n.startswith("test_col")]
assert not leaked, (
f"Found {len(leaked)} test_col_* collection artifacts left behind "
f"by integration tests: {leaked}. "
f"Fix: use the `clean_test_collection` fixture below, or add "
f"explicit teardown in your test that drops the collection."
)
def test_no_legacy_test_col_collection() -> None:
"""The bare 'test_col' collection (no suffix) is a known test artifact
from before fixtures used uuid suffixes. Catch any regression.
"""
names = _list_collections()
assert "test_col" not in names, (
"Bare 'test_col' collection found - this is a test artifact that "
"should never be present in production. Use the "
"`clean_test_collection` fixture for all Qdrant tests."
)
@pytest.fixture
def clean_test_collection() -> str:
"""Yield a unique Qdrant collection name and auto-drop on teardown.
Usage:
def test_my_qdrant_feature(clean_test_collection):
# collection is auto-created with a unique uuid name
qdrant.upsert(clean_test_collection, points=[...])
assert qdrant.search(clean_test_collection, vector=[...])
The fixture handles:
- Creates a fresh collection per test (no shared state)
- UUID-based name so parallel test runs don't collide
- Drops the collection on teardown, even if the test fails
- Skips the test if Qdrant is unreachable (graceful)
"""
name = f"test_col_{uuid.uuid4().hex[:12]}"
try:
httpx.put(
f"{QDRANT_URL}/collections/{name}",
json={"vectors": {"size": 4, "distance": "Cosine"}},
timeout=10.0,
).raise_for_status()
except (httpx.HTTPError, httpx.ConnectError) as e:
pytest.skip(f"Qdrant unreachable at {QDRANT_URL}: {e}")
return name # unreachable, for type checker
try:
yield name
finally:
# Always drop, even on test failure
try: # noqa: SIM105
httpx.delete(f"{QDRANT_URL}/collections/{name}", timeout=5.0)
except Exception:
pass # best-effort cleanup