test: pin suite to reserved llm_tester tenant with guard and teardown

Rewrite tests/conftest.py for the shared-services testing model where
tenancy is the only isolation wall:

- Remove the hardcoded production host default (192.168.86.149):
  TEST_HOST env with a safe localhost default; LIBRARY_DESK_URL selects
  the local wakeup server (8778), never the production container (8089).
- Pin the suite to the reserved test tenant llm_tester (TEST_TENANT may
  only choose a tenant inside the reserved llm_tester* namespace).
- Session guard (autouse) hard-aborts the whole run if the effective
  tenant is jpmschweitzer or outside the reserved namespace.
- Integration-marked tests only run with RUN_INTEGRATION_TESTS=1 and a
  passing guard; they are skipped otherwise.
- Session-scoped teardown deletes ALL llm_tester artifacts created
  during the run: Qdrant *_llm_tester collections, Neo4j
  User_Llm_Tester* nodes, wiki subtree users/llm_tester (and hyphen
  variant), llm_tester Redis keys on the service DB - with hard
  assert_safe_test_tenant() checks before every delete. Uses a sync
  fixture + asyncio.run to avoid the session loop-scope mismatch.
- Legacy tests/test_integration.py marked integration and pinned to the
  test tenant (taxonomy/list reads no longer touch the production
  namespace; Qdrant tests use the tenant-scoped collection name).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 11:21:23 +02:00
co-authored by Claude Fable 5
parent 33e62db6a2
commit b2399de5f9
3 changed files with 326 additions and 19 deletions
+23 -6
View File
@@ -7,13 +7,22 @@ These tests require actual service connectivity:
- SearXNG running at http://searxng:8080
- Ollama running at http://ollama:11434
Run with: pytest tests/test_integration.py -v
These tests run against the SHARED production services under the reserved
test tenant only. They are gated behind the session tenant guard and the
RUN_INTEGRATION_TESTS=1 environment flag (see tests/conftest.py) and are
skipped otherwise.
Run with:
RUN_INTEGRATION_TESTS=1 TEST_HOST=<shared-host> \
.venv/bin/python -m pytest tests/test_integration.py -v
"""
import pytest
import pytest_asyncio
from typing import AsyncGenerator
from tests.conftest import TEST_TENANT, assert_safe_test_tenant
from src.clients.neo4j_client import Neo4jClient
from src.clients.qdrant_client import QdrantClientWrapper
from src.clients.wikijs_client import WikiJSClient
@@ -22,6 +31,9 @@ from src.clients.ollama_client import OllamaClient
from src.jobs.job_manager import JobManager, JobType, JobStatus
from src.config import get_settings
# Only run when the tenant guard passes and integration mode is enabled.
pytestmark = pytest.mark.integration
@pytest.fixture
def settings():
@@ -100,6 +112,7 @@ class TestNeo4jIntegration:
@pytest.mark.asyncio
async def test_create_and_get_document(self, neo4j_client, test_user):
"""Test creating and retrieving a document node."""
assert_safe_test_tenant(test_user)
doc_id = "test_doc_integration"
# Create document
@@ -131,9 +144,10 @@ class TestQdrantIntegration:
@pytest.mark.asyncio
async def test_collection_creation(self, qdrant_client, test_user):
"""Test creating a collection."""
await qdrant_client.ensure_collection(test_user)
assert_safe_test_tenant(test_user)
collection_name = qdrant_client.get_collection_name(test_user)
await qdrant_client.ensure_collection(collection_name)
collections = qdrant_client.client.get_collections()
collection_names = [c.name for c in collections.collections]
@@ -142,7 +156,10 @@ class TestQdrantIntegration:
@pytest.mark.asyncio
async def test_upsert_and_search(self, qdrant_client, test_user):
"""Test upserting and searching chunks."""
await qdrant_client.ensure_collection(test_user)
assert_safe_test_tenant(test_user)
await qdrant_client.ensure_collection(
qdrant_client.get_collection_name(test_user)
)
# Create test chunks with 768-dimensional embeddings
chunks = [
@@ -190,7 +207,7 @@ class TestWikiJSIntegration:
@pytest.mark.asyncio
async def test_list_all_pages(self, wikijs_client):
"""Test listing all pages with pagination support."""
pages = await wikijs_client.list_all_pages(path_prefix="users/")
pages = await wikijs_client.list_all_pages(path_prefix=f"users/{TEST_TENANT}")
assert isinstance(pages, list)
# Verify each page has expected fields
for page in pages[:5]: # Check first 5
@@ -201,7 +218,7 @@ class TestWikiJSIntegration:
@pytest.mark.asyncio
async def test_get_taxonomy_structure(self, wikijs_client):
"""Test getting taxonomy structure for a user."""
taxonomy = await wikijs_client.get_taxonomy_structure("users/jpmschweitzer")
taxonomy = await wikijs_client.get_taxonomy_structure(f"users/{TEST_TENANT}")
assert isinstance(taxonomy, dict)
# Each key should be a category, value should be list of subcategories
for category, subcategories in taxonomy.items():