Files
hermes-web-ui/tests/server/safe-file-store-backup-fallback.test.ts

66 lines
2.3 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from 'vitest'
const {
mockCopyFile,
mockMkdir,
mockReadFile,
mockRename,
mockRm,
mockWriteFile,
} = vi.hoisted(() => ({
mockCopyFile: vi.fn(),
mockMkdir: vi.fn(),
mockReadFile: vi.fn(),
mockRename: vi.fn(),
mockRm: vi.fn(),
mockWriteFile: vi.fn(),
}))
vi.mock('fs/promises', () => ({
copyFile: mockCopyFile,
mkdir: mockMkdir,
readFile: mockReadFile,
rename: mockRename,
rm: mockRm,
writeFile: mockWriteFile,
}))
afterEach(() => {
vi.clearAllMocks()
})
describe('SafeFileStore backup fallback', () => {
it('uses a timestamped backup when the default backup cannot be overwritten', async () => {
mockCopyFile
.mockRejectedValueOnce(Object.assign(new Error('permission denied'), { code: 'EACCES' }))
.mockResolvedValueOnce(undefined)
mockMkdir.mockResolvedValue(undefined)
mockWriteFile.mockResolvedValue(undefined)
mockRename.mockResolvedValue(undefined)
const { SafeFileStore } = await import('../../packages/server/src/services/safe-file-store')
const store = new SafeFileStore()
await store.writeText('/tmp/config.yaml', 'model:\n default: new\n', { backup: true })
expect(mockCopyFile).toHaveBeenCalledTimes(2)
expect(mockCopyFile).toHaveBeenNthCalledWith(1, '/tmp/config.yaml', '/tmp/config.yaml.bak')
expect(mockCopyFile.mock.calls[1][0]).toBe('/tmp/config.yaml')
expect(mockCopyFile.mock.calls[1][1]).toMatch(/^\/tmp\/config\.yaml\.bak\.\d+\./)
expect(mockWriteFile).toHaveBeenCalledWith(expect.stringContaining('/tmp/config.yaml.tmp.'), 'model:\n default: new\n', 'utf-8')
expect(mockRename).toHaveBeenCalledWith(expect.stringContaining('/tmp/config.yaml.tmp.'), '/tmp/config.yaml')
})
it('preserves explicit backup path failures', async () => {
mockCopyFile.mockRejectedValueOnce(Object.assign(new Error('permission denied'), { code: 'EACCES' }))
mockMkdir.mockResolvedValue(undefined)
const { SafeFileStore } = await import('../../packages/server/src/services/safe-file-store')
const store = new SafeFileStore()
await expect(store.writeText('/tmp/config.yaml', 'new', { backup: true, backupPath: '/tmp/custom.bak' })).rejects.toThrow('permission denied')
expect(mockCopyFile).toHaveBeenCalledTimes(1)
expect(mockWriteFile).not.toHaveBeenCalled()
})
})