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

@ -46,7 +46,7 @@ from app.db import (
NewChatMessage,
NewChatMessageRole,
NewChatThread,
SearchSpace,
Workspace,
TokenUsage,
User,
)
@ -69,11 +69,11 @@ pytestmark = pytest.mark.integration
@pytest_asyncio.fixture
async def db_thread(
db_session: AsyncSession, db_user: User, db_search_space: SearchSpace
db_session: AsyncSession, db_user: User, db_workspace: Workspace
) -> NewChatThread:
thread = NewChatThread(
title="Test Chat",
search_space_id=db_search_space.id,
workspace_id=db_workspace.id,
created_by_id=db_user.id,
visibility=ChatVisibility.PRIVATE,
)
@ -109,7 +109,7 @@ def bypass_permission_checks(monkeypatch):
"""Replace RBAC + thread access checks with no-ops.
The append_message route under test calls ``check_permission`` and
``check_thread_access``; those rely on a SearchSpaceMembership row
``check_thread_access``; those rely on a WorkspaceMembership row
that the existing integration fixtures don't create. The contract
we want to verify here is the ``IntegrityError`` -> recovery branch,
not the RBAC plumbing so stub them.
@ -208,7 +208,7 @@ class TestToolHeavyTurnFinalize:
db_session,
db_user,
db_thread,
db_search_space,
db_workspace,
patched_shielded_session,
):
"""End-to-end seam: builder snapshot -> finalize -> DB row.
@ -221,7 +221,7 @@ class TestToolHeavyTurnFinalize:
"""
thread_id = db_thread.id
user_id_str = str(db_user.id)
search_space_id = db_search_space.id
workspace_id = db_workspace.id
turn_id = f"{thread_id}:tool_heavy"
msg_id = await persist_assistant_shell(
@ -258,7 +258,7 @@ class TestToolHeavyTurnFinalize:
await finalize_assistant_turn(
message_id=msg_id,
chat_id=thread_id,
search_space_id=search_space_id,
workspace_id=workspace_id,
user_id=user_id_str,
turn_id=turn_id,
content=snapshot,
@ -300,7 +300,7 @@ class TestToolHeavyTurnFinalize:
assert usage.total_tokens == 280
assert usage.cost_micros == 22222
assert usage.thread_id == thread_id
assert usage.search_space_id == search_space_id
assert usage.workspace_id == workspace_id
# ---------------------------------------------------------------------------
@ -314,7 +314,7 @@ class TestAppendMessageRecoveryAfterFinalize:
db_session,
db_user,
db_thread,
db_search_space,
db_workspace,
patched_shielded_session,
bypass_permission_checks,
):
@ -337,7 +337,7 @@ class TestAppendMessageRecoveryAfterFinalize:
"""
thread_id = db_thread.id
user_id_str = str(db_user.id)
search_space_id = db_search_space.id
workspace_id = db_workspace.id
turn_id = f"{thread_id}:fe_late_append"
# Step 1: server stream completes. Server-built rich content is
@ -353,7 +353,7 @@ class TestAppendMessageRecoveryAfterFinalize:
await finalize_assistant_turn(
message_id=msg_id,
chat_id=thread_id,
search_space_id=search_space_id,
workspace_id=workspace_id,
user_id=user_id_str,
turn_id=turn_id,
content=server_content,
@ -439,7 +439,7 @@ class TestAppendMessageRecoveryAfterFinalize:
db_session,
db_user,
db_thread,
db_search_space,
db_workspace,
patched_shielded_session,
bypass_permission_checks,
):
@ -456,7 +456,7 @@ class TestAppendMessageRecoveryAfterFinalize:
"""
thread_id = db_thread.id
user_id_str = str(db_user.id)
search_space_id = db_search_space.id
workspace_id = db_workspace.id
turn_id = f"{thread_id}:fe_first"
# Step 1: legacy FE appendMessage lands first. No prior shell
@ -490,7 +490,7 @@ class TestAppendMessageRecoveryAfterFinalize:
await finalize_assistant_turn(
message_id=adopted_id,
chat_id=thread_id,
search_space_id=search_space_id,
workspace_id=workspace_id,
user_id=user_id_str,
turn_id=turn_id,
content=server_content,

View file

@ -48,7 +48,7 @@ from app.db import (
NewChatMessage,
NewChatMessageRole,
NewChatThread,
SearchSpace,
Workspace,
User,
)
from app.services.new_streaming_service import VercelStreamingService
@ -68,11 +68,11 @@ pytestmark = pytest.mark.integration
@pytest_asyncio.fixture
async def db_thread(
db_session: AsyncSession, db_user: User, db_search_space: SearchSpace
db_session: AsyncSession, db_user: User, db_workspace: Workspace
) -> NewChatThread:
thread = NewChatThread(
title="Test Chat",
search_space_id=db_search_space.id,
workspace_id=db_workspace.id,
created_by_id=db_user.id,
visibility=ChatVisibility.PRIVATE,
)

View file

@ -38,7 +38,7 @@ from app.db import (
NewChatMessage,
NewChatMessageRole,
NewChatThread,
SearchSpace,
Workspace,
TokenUsage,
User,
)
@ -60,11 +60,11 @@ pytestmark = pytest.mark.integration
@pytest_asyncio.fixture
async def db_thread(
db_session: AsyncSession, db_user: User, db_search_space: SearchSpace
db_session: AsyncSession, db_user: User, db_workspace: Workspace
) -> NewChatThread:
thread = NewChatThread(
title="Test Chat",
search_space_id=db_search_space.id,
workspace_id=db_workspace.id,
created_by_id=db_user.id,
visibility=ChatVisibility.PRIVATE,
)
@ -537,13 +537,13 @@ class TestFinalizeAssistantTurn:
db_session,
db_user,
db_thread,
db_search_space,
db_workspace,
patched_shielded_session,
):
thread_id = db_thread.id
user_id_uuid = db_user.id
user_id_str = str(user_id_uuid)
search_space_id = db_search_space.id
workspace_id = db_workspace.id
turn_id = f"{thread_id}:4000"
msg_id = await persist_assistant_shell(
@ -568,7 +568,7 @@ class TestFinalizeAssistantTurn:
await finalize_assistant_turn(
message_id=msg_id,
chat_id=thread_id,
search_space_id=search_space_id,
workspace_id=workspace_id,
user_id=user_id_str,
turn_id=turn_id,
content=rich_content,
@ -597,19 +597,19 @@ class TestFinalizeAssistantTurn:
assert usage.total_tokens == 150
assert usage.cost_micros == 12345
assert usage.thread_id == thread_id
assert usage.search_space_id == search_space_id
assert usage.workspace_id == workspace_id
async def test_empty_content_writes_status_marker(
self,
db_session,
db_user,
db_thread,
db_search_space,
db_workspace,
patched_shielded_session,
):
thread_id = db_thread.id
user_id_str = str(db_user.id)
search_space_id = db_search_space.id
workspace_id = db_workspace.id
turn_id = f"{thread_id}:5000"
msg_id = await persist_assistant_shell(
@ -624,7 +624,7 @@ class TestFinalizeAssistantTurn:
await finalize_assistant_turn(
message_id=msg_id,
chat_id=thread_id,
search_space_id=search_space_id,
workspace_id=workspace_id,
user_id=user_id_str,
turn_id=turn_id,
content=[],
@ -640,12 +640,12 @@ class TestFinalizeAssistantTurn:
db_session,
db_user,
db_thread,
db_search_space,
db_workspace,
patched_shielded_session,
):
thread_id = db_thread.id
user_id_str = str(db_user.id)
search_space_id = db_search_space.id
workspace_id = db_workspace.id
turn_id = f"{thread_id}:6000"
msg_id = await persist_assistant_shell(
@ -659,7 +659,7 @@ class TestFinalizeAssistantTurn:
await finalize_assistant_turn(
message_id=msg_id,
chat_id=thread_id,
search_space_id=search_space_id,
workspace_id=workspace_id,
user_id=user_id_str,
turn_id=turn_id,
content=[{"type": "text", "text": "first finalize"}],
@ -681,7 +681,7 @@ class TestFinalizeAssistantTurn:
await finalize_assistant_turn(
message_id=msg_id,
chat_id=thread_id,
search_space_id=search_space_id,
workspace_id=workspace_id,
user_id=user_id_str,
turn_id=turn_id,
content=[{"type": "text", "text": "second finalize"}],
@ -708,7 +708,7 @@ class TestFinalizeAssistantTurn:
db_session,
db_user,
db_thread,
db_search_space,
db_workspace,
patched_shielded_session,
):
"""Cross-writer race: ``append_message`` arrives after ``finalize_assistant_turn``.
@ -722,7 +722,7 @@ class TestFinalizeAssistantTurn:
thread_id = db_thread.id
user_uuid = db_user.id
user_id_str = str(user_uuid)
search_space_id = db_search_space.id
workspace_id = db_workspace.id
turn_id = f"{thread_id}:7000"
msg_id = await persist_assistant_shell(
@ -735,7 +735,7 @@ class TestFinalizeAssistantTurn:
await finalize_assistant_turn(
message_id=msg_id,
chat_id=thread_id,
search_space_id=search_space_id,
workspace_id=workspace_id,
user_id=user_id_str,
turn_id=turn_id,
content=[{"type": "text", "text": "from server"}],
@ -758,7 +758,7 @@ class TestFinalizeAssistantTurn:
call_details=None,
thread_id=thread_id,
message_id=msg_id,
search_space_id=search_space_id,
workspace_id=workspace_id,
user_id=user_uuid,
)
.on_conflict_do_nothing(
@ -783,19 +783,19 @@ class TestFinalizeAssistantTurn:
db_session,
db_user,
db_thread,
db_search_space,
db_workspace,
patched_shielded_session,
):
thread_id = db_thread.id
user_id_str = str(db_user.id)
search_space_id = db_search_space.id
workspace_id = db_workspace.id
# message_id that doesn't exist — finalize must log+return,
# never raise (called from shielded finally).
await finalize_assistant_turn(
message_id=999_999_999,
chat_id=thread_id,
search_space_id=search_space_id,
workspace_id=workspace_id,
user_id=user_id_str,
turn_id="anything",
content=[{"type": "text", "text": "x"}],

View file

@ -2,7 +2,7 @@
These tests exercise the route handlers directly with real DB-backed
users, memberships, and permissions. The important contract is that a
thread shared with a search space stays shared across normal metadata
thread shared with a workspace stays shared across normal metadata
updates until the creator explicitly makes it private again.
"""
@ -19,9 +19,9 @@ from sqlalchemy.ext.asyncio import AsyncSession
from app.auth.context import AuthContext
from app.db import (
ChatVisibility,
SearchSpace,
SearchSpaceMembership,
SearchSpaceRole,
Workspace,
WorkspaceMembership,
WorkspaceRole,
User,
)
from app.routes import new_chat_routes
@ -39,7 +39,7 @@ def _auth(user: User) -> AuthContext:
@pytest_asyncio.fixture
async def db_member(db_session: AsyncSession, db_search_space: SearchSpace) -> User:
async def db_member(db_session: AsyncSession, db_workspace: Workspace) -> User:
member = User(
id=uuid.uuid4(),
email="member@surfsense.net",
@ -54,9 +54,9 @@ async def db_member(db_session: AsyncSession, db_search_space: SearchSpace) -> U
role = (
(
await db_session.execute(
select(SearchSpaceRole).where(
SearchSpaceRole.search_space_id == db_search_space.id,
SearchSpaceRole.name == "Editor",
select(WorkspaceRole).where(
WorkspaceRole.workspace_id == db_workspace.id,
WorkspaceRole.name == "Editor",
)
)
)
@ -64,9 +64,9 @@ async def db_member(db_session: AsyncSession, db_search_space: SearchSpace) -> U
.one()
)
db_session.add(
SearchSpaceMembership(
WorkspaceMembership(
user_id=member.id,
search_space_id=db_search_space.id,
workspace_id=db_workspace.id,
role_id=role.id,
is_owner=False,
)
@ -78,7 +78,7 @@ async def db_member(db_session: AsyncSession, db_search_space: SearchSpace) -> U
async def _create_thread(
db_session: AsyncSession,
db_user: User,
db_search_space: SearchSpace,
db_workspace: Workspace,
*,
title: str = "Visibility Invariant Chat",
):
@ -86,7 +86,7 @@ async def _create_thread(
NewChatThreadCreate(
title=title,
archived=False,
search_space_id=db_search_space.id,
workspace_id=db_workspace.id,
visibility=ChatVisibility.PRIVATE,
),
session=db_session,
@ -102,21 +102,21 @@ def _search_thread_ids(response) -> set[int]:
return {thread.id for thread in response}
async def test_private_thread_is_hidden_from_other_search_space_member(
async def test_private_thread_is_hidden_from_other_workspace_member(
db_session: AsyncSession,
db_user: User,
db_member: User,
db_search_space: SearchSpace,
db_workspace: Workspace,
):
thread = await _create_thread(db_session, db_user, db_search_space)
thread = await _create_thread(db_session, db_user, db_workspace)
member_threads = await new_chat_routes.list_threads(
search_space_id=db_search_space.id,
workspace_id=db_workspace.id,
session=db_session,
auth=_auth(db_member),
)
member_search = await new_chat_routes.search_threads(
search_space_id=db_search_space.id,
workspace_id=db_workspace.id,
title="Visibility",
session=db_session,
auth=_auth(db_member),
@ -137,9 +137,9 @@ async def test_creator_can_share_thread_and_member_can_list_search_read_it(
db_session: AsyncSession,
db_user: User,
db_member: User,
db_search_space: SearchSpace,
db_workspace: Workspace,
):
thread = await _create_thread(db_session, db_user, db_search_space)
thread = await _create_thread(db_session, db_user, db_workspace)
updated = await new_chat_routes.update_thread_visibility(
thread_id=thread.id,
@ -151,12 +151,12 @@ async def test_creator_can_share_thread_and_member_can_list_search_read_it(
)
member_threads = await new_chat_routes.list_threads(
search_space_id=db_search_space.id,
workspace_id=db_workspace.id,
session=db_session,
auth=_auth(db_member),
)
member_search = await new_chat_routes.search_threads(
search_space_id=db_search_space.id,
workspace_id=db_workspace.id,
title="Visibility",
session=db_session,
auth=_auth(db_member),
@ -177,9 +177,9 @@ async def test_creator_can_share_thread_and_member_can_list_search_read_it(
async def test_rename_and_archive_do_not_reset_shared_visibility(
db_session: AsyncSession,
db_user: User,
db_search_space: SearchSpace,
db_workspace: Workspace,
):
thread = await _create_thread(db_session, db_user, db_search_space)
thread = await _create_thread(db_session, db_user, db_workspace)
await new_chat_routes.update_thread_visibility(
thread_id=thread.id,
visibility_update=NewChatThreadVisibilityUpdate(
@ -211,9 +211,9 @@ async def test_non_creator_cannot_change_shared_thread_back_to_private(
db_session: AsyncSession,
db_user: User,
db_member: User,
db_search_space: SearchSpace,
db_workspace: Workspace,
):
thread = await _create_thread(db_session, db_user, db_search_space)
thread = await _create_thread(db_session, db_user, db_workspace)
await new_chat_routes.update_thread_visibility(
thread_id=thread.id,
visibility_update=NewChatThreadVisibilityUpdate(
@ -240,9 +240,9 @@ async def test_creator_can_make_shared_thread_private_again(
db_session: AsyncSession,
db_user: User,
db_member: User,
db_search_space: SearchSpace,
db_workspace: Workspace,
):
thread = await _create_thread(db_session, db_user, db_search_space)
thread = await _create_thread(db_session, db_user, db_workspace)
await new_chat_routes.update_thread_visibility(
thread_id=thread.id,
visibility_update=NewChatThreadVisibilityUpdate(
@ -261,12 +261,12 @@ async def test_creator_can_make_shared_thread_private_again(
auth=_auth(db_user),
)
member_threads = await new_chat_routes.list_threads(
search_space_id=db_search_space.id,
workspace_id=db_workspace.id,
session=db_session,
auth=_auth(db_member),
)
member_search = await new_chat_routes.search_threads(
search_space_id=db_search_space.id,
workspace_id=db_workspace.id,
title="Visibility",
session=db_session,
auth=_auth(db_member),