fix: Pool-Connection-Isolation in withTenant, SQL-Injection-Schutz, ClickHouse env-var-Check
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,36 +1,65 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
|
||||
vi.mock('./client', () => ({
|
||||
db: {
|
||||
execute: vi.fn(),
|
||||
query: vi.fn().mockResolvedValue([{ id: '1' }]),
|
||||
},
|
||||
// Pool mocken — gibt einen fake PoolClient zurück
|
||||
const mockClient = vi.hoisted(() => ({
|
||||
query: vi.fn(),
|
||||
release: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock('pg', () => ({
|
||||
Pool: vi.fn().mockImplementation(() => ({
|
||||
connect: vi.fn().mockResolvedValue(mockClient),
|
||||
})),
|
||||
}))
|
||||
|
||||
import { withTenant } from './tenant'
|
||||
import { db } from './client'
|
||||
|
||||
describe('withTenant', () => {
|
||||
beforeEach(() => vi.clearAllMocks())
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
mockClient.query.mockResolvedValue({ rows: [] })
|
||||
})
|
||||
|
||||
it('setzt search_path auf tenant-Schema', async () => {
|
||||
await withTenant('abc123', () => db.query('SELECT 1', []))
|
||||
expect(db.execute).toHaveBeenCalledWith('SET search_path = tenant_abc123, public')
|
||||
await withTenant('abc123', async (client) => {
|
||||
await client.query('SELECT 1', [])
|
||||
})
|
||||
expect(mockClient.query).toHaveBeenCalledWith('SET search_path = tenant_abc123, public')
|
||||
})
|
||||
|
||||
it('setzt search_path zurück auf public nach Ausführung', async () => {
|
||||
await withTenant('abc123', () => db.query('SELECT 1', []))
|
||||
expect(db.execute).toHaveBeenLastCalledWith('SET search_path = public')
|
||||
await withTenant('abc123', async (client) => {
|
||||
await client.query('SELECT 1', [])
|
||||
})
|
||||
expect(mockClient.query).toHaveBeenLastCalledWith('SET search_path = public')
|
||||
})
|
||||
|
||||
it('setzt search_path zurück auch bei Fehler', async () => {
|
||||
const fn = vi.fn().mockRejectedValue(new Error('DB-Fehler'))
|
||||
await expect(withTenant('abc123', fn)).rejects.toThrow('DB-Fehler')
|
||||
expect(db.execute).toHaveBeenLastCalledWith('SET search_path = public')
|
||||
await expect(
|
||||
withTenant('abc123', async () => { throw new Error('DB-Fehler') })
|
||||
).rejects.toThrow('DB-Fehler')
|
||||
expect(mockClient.query).toHaveBeenLastCalledWith('SET search_path = public')
|
||||
expect(mockClient.release).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('gibt Rückgabewert der Funktion zurück', async () => {
|
||||
const result = await withTenant('abc123', async () => 'testdata')
|
||||
expect(result).toBe('testdata')
|
||||
})
|
||||
|
||||
it('wirft bei ungültiger tenantId', async () => {
|
||||
await expect(
|
||||
withTenant('invalid-tenant!', async () => 'x')
|
||||
).rejects.toThrow('Ungültige tenantId')
|
||||
})
|
||||
|
||||
it('gibt dieselbe Client-Instanz an fn weiter (Connection-Isolation)', async () => {
|
||||
let capturedClient: unknown
|
||||
await withTenant('tenant1', async (client) => {
|
||||
capturedClient = client
|
||||
})
|
||||
// Client muss nach withTenant released worden sein
|
||||
expect(mockClient.release).toHaveBeenCalledOnce()
|
||||
expect(capturedClient).toBeDefined()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user