Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/desktop-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ jobs:
working-directory: apps/desktop
run: bunx playwright install chromium

# The terminal-cancel suite drives a real tmux server; without tmux its tmux scenarios skip.
- name: Install tmux
run: brew install tmux

- name: Run Playwright _electron smoke suite
working-directory: apps/desktop
run: bunx playwright test
Expand Down
62 changes: 54 additions & 8 deletions apps/desktop/src/main/desktop-executor/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,31 @@ import { describe, expect, it, vi } from 'vitest'

vi.mock('electron', () => import('@/test/electron-mock'))

/** How many journal loads still fail, like a read that throws. */
const journalFaults = vi.hoisted(() => ({ loads: 0 }))

vi.mock('@/main/desktop-executor/journal', async () => {
const actual = await vi.importActual<typeof import('@/main/desktop-executor/journal')>(
'@/main/desktop-executor/journal'
)
return {
...actual,
createExecutorJournal: (...args: Parameters<typeof actual.createExecutorJournal>) => {
const journal = actual.createExecutorJournal(...args)
return {
...journal,
load: () => {
if (journalFaults.loads <= 0) return journal.load()
journalFaults.loads -= 1
return Promise.reject(new Error('The disk went away.'))
},
}
},
}
})

import { net } from 'electron'
import { DesktopExecutor } from '@/main/desktop-executor/executor'
import { createExecutorJournal } from '@/main/desktop-executor/journal'
import { createDesktopExecutorService, deviceName } from '@/main/desktop-executor/service'

Expand Down Expand Up @@ -156,18 +180,40 @@ describe('results recovery will hand to the model', () => {
executionToken: 't1',
completion: { status: 'success', message: 'running', data: { status: 'running' } },
})
const { sim, desktopExecutor } = await service(1, userData)
// Recovery returns only once Sim has the result and the journal no longer holds it, so a
// snapshot taken any time after recovery started would come back empty.
const recover = DesktopExecutor.prototype.recover
const recovered = vi
.spyOn(DesktopExecutor.prototype, 'recover')
.mockImplementation(async function (this: DesktopExecutor) {
await recover.call(this)
await vi.waitFor(async () => expect(await createExecutorJournal(path).load()).toEqual([]))
})
try {
const { sim, desktopExecutor } = await service(1, userData)
desktopExecutor.start()
await vi.waitFor(() => expect(sim.registrations).toHaveLength(1))
sim.registrations[0]?.(true)
await vi.waitFor(() => expect(sim.requests).toContain('POST /api/desktop/tool/complete'))
await vi.waitFor(async () => expect(await createExecutorJournal(path).load()).toEqual([]))

expect([...(await desktopExecutor.pendingResults())]).toEqual(['handed-back'])
await desktopExecutor.signOut()
} finally {
recovered.mockRestore()
}
})

it('counts a journal that cannot be loaded at all as holding none, and still starts', async () => {
journalFaults.loads = 1
const { sim, desktopExecutor } = await service()

expect([...(await desktopExecutor.pendingResults())]).toEqual([])
desktopExecutor.start()
await vi.waitFor(() => expect(sim.registrations).toHaveLength(1))
sim.registrations[0]?.(true)

// Recovery hands the result to Sim and drops it from the journal.
await vi.waitFor(async () => {
expect(sim.requests).toContain('POST /api/desktop/tool/complete')
expect(await createExecutorJournal(path).load()).toEqual([])
})

expect([...(await desktopExecutor.pendingResults())]).toEqual(['handed-back'])
await vi.waitFor(() => expect(sim.requests).toContain('GET /api/desktop/inbox'))
await desktopExecutor.signOut()
})
})
Expand Down
8 changes: 8 additions & 0 deletions apps/desktop/src/main/desktop-executor/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,14 @@ export function createDesktopExecutorService(
)
)
)
// The journal reads an unreadable file as empty, so this is for a load that throws anyway:
// it holds none, and the executor still starts.
.catch((error: unknown) => {
Comment thread
waleedlatif1 marked this conversation as resolved.
logger.warn('Could not read the executor journal for pending results', {
error: getErrorMessage(error),
})
return new Set<string>()
})
return pendingSnapshot
}
/** Bumped on sign-out, so work started for the previous session cannot resume it. */
Expand Down
Loading