Files
orca/src/main/runtime/runtime-project-group-controller-folder-delete.test.ts
T
Jinwoo Hong bed9734a9d Prevent deleted workspace browser snapshot resurrection (#17779)
* Prevent deleted workspace browser snapshot resurrection

* fix: tear down folder workspace browser tabs

* fix: fence pre-publication browser snapshots

* fix: route folder deletion through runtime cleanup

* chore: retrigger CI

* fix: sweep folder PTYs on runtime deletion

* fix: restore deletion fences after runtime refactor

* test: cover deleted renderer snapshot after recreation

* fix: avoid publishing ambiguous worktree snapshots

* fix: preserve optional worktree index state

* fix: fence paired PTYs on worktree removal

* fix: harden deletion fence and folder-delete teardown

- Folder-group delete no longer fails on a mixed-host group: an ambiguous
  connection skips the PTY sweep instead of rejecting the delete.
- Share one folder-workspace PTY teardown helper between the runtime
  removal path and the project-group controller.
- Simplify the mobile snapshot fence: identity-carrying frames are judged
  against the live catalog instanceId and clear the fence once the
  successor is accepted; identity-less frames are fenced by renderer
  generation. Drops the unbounded epoch bookkeeping.
- A fenced frame no longer triggers a resync request on every sync while
  the renderer still lists it as unchanged.
- Cross-host id collisions publish without an instanceId rather than
  blanking the mobile session for that workspace.
- Folder delete IPC always routes through the runtime; the store-only
  fallback and double notify are gone.
- Drop the redundant rescue-path tombstone check; ownership is purged at
  removal.
- Fence tests drive removeWorktreeMetadataAndHistory + syncWindowGraph
  instead of seeding the fence map, and add accept-after-recreate,
  no-resync, and ambiguous-host folder delete cases.
2026-09-02 00:52:24 -04:00

65 lines
2.4 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest'
import { RuntimeProjectGroupController } from './runtime-project-group-controller'
import type { FolderWorkspace } from '../../shared/folder-workspace-types'
const workspace = {
id: 'ws-1',
projectGroupId: 'group-1',
folderPath: '/tmp/ws'
} as FolderWorkspace
function createController(
resolveFolderConnectionId: (workspace: FolderWorkspace) => string | null
) {
const removeFolderWorkspace = vi.fn(() => true)
const teardownFolderWorkspacePtys = vi.fn(async () => undefined)
const cleanupRemovedFolderWorkspaceState = vi.fn()
const notifyReposChanged = vi.fn()
const controller = new RuntimeProjectGroupController({
getStore: () => ({ getFolderWorkspaces: () => [workspace], removeFolderWorkspace }) as never,
resolveRepo: async () => {
throw new Error('unused')
},
notifyReposChanged,
resolveFolderConnectionId,
teardownFolderWorkspacePtys,
cleanupRemovedFolderWorkspaceState
})
return {
controller,
removeFolderWorkspace,
teardownFolderWorkspacePtys,
cleanupRemovedFolderWorkspaceState,
notifyReposChanged
}
}
describe('RuntimeProjectGroupController.deleteFolderWorkspace', () => {
it('tears down PTYs and runtime state before removing the catalog row', async () => {
const deps = createController(() => 'ssh-1')
await expect(deps.controller.deleteFolderWorkspace('ws-1')).resolves.toEqual({ deleted: true })
expect(deps.teardownFolderWorkspacePtys).toHaveBeenCalledWith('folder:ws-1', 'ssh-1')
expect(deps.cleanupRemovedFolderWorkspaceState).toHaveBeenCalledWith('folder:ws-1')
expect(deps.teardownFolderWorkspacePtys.mock.invocationCallOrder[0]).toBeLessThan(
deps.removeFolderWorkspace.mock.invocationCallOrder[0]!
)
expect(deps.notifyReposChanged).toHaveBeenCalledTimes(1)
})
it('still deletes when the folder host is ambiguous, skipping only the PTY sweep', async () => {
const warn = vi.spyOn(console, 'warn').mockImplementation(() => undefined)
const deps = createController(() => {
throw new Error('folder_workspace_connection_ambiguous')
})
await expect(deps.controller.deleteFolderWorkspace('ws-1')).resolves.toEqual({ deleted: true })
expect(deps.teardownFolderWorkspacePtys).not.toHaveBeenCalled()
expect(deps.cleanupRemovedFolderWorkspaceState).toHaveBeenCalledWith('folder:ws-1')
expect(deps.removeFolderWorkspace).toHaveBeenCalledWith('ws-1')
warn.mockRestore()
})
})