Add Fastify server with config validation (Zod), health/healthz endpoints, auth middleware (Bearer token + session lookup), security plugins (CORS, Helmet, rate limiting), error handler, audit logging, and graceful shutdown. 36 tests passing. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
84 lines
2.3 KiB
TypeScript
84 lines
2.3 KiB
TypeScript
import { describe, it, expect, afterEach } from 'vitest';
|
|
import type { FastifyInstance } from 'fastify';
|
|
import { createServer } from '../src/server.js';
|
|
import type { McpdConfig } from '../src/config/index.js';
|
|
|
|
let app: FastifyInstance;
|
|
|
|
afterEach(async () => {
|
|
if (app) await app.close();
|
|
});
|
|
|
|
const testConfig: McpdConfig = {
|
|
port: 3000,
|
|
host: '0.0.0.0',
|
|
databaseUrl: 'postgresql://localhost/test',
|
|
logLevel: 'fatal', // suppress logs in tests
|
|
corsOrigins: ['*'],
|
|
rateLimitMax: 100,
|
|
rateLimitWindowMs: 60_000,
|
|
};
|
|
|
|
describe('createServer', () => {
|
|
it('creates a Fastify instance', async () => {
|
|
app = await createServer(testConfig, {
|
|
health: { checkDb: async () => true },
|
|
});
|
|
expect(app).toBeDefined();
|
|
});
|
|
|
|
it('registers health endpoint', async () => {
|
|
app = await createServer(testConfig, {
|
|
health: { checkDb: async () => true },
|
|
});
|
|
await app.ready();
|
|
|
|
const res = await app.inject({ method: 'GET', url: '/health' });
|
|
expect(res.statusCode).toBe(200);
|
|
});
|
|
|
|
it('registers healthz endpoint', async () => {
|
|
app = await createServer(testConfig, {
|
|
health: { checkDb: async () => true },
|
|
});
|
|
await app.ready();
|
|
|
|
const res = await app.inject({ method: 'GET', url: '/healthz' });
|
|
expect(res.statusCode).toBe(200);
|
|
});
|
|
|
|
it('returns 404 for unknown routes', async () => {
|
|
app = await createServer(testConfig, {
|
|
health: { checkDb: async () => true },
|
|
});
|
|
await app.ready();
|
|
|
|
const res = await app.inject({ method: 'GET', url: '/nonexistent' });
|
|
expect(res.statusCode).toBe(404);
|
|
});
|
|
|
|
it('includes CORS headers', async () => {
|
|
app = await createServer(testConfig, {
|
|
health: { checkDb: async () => true },
|
|
});
|
|
await app.ready();
|
|
|
|
const res = await app.inject({
|
|
method: 'OPTIONS',
|
|
url: '/health',
|
|
headers: { origin: 'http://localhost:3000' },
|
|
});
|
|
expect(res.headers['access-control-allow-origin']).toBeDefined();
|
|
});
|
|
|
|
it('includes security headers from Helmet', async () => {
|
|
app = await createServer(testConfig, {
|
|
health: { checkDb: async () => true },
|
|
});
|
|
await app.ready();
|
|
|
|
const res = await app.inject({ method: 'GET', url: '/health' });
|
|
expect(res.headers['x-content-type-options']).toBe('nosniff');
|
|
});
|
|
});
|