fix: dispose races, tunnel guards, retry on stale
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import type { ConnectionConfig } from '../../../src/config/types.js'
|
||||
import { DriverDisposedError } from '../../../src/db/driver.js'
|
||||
import type { ManagedConnection } from '../../../src/db/manager.js'
|
||||
import { withManaged } from '../../../src/tools/managed.js'
|
||||
import { type FakeManager, fakeManager } from '../helpers.js'
|
||||
|
||||
const config: ConnectionConfig = {
|
||||
name: 'c',
|
||||
type: 'postgres',
|
||||
host: 'h',
|
||||
user: 'u',
|
||||
readonly: false
|
||||
}
|
||||
|
||||
const managed = (driver: ManagedConnection['driver']): ManagedConnection => ({
|
||||
driver,
|
||||
config,
|
||||
source: 'store'
|
||||
})
|
||||
|
||||
describe('withManaged', () => {
|
||||
it('retries once when the driver was disposed under the caller', async () => {
|
||||
const manager: FakeManager = fakeManager()
|
||||
manager.get.mockResolvedValue(managed({} as ManagedConnection['driver']))
|
||||
const fn = vi
|
||||
.fn()
|
||||
.mockRejectedValueOnce(new DriverDisposedError())
|
||||
.mockResolvedValueOnce({ value: 42 })
|
||||
|
||||
const result = await withManaged(manager, 'c', fn)
|
||||
|
||||
expect(result.isError).toBeFalsy()
|
||||
expect(JSON.parse((result.content[0] as { text: string }).text)).toEqual({ value: 42 })
|
||||
expect(manager.get).toHaveBeenCalledTimes(2)
|
||||
expect(fn).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it('gives up after a second DriverDisposedError', async () => {
|
||||
const manager: FakeManager = fakeManager()
|
||||
manager.get.mockResolvedValue(managed({} as ManagedConnection['driver']))
|
||||
const fn = vi.fn().mockRejectedValue(new DriverDisposedError())
|
||||
|
||||
const result = await withManaged(manager, 'c', fn)
|
||||
|
||||
expect(result.isError).toBe(true)
|
||||
expect((result.content[0] as { text: string }).text).toContain('being reconfigured')
|
||||
expect(manager.get).toHaveBeenCalledTimes(2)
|
||||
})
|
||||
|
||||
it('formats other driver errors with the engine prefix, no retry', async () => {
|
||||
const manager: FakeManager = fakeManager()
|
||||
manager.get.mockResolvedValue(managed({} as ManagedConnection['driver']))
|
||||
const fn = vi.fn().mockRejectedValue(Object.assign(new Error('boom'), { code: '42P01' }))
|
||||
|
||||
const result = await withManaged(manager, 'c', fn)
|
||||
|
||||
expect(result.isError).toBe(true)
|
||||
expect((result.content[0] as { text: string }).text).toBe('[postgres 42P01] boom')
|
||||
expect(manager.get).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('returns manager errors plain without the engine prefix', async () => {
|
||||
const manager: FakeManager = fakeManager()
|
||||
manager.get.mockRejectedValue(new Error('no such connection'))
|
||||
const fn = vi.fn()
|
||||
|
||||
const result = await withManaged(manager, 'c', fn)
|
||||
|
||||
expect(result.isError).toBe(true)
|
||||
expect((result.content[0] as { text: string }).text).toBe('no such connection')
|
||||
expect(fn).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user