test: rename SearchSpace -> Workspace across tests + fixtures (Phase 2 Wave F)

Apply the same rename to surfsense_backend/tests: workspace_id fields/vars,
Workspace* classes/schemas, table name searchspaces -> workspaces in raw SQL,
and the API URL spellings -> /workspaces. Preserves the carve-out wire literals
tests assert (Celery task names, OTel key "search_space.id").
This commit is contained in:
CREDO23 2026-06-26 18:36:46 +02:00
parent 56826a63bc
commit ca9bd28934
124 changed files with 1269 additions and 1269 deletions

View file

@ -34,7 +34,7 @@ from tests.utils.helpers import (
auth_headers,
delete_document,
get_auth_token,
get_search_space_id,
get_workspace_id,
)
limiter.enabled = False
@ -66,7 +66,7 @@ class InlineTaskDispatcher:
document_id: int,
temp_path: str,
filename: str,
search_space_id: int,
workspace_id: int,
user_id: str,
use_vision_llm: bool = False,
processing_mode: str = "basic",
@ -80,7 +80,7 @@ class InlineTaskDispatcher:
document_id,
temp_path,
filename,
search_space_id,
workspace_id,
user_id,
use_vision_llm=use_vision_llm,
processing_mode=processing_mode,
@ -107,7 +107,7 @@ async def _ensure_tables():
# ---------------------------------------------------------------------------
# Auth & search space (session-scoped, via the in-process app)
# Auth & workspace (session-scoped, via the in-process app)
# ---------------------------------------------------------------------------
@ -121,12 +121,12 @@ async def auth_token(_ensure_tables) -> str:
@pytest.fixture(scope="session")
async def search_space_id(auth_token: str) -> int:
"""Discover the first search space belonging to the test user."""
async def workspace_id(auth_token: str) -> int:
"""Discover the first workspace belonging to the test user."""
async with httpx.AsyncClient(
transport=ASGITransport(app=app), base_url="http://test", timeout=30.0
) as c:
return await get_search_space_id(c, auth_token)
return await get_workspace_id(c, auth_token)
@pytest.fixture(scope="session")
@ -155,19 +155,19 @@ def cleanup_doc_ids() -> list[int]:
@pytest.fixture(scope="session", autouse=True)
async def _purge_test_search_space(search_space_id: int):
async def _purge_test_workspace(workspace_id: int):
"""Delete stale documents from previous runs before the session starts."""
conn = await asyncpg.connect(_ASYNCPG_URL)
try:
result = await conn.execute(
"DELETE FROM documents WHERE workspace_id = $1",
search_space_id,
workspace_id,
)
deleted = int(result.split()[-1])
if deleted:
print(
f"\n[purge] Deleted {deleted} stale document(s) "
f"from search space {search_space_id}"
f"from workspace {workspace_id}"
)
finally:
await conn.close()

View file

@ -37,11 +37,11 @@ class TestTxtFileUpload:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
):
resp = await upload_file(
client, headers, "sample.txt", search_space_id=search_space_id
client, headers, "sample.txt", workspace_id=workspace_id
)
assert resp.status_code == 200
@ -54,18 +54,18 @@ class TestTxtFileUpload:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
):
resp = await upload_file(
client, headers, "sample.txt", search_space_id=search_space_id
client, headers, "sample.txt", workspace_id=workspace_id
)
assert resp.status_code == 200
doc_ids = resp.json()["document_ids"]
cleanup_doc_ids.extend(doc_ids)
statuses = await poll_document_status(
client, headers, doc_ids, search_space_id=search_space_id
client, headers, doc_ids, workspace_id=workspace_id
)
for did in doc_ids:
assert statuses[did]["status"]["state"] == "ready"
@ -78,18 +78,18 @@ class TestPdfFileUpload:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
):
resp = await upload_file(
client, headers, "sample.pdf", search_space_id=search_space_id
client, headers, "sample.pdf", workspace_id=workspace_id
)
assert resp.status_code == 200
doc_ids = resp.json()["document_ids"]
cleanup_doc_ids.extend(doc_ids)
statuses = await poll_document_status(
client, headers, doc_ids, search_space_id=search_space_id, timeout=300.0
client, headers, doc_ids, workspace_id=workspace_id, timeout=300.0
)
for did in doc_ids:
assert statuses[did]["status"]["state"] == "ready"
@ -107,14 +107,14 @@ class TestMultiFileUpload:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
):
resp = await upload_multiple_files(
client,
headers,
["sample.txt", "sample.md"],
search_space_id=search_space_id,
workspace_id=workspace_id,
)
assert resp.status_code == 200
@ -139,22 +139,22 @@ class TestDuplicateFileUpload:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
):
resp1 = await upload_file(
client, headers, "sample.txt", search_space_id=search_space_id
client, headers, "sample.txt", workspace_id=workspace_id
)
assert resp1.status_code == 200
first_ids = resp1.json()["document_ids"]
cleanup_doc_ids.extend(first_ids)
await poll_document_status(
client, headers, first_ids, search_space_id=search_space_id
client, headers, first_ids, workspace_id=workspace_id
)
resp2 = await upload_file(
client, headers, "sample.txt", search_space_id=search_space_id
client, headers, "sample.txt", workspace_id=workspace_id
)
assert resp2.status_code == 200
@ -179,18 +179,18 @@ class TestDuplicateContentDetection:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
tmp_path: Path,
):
resp1 = await upload_file(
client, headers, "sample.txt", search_space_id=search_space_id
client, headers, "sample.txt", workspace_id=workspace_id
)
assert resp1.status_code == 200
first_ids = resp1.json()["document_ids"]
cleanup_doc_ids.extend(first_ids)
await poll_document_status(
client, headers, first_ids, search_space_id=search_space_id
client, headers, first_ids, workspace_id=workspace_id
)
src = FIXTURES_DIR / "sample.txt"
@ -202,7 +202,7 @@ class TestDuplicateContentDetection:
"/api/v1/documents/fileupload",
headers=headers,
files={"files": ("renamed_sample.txt", f)},
data={"search_space_id": str(search_space_id)},
data={"workspace_id": str(workspace_id)},
)
assert resp2.status_code == 200
second_ids = resp2.json()["document_ids"]
@ -212,7 +212,7 @@ class TestDuplicateContentDetection:
)
statuses = await poll_document_status(
client, headers, second_ids, search_space_id=search_space_id
client, headers, second_ids, workspace_id=workspace_id
)
for did in second_ids:
assert statuses[did]["status"]["state"] == "failed"
@ -231,11 +231,11 @@ class TestEmptyFileUpload:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
):
resp = await upload_file(
client, headers, "empty.pdf", search_space_id=search_space_id
client, headers, "empty.pdf", workspace_id=workspace_id
)
assert resp.status_code == 200
@ -244,7 +244,7 @@ class TestEmptyFileUpload:
assert doc_ids, "Expected at least one document id for empty PDF upload"
statuses = await poll_document_status(
client, headers, doc_ids, search_space_id=search_space_id, timeout=120.0
client, headers, doc_ids, workspace_id=workspace_id, timeout=120.0
)
for did in doc_ids:
assert statuses[did]["status"]["state"] == "failed"
@ -264,14 +264,14 @@ class TestUnauthenticatedUpload:
async def test_upload_without_auth_returns_401(
self,
client: httpx.AsyncClient,
search_space_id: int,
workspace_id: int,
):
file_path = FIXTURES_DIR / "sample.txt"
with open(file_path, "rb") as f:
resp = await client.post(
"/api/v1/documents/fileupload",
files={"files": ("sample.txt", f)},
data={"search_space_id": str(search_space_id)},
data={"workspace_id": str(workspace_id)},
)
assert resp.status_code == 401
@ -288,12 +288,12 @@ class TestNoFilesUpload:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
):
resp = await client.post(
"/api/v1/documents/fileupload",
headers=headers,
data={"search_space_id": str(search_space_id)},
data={"workspace_id": str(workspace_id)},
)
assert resp.status_code in {400, 422}
@ -310,24 +310,24 @@ class TestDocumentSearchability:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
):
resp = await upload_file(
client, headers, "sample.txt", search_space_id=search_space_id
client, headers, "sample.txt", workspace_id=workspace_id
)
assert resp.status_code == 200
doc_ids = resp.json()["document_ids"]
cleanup_doc_ids.extend(doc_ids)
await poll_document_status(
client, headers, doc_ids, search_space_id=search_space_id
client, headers, doc_ids, workspace_id=workspace_id
)
search_resp = await client.get(
"/api/v1/documents/search",
headers=headers,
params={"title": "sample", "search_space_id": search_space_id},
params={"title": "sample", "workspace_id": workspace_id},
)
assert search_resp.status_code == 200

View file

@ -57,7 +57,7 @@ class TestBalanceDecrementsOnSuccess:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
credits,
):
@ -65,14 +65,14 @@ class TestBalanceDecrementsOnSuccess:
before = await _get_balance(client, headers)
resp = await upload_file(
client, headers, "sample.pdf", search_space_id=search_space_id
client, headers, "sample.pdf", workspace_id=workspace_id
)
assert resp.status_code == 200
doc_ids = resp.json()["document_ids"]
cleanup_doc_ids.extend(doc_ids)
statuses = await poll_document_status(
client, headers, doc_ids, search_space_id=search_space_id, timeout=300.0
client, headers, doc_ids, workspace_id=workspace_id, timeout=300.0
)
for did in doc_ids:
assert statuses[did]["status"]["state"] == "ready"
@ -94,21 +94,21 @@ class TestUploadRejectedWhenCreditExhausted:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
credits,
):
await credits.set(balance_micros=0)
resp = await upload_file(
client, headers, "sample.pdf", search_space_id=search_space_id
client, headers, "sample.pdf", workspace_id=workspace_id
)
assert resp.status_code == 200
doc_ids = resp.json()["document_ids"]
cleanup_doc_ids.extend(doc_ids)
statuses = await poll_document_status(
client, headers, doc_ids, search_space_id=search_space_id, timeout=300.0
client, headers, doc_ids, workspace_id=workspace_id, timeout=300.0
)
for did in doc_ids:
assert statuses[did]["status"]["state"] == "failed"
@ -121,21 +121,21 @@ class TestUploadRejectedWhenCreditExhausted:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
credits,
):
await credits.set(balance_micros=0)
resp = await upload_file(
client, headers, "sample.pdf", search_space_id=search_space_id
client, headers, "sample.pdf", workspace_id=workspace_id
)
assert resp.status_code == 200
doc_ids = resp.json()["document_ids"]
cleanup_doc_ids.extend(doc_ids)
await poll_document_status(
client, headers, doc_ids, search_space_id=search_space_id, timeout=300.0
client, headers, doc_ids, workspace_id=workspace_id, timeout=300.0
)
balance = await _get_balance(client, headers)
@ -157,28 +157,28 @@ class TestInsufficientCreditsNotification:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
credits,
):
await credits.set(balance_micros=0)
resp = await upload_file(
client, headers, "sample.pdf", search_space_id=search_space_id
client, headers, "sample.pdf", workspace_id=workspace_id
)
assert resp.status_code == 200
doc_ids = resp.json()["document_ids"]
cleanup_doc_ids.extend(doc_ids)
await poll_document_status(
client, headers, doc_ids, search_space_id=search_space_id, timeout=300.0
client, headers, doc_ids, workspace_id=workspace_id, timeout=300.0
)
notifications = await get_notifications(
client,
headers,
type_filter="insufficient_credits",
search_space_id=search_space_id,
workspace_id=workspace_id,
)
assert len(notifications) >= 1, (
"Expected at least one insufficient_credits notification"
@ -206,28 +206,28 @@ class TestDocumentProcessingNotification:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
credits,
):
await credits.set(balance_micros=credits.pages(1000))
resp = await upload_file(
client, headers, "sample.txt", search_space_id=search_space_id
client, headers, "sample.txt", workspace_id=workspace_id
)
assert resp.status_code == 200
doc_ids = resp.json()["document_ids"]
cleanup_doc_ids.extend(doc_ids)
await poll_document_status(
client, headers, doc_ids, search_space_id=search_space_id
client, headers, doc_ids, workspace_id=workspace_id
)
notifications = await get_notifications(
client,
headers,
type_filter="document_processing",
search_space_id=search_space_id,
workspace_id=workspace_id,
)
completed = [
n
@ -252,7 +252,7 @@ class TestBalanceUnchangedOnProcessingFailure:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
credits,
):
@ -260,7 +260,7 @@ class TestBalanceUnchangedOnProcessingFailure:
await credits.set(balance_micros=starting)
resp = await upload_file(
client, headers, "empty.pdf", search_space_id=search_space_id
client, headers, "empty.pdf", workspace_id=workspace_id
)
assert resp.status_code == 200
doc_ids = resp.json()["document_ids"]
@ -268,7 +268,7 @@ class TestBalanceUnchangedOnProcessingFailure:
if doc_ids:
statuses = await poll_document_status(
client, headers, doc_ids, search_space_id=search_space_id, timeout=120.0
client, headers, doc_ids, workspace_id=workspace_id, timeout=120.0
)
for did in doc_ids:
assert statuses[did]["status"]["state"] == "failed"
@ -292,7 +292,7 @@ class TestSecondUploadExceedsCredit:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
credits,
):
@ -301,14 +301,14 @@ class TestSecondUploadExceedsCredit:
await credits.set(balance_micros=credits.pages(1))
resp1 = await upload_file(
client, headers, "sample.pdf", search_space_id=search_space_id
client, headers, "sample.pdf", workspace_id=workspace_id
)
assert resp1.status_code == 200
first_ids = resp1.json()["document_ids"]
cleanup_doc_ids.extend(first_ids)
statuses1 = await poll_document_status(
client, headers, first_ids, search_space_id=search_space_id, timeout=300.0
client, headers, first_ids, workspace_id=workspace_id, timeout=300.0
)
for did in first_ids:
assert statuses1[did]["status"]["state"] == "ready"
@ -317,7 +317,7 @@ class TestSecondUploadExceedsCredit:
client,
headers,
"sample.pdf",
search_space_id=search_space_id,
workspace_id=workspace_id,
filename_override="sample_copy.pdf",
)
assert resp2.status_code == 200
@ -325,7 +325,7 @@ class TestSecondUploadExceedsCredit:
cleanup_doc_ids.extend(second_ids)
statuses2 = await poll_document_status(
client, headers, second_ids, search_space_id=search_space_id, timeout=300.0
client, headers, second_ids, workspace_id=workspace_id, timeout=300.0
)
for did in second_ids:
assert statuses2[did]["status"]["state"] == "failed"

View file

@ -187,7 +187,7 @@ class TestStripeCheckoutSessionCreation:
self,
client,
headers,
search_space_id: int,
workspace_id: int,
monkeypatch,
):
checkout_session = SimpleNamespace(
@ -205,7 +205,7 @@ class TestStripeCheckoutSessionCreation:
response = await client.post(
"/api/v1/stripe/create-credit-checkout-session",
headers=headers,
json={"quantity": 2, "search_space_id": search_space_id},
json={"quantity": 2, "workspace_id": workspace_id},
)
assert response.status_code == 200, response.text
@ -217,12 +217,12 @@ class TestStripeCheckoutSessionCreation:
]
assert (
fake_client.last_params["success_url"]
== f"http://localhost:3000/dashboard/{search_space_id}/purchase-success"
== f"http://localhost:3000/dashboard/{workspace_id}/purchase-success"
"?session_id={CHECKOUT_SESSION_ID}"
)
assert (
fake_client.last_params["cancel_url"]
== f"http://localhost:3000/dashboard/{search_space_id}/purchase-cancel"
== f"http://localhost:3000/dashboard/{workspace_id}/purchase-cancel"
)
assert fake_client.last_params["metadata"]["purchase_type"] == "credits"
@ -244,7 +244,7 @@ class TestStripeCheckoutSessionCreation:
self,
client,
headers,
search_space_id: int,
workspace_id: int,
monkeypatch,
):
monkeypatch.setattr(stripe_routes.config, "STRIPE_CREDIT_BUYING_ENABLED", False)
@ -252,7 +252,7 @@ class TestStripeCheckoutSessionCreation:
response = await client.post(
"/api/v1/stripe/create-credit-checkout-session",
headers=headers,
json={"quantity": 2, "search_space_id": search_space_id},
json={"quantity": 2, "workspace_id": workspace_id},
)
assert response.status_code == 503, response.text
@ -270,7 +270,7 @@ class TestStripeWebhookFulfillment:
self,
client,
headers,
search_space_id: int,
workspace_id: int,
credits,
monkeypatch,
):
@ -291,7 +291,7 @@ class TestStripeWebhookFulfillment:
create_response = await client.post(
"/api/v1/stripe/create-credit-checkout-session",
headers=headers,
json={"quantity": 3, "search_space_id": search_space_id},
json={"quantity": 3, "workspace_id": workspace_id},
)
assert create_response.status_code == 200, create_response.text
@ -359,7 +359,7 @@ class TestStripeReconciliation:
self,
client,
headers,
search_space_id: int,
workspace_id: int,
credits,
monkeypatch,
):
@ -380,7 +380,7 @@ class TestStripeReconciliation:
create_response = await client.post(
"/api/v1/stripe/create-credit-checkout-session",
headers=headers,
json={"quantity": 3, "search_space_id": search_space_id},
json={"quantity": 3, "workspace_id": workspace_id},
)
assert create_response.status_code == 200, create_response.text
assert await _get_balance(TEST_EMAIL) == 1_000_000
@ -433,7 +433,7 @@ class TestStripeReconciliation:
self,
client,
headers,
search_space_id: int,
workspace_id: int,
credits,
monkeypatch,
):
@ -454,7 +454,7 @@ class TestStripeReconciliation:
create_response = await client.post(
"/api/v1/stripe/create-credit-checkout-session",
headers=headers,
json={"quantity": 1, "search_space_id": search_space_id},
json={"quantity": 1, "workspace_id": workspace_id},
)
assert create_response.status_code == 200, create_response.text

View file

@ -34,14 +34,14 @@ class TestPerFileSizeLimit:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
):
oversized = io.BytesIO(b"\x00" * (500 * 1024 * 1024 + 1))
resp = await client.post(
"/api/v1/documents/fileupload",
headers=headers,
files=[("files", ("big.pdf", oversized, "application/pdf"))],
data={"search_space_id": str(search_space_id)},
data={"workspace_id": str(workspace_id)},
)
assert resp.status_code == 413
assert "per-file limit" in resp.json()["detail"].lower()
@ -50,7 +50,7 @@ class TestPerFileSizeLimit:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
):
at_limit = io.BytesIO(b"\x00" * (500 * 1024 * 1024))
@ -58,7 +58,7 @@ class TestPerFileSizeLimit:
"/api/v1/documents/fileupload",
headers=headers,
files=[("files", ("exact500mb.txt", at_limit, "text/plain"))],
data={"search_space_id": str(search_space_id)},
data={"workspace_id": str(workspace_id)},
)
assert resp.status_code == 200
cleanup_doc_ids.extend(resp.json().get("document_ids", []))
@ -76,7 +76,7 @@ class TestNoFileCountLimit:
self,
client: httpx.AsyncClient,
headers: dict[str, str],
search_space_id: int,
workspace_id: int,
cleanup_doc_ids: list[int],
):
files = [
@ -87,7 +87,7 @@ class TestNoFileCountLimit:
"/api/v1/documents/fileupload",
headers=headers,
files=files,
data={"search_space_id": str(search_space_id)},
data={"workspace_id": str(workspace_id)},
)
assert resp.status_code == 200
cleanup_doc_ids.extend(resp.json().get("document_ids", []))