import test, { beforeEach } from 'node:test'; import assert from 'node:assert/strict'; import request from 'supertest'; import { createApp } from '../src/app.js'; import { __resetLlmRateLimitForTests } from '../src/services/llm-rate-limit.js'; import { __resetVerificationJobsForTests } from '../src/services/verification-jobs.js'; beforeEach(async () => { process.env.AUTH_BYPASS = 'true'; process.env.LLM_MOCK = 'true'; process.env.SIGNED_URL_MOCK = 'true'; process.env.UPLOAD_MOCK = 'true'; process.env.MAX_SIGNED_URL_SECONDS = '900'; process.env.LLM_RATE_LIMIT_PER_MINUTE = '20'; process.env.VERIFICATION_REQUIRE_FILE_EXISTS = 'false'; process.env.VERIFICATION_ACCESS_MODE = 'authenticated'; process.env.VERIFICATION_ATTIRE_PROVIDER = 'mock'; process.env.VERIFICATION_STORE = 'memory'; __resetLlmRateLimitForTests(); await __resetVerificationJobsForTests(); }); async function waitForMachineStatus(app, verificationId, maxAttempts = 30) { let last; for (let attempt = 0; attempt < maxAttempts; attempt += 1) { last = await request(app) .get(`/core/verifications/${verificationId}`) .set('Authorization', 'Bearer test-token'); if ( last.body?.status === 'AUTO_PASS' || last.body?.status === 'AUTO_FAIL' || last.body?.status === 'NEEDS_REVIEW' || last.body?.status === 'ERROR' ) { return last; } // eslint-disable-next-line no-await-in-loop await new Promise((resolve) => setTimeout(resolve, 10)); } return last; } test('GET /healthz returns healthy response', async () => { const app = createApp(); const res = await request(app).get('/healthz'); assert.equal(res.status, 200); assert.equal(res.body.ok, true); assert.equal(typeof res.body.requestId, 'string'); assert.equal(typeof res.headers['x-request-id'], 'string'); }); test('GET /readyz reports database not configured when env is absent', async () => { delete process.env.DATABASE_URL; delete process.env.DB_HOST; delete process.env.DB_NAME; delete process.env.DB_USER; delete process.env.DB_PASSWORD; delete process.env.INSTANCE_CONNECTION_NAME; delete process.env.VERIFICATION_STORE; const app = createApp(); const res = await request(app).get('/readyz'); assert.equal(res.status, 503); assert.equal(res.body.status, 'DATABASE_NOT_CONFIGURED'); }); test('POST /core/create-signed-url requires auth', async () => { process.env.AUTH_BYPASS = 'false'; const app = createApp(); const res = await request(app).post('/core/create-signed-url').send({ fileUri: 'gs://krow-workforce-dev-private/foo.pdf', }); assert.equal(res.status, 401); assert.equal(res.body.code, 'UNAUTHENTICATED'); process.env.AUTH_BYPASS = 'true'; }); test('POST /core/create-signed-url returns signed URL', async () => { const app = createApp(); const res = await request(app) .post('/core/create-signed-url') .set('Authorization', 'Bearer test-token') .send({ fileUri: 'gs://krow-workforce-dev-private/uploads/test-user/foo.pdf', expiresInSeconds: 300, }); assert.equal(res.status, 200); assert.equal(typeof res.body.signedUrl, 'string'); assert.equal(typeof res.body.expiresAt, 'string'); assert.equal(typeof res.body.requestId, 'string'); }); test('POST /core/create-signed-url rejects non-owned path', async () => { const app = createApp(); const res = await request(app) .post('/core/create-signed-url') .set('Authorization', 'Bearer test-token') .send({ fileUri: 'gs://krow-workforce-dev-private/uploads/other-user/foo.pdf', expiresInSeconds: 300, }); assert.equal(res.status, 403); assert.equal(res.body.code, 'FORBIDDEN'); }); test('POST /core/create-signed-url enforces expiry cap', async () => { process.env.MAX_SIGNED_URL_SECONDS = '300'; const app = createApp(); const res = await request(app) .post('/core/create-signed-url') .set('Authorization', 'Bearer test-token') .send({ fileUri: 'gs://krow-workforce-dev-private/uploads/test-user/foo.pdf', expiresInSeconds: 301, }); assert.equal(res.status, 400); assert.equal(res.body.code, 'VALIDATION_ERROR'); }); test('POST /invokeLLM legacy alias works', async () => { const app = createApp(); const res = await request(app) .post('/invokeLLM') .set('Authorization', 'Bearer test-token') .send({ prompt: 'hello', responseJsonSchema: { type: 'object' }, fileUrls: [], }); assert.equal(res.status, 200); assert.equal(typeof res.body.result, 'object'); assert.equal(typeof res.body.model, 'string'); }); test('POST /core/invoke-llm enforces per-user rate limit', async () => { process.env.LLM_RATE_LIMIT_PER_MINUTE = '1'; const app = createApp(); const first = await request(app) .post('/core/invoke-llm') .set('Authorization', 'Bearer test-token') .send({ prompt: 'hello', responseJsonSchema: { type: 'object' }, fileUrls: [], }); const second = await request(app) .post('/core/invoke-llm') .set('Authorization', 'Bearer test-token') .send({ prompt: 'hello again', responseJsonSchema: { type: 'object' }, fileUrls: [], }); assert.equal(first.status, 200); assert.equal(second.status, 429); assert.equal(second.body.code, 'RATE_LIMITED'); assert.equal(typeof second.headers['retry-after'], 'string'); }); test('POST /core/upload-file accepts audio/webm for rapid transcription', async () => { const app = createApp(); const res = await request(app) .post('/core/upload-file') .set('Authorization', 'Bearer test-token') .field('visibility', 'private') .attach('file', Buffer.from('fake-audio-data'), { filename: 'rapid-request.webm', contentType: 'audio/webm', }); assert.equal(res.status, 200); assert.equal(res.body.contentType, 'audio/webm'); assert.equal(typeof res.body.fileUri, 'string'); }); test('POST /core/rapid-orders/transcribe returns transcript in mock mode', async () => { const app = createApp(); const res = await request(app) .post('/core/rapid-orders/transcribe') .set('Authorization', 'Bearer test-token') .send({ audioFileUri: 'gs://krow-workforce-dev-private/uploads/test-user/request.webm', locale: 'en-US', promptHints: ['server', 'urgent'], }); assert.equal(res.status, 200); assert.equal(typeof res.body.transcript, 'string'); assert.ok(res.body.transcript.length > 0); assert.equal(typeof res.body.confidence, 'number'); assert.equal(typeof res.body.model, 'string'); assert.equal(typeof res.body.requestId, 'string'); }); test('POST /core/rapid-orders/transcribe rejects non-owned file URI', async () => { const app = createApp(); const res = await request(app) .post('/core/rapid-orders/transcribe') .set('Authorization', 'Bearer test-token') .send({ audioFileUri: 'gs://krow-workforce-dev-private/uploads/other-user/request.webm', locale: 'en-US', }); assert.equal(res.status, 403); assert.equal(res.body.code, 'FORBIDDEN'); }); test('POST /core/rapid-orders/parse returns structured rapid order draft', async () => { const app = createApp(); const res = await request(app) .post('/core/rapid-orders/parse') .set('Authorization', 'Bearer test-token') .send({ text: 'Need 2 servers ASAP for 4 hours', locale: 'en-US', timezone: 'America/New_York', now: '2026-02-27T12:00:00.000Z', }); assert.equal(res.status, 200); assert.equal(res.body.parsed.orderType, 'ONE_TIME'); assert.equal(res.body.parsed.isRapid, true); assert.equal(Array.isArray(res.body.parsed.positions), true); assert.equal(res.body.parsed.positions[0].role, 'server'); assert.equal(res.body.parsed.positions[0].count, 2); assert.equal(res.body.parsed.durationMinutes, 240); assert.equal(typeof res.body.confidence.overall, 'number'); assert.equal(typeof res.body.requestId, 'string'); }); test('POST /core/rapid-orders/parse validates timezone', async () => { const app = createApp(); const res = await request(app) .post('/core/rapid-orders/parse') .set('Authorization', 'Bearer test-token') .send({ text: 'Need 2 servers ASAP', timezone: 'Mars/OlympusMons', }); assert.equal(res.status, 400); assert.equal(res.body.code, 'VALIDATION_ERROR'); }); test('POST /core/rapid-orders/parse rejects unknown fields', async () => { const app = createApp(); const res = await request(app) .post('/core/rapid-orders/parse') .set('Authorization', 'Bearer test-token') .send({ text: 'Need 2 servers ASAP', unexpected: 'not-allowed', }); assert.equal(res.status, 400); assert.equal(res.body.code, 'VALIDATION_ERROR'); }); test('POST /core/rapid-orders/parse enforces per-user model rate limit', async () => { process.env.LLM_RATE_LIMIT_PER_MINUTE = '1'; const app = createApp(); const first = await request(app) .post('/core/rapid-orders/parse') .set('Authorization', 'Bearer test-token') .send({ text: 'Need 2 servers ASAP for 4 hours', }); const second = await request(app) .post('/core/rapid-orders/parse') .set('Authorization', 'Bearer test-token') .send({ text: 'Need 3 bartenders tonight', }); assert.equal(first.status, 200); assert.equal(second.status, 429); assert.equal(second.body.code, 'RATE_LIMITED'); assert.equal(typeof second.headers['retry-after'], 'string'); }); test('POST /core/verifications creates async job and GET returns status', async () => { const app = createApp(); const created = await request(app) .post('/core/verifications') .set('Authorization', 'Bearer test-token') .send({ type: 'attire', subjectType: 'staff', subjectId: 'staff_1', fileUri: 'gs://krow-workforce-dev-private/uploads/test-user/attire.jpg', rules: { attireType: 'shoes', expectedColor: 'black' }, }); assert.equal(created.status, 202); assert.equal(created.body.type, 'attire'); assert.equal(created.body.status, 'PENDING'); assert.equal(typeof created.body.verificationId, 'string'); const status = await waitForMachineStatus(app, created.body.verificationId); assert.equal(status.status, 200); assert.equal(status.body.verificationId, created.body.verificationId); assert.equal(status.body.type, 'attire'); assert.ok(['NEEDS_REVIEW', 'AUTO_PASS', 'AUTO_FAIL', 'ERROR'].includes(status.body.status)); }); test('POST /core/verifications rejects file paths not owned by actor', async () => { const app = createApp(); const res = await request(app) .post('/core/verifications') .set('Authorization', 'Bearer test-token') .send({ type: 'attire', fileUri: 'gs://krow-workforce-dev-private/uploads/other-user/not-allowed.jpg', rules: { attireType: 'shoes' }, }); assert.equal(res.status, 403); assert.equal(res.body.code, 'FORBIDDEN'); }); test('POST /core/verifications/:id/review finalizes verification', async () => { const app = createApp(); const created = await request(app) .post('/core/verifications') .set('Authorization', 'Bearer test-token') .send({ type: 'certification', subjectType: 'staff', subjectId: 'staff_1', fileUri: 'gs://krow-workforce-dev-private/uploads/test-user/cert.pdf', rules: { certType: 'food_safety' }, }); const status = await waitForMachineStatus(app, created.body.verificationId); assert.equal(status.status, 200); const reviewed = await request(app) .post(`/core/verifications/${created.body.verificationId}/review`) .set('Authorization', 'Bearer test-token') .send({ decision: 'APPROVED', note: 'Looks good', reasonCode: 'MANUAL_REVIEW', }); assert.equal(reviewed.status, 200); assert.equal(reviewed.body.status, 'APPROVED'); assert.equal(reviewed.body.review.decision, 'APPROVED'); }); test('POST /core/verifications/:id/retry requeues verification', async () => { const app = createApp(); const created = await request(app) .post('/core/verifications') .set('Authorization', 'Bearer test-token') .send({ type: 'government_id', subjectType: 'staff', subjectId: 'staff_1', fileUri: 'gs://krow-workforce-dev-private/uploads/test-user/id-front.jpg', rules: {}, }); const status = await waitForMachineStatus(app, created.body.verificationId); assert.equal(status.status, 200); const retried = await request(app) .post(`/core/verifications/${created.body.verificationId}/retry`) .set('Authorization', 'Bearer test-token') .send({}); assert.equal(retried.status, 202); assert.equal(retried.body.status, 'PENDING'); });