import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' import { NextRequest, NextResponse } from 'next/server' function createCronRequest( url = 'https://example.com/api/cron/test', authHeader?: string, extraHeaders: Record = {}, ): NextRequest { const headers = new Headers(extraHeaders) if (authHeader) { headers.set('authorization', authHeader) } return new NextRequest(url, { headers }) } describe('cron auth and coordination', () => { beforeEach(() => { vi.resetModules() vi.stubEnv('REDIS_ENABLED', 'false') vi.stubEnv('CRON_SECRET', 'top-secret-token') }) afterEach(() => { vi.unstubAllEnvs() }) it('denies requests when CRON_SECRET is missing', async () => { vi.stubEnv('CRON_SECRET', '') const { requireCronAuth } = await import('@/lib/security/cron-auth') const response = requireCronAuth(createCronRequest()) expect(response).not.toBeNull() expect(response?.status).toBe(503) }) it('denies requests with missing bearer header', async () => { const { requireCronAuth } = await import('@/lib/security/cron-auth') const response = requireCronAuth(createCronRequest()) expect(response).not.toBeNull() expect(response?.status).toBe(401) }) it('allows requests with valid bearer header', async () => { const { requireCronAuth } = await import('@/lib/security/cron-auth') const response = requireCronAuth( createCronRequest('https://example.com/api/cron/test', 'Bearer top-secret-token'), ) expect(response).toBeNull() }) it('ignores duplicate idempotency-key requests', async () => { const { withCronExecution, resetCronCoordinationStateForTests } = await import( '@/lib/security/cron-coordination' ) resetCronCoordinationStateForTests() const req1 = createCronRequest( 'https://example.com/api/cron/test?idempotencyKey=abc', 'Bearer top-secret-token', ) const req2 = createCronRequest( 'https://example.com/api/cron/test?idempotencyKey=abc', 'Bearer top-secret-token', ) const first = await withCronExecution(req1, { endpoint: 'test-cron' }, async () => NextResponse.json({ ok: true }), ) const second = await withCronExecution(req2, { endpoint: 'test-cron' }, async () => NextResponse.json({ ok: true }), ) expect(first.status).toBe(200) expect(second.status).toBe(202) }) it('enforces execution lock per endpoint', async () => { const { withCronExecution, resetCronCoordinationStateForTests } = await import( '@/lib/security/cron-coordination' ) resetCronCoordinationStateForTests() let releaseHandler: (() => void) | null = null const firstRun = withCronExecution( createCronRequest('https://example.com/api/cron/test', 'Bearer top-secret-token'), { endpoint: 'locked-cron', lockTtlMs: 120000 }, async () => new Promise((resolve) => { releaseHandler = () => resolve(NextResponse.json({ ok: true })) }), ) const second = await withCronExecution( createCronRequest('https://example.com/api/cron/test', 'Bearer top-secret-token'), { endpoint: 'locked-cron', lockTtlMs: 120000 }, async () => NextResponse.json({ ok: true }), ) expect(second.status).toBe(423) releaseHandler?.() const first = await firstRun expect(first.status).toBe(200) }) })