/**
* Integration tests for HTTP Server
*/
import { describe, it, expect, vi, beforeAll, afterAll } from 'vitest';
import request from 'supertest';
import express from 'express';
// Mock environment variables
process.env.KIBANA_URL = 'https://test-kibana.example.com';
process.env.KIBANA_API_KEY = 'test-key';
process.env.HTTP_PORT = '0'; // Use port 0 to get random available port
process.env.LOG_LEVEL = 'error';
// Mock the entire MCP SDK and Kibana client
vi.mock('@modelcontextprotocol/sdk/server/sse.js', () => ({
SSEServerTransport: vi.fn().mockImplementation(() => ({
connect: vi.fn(),
})),
}));
vi.mock('./server.js', () => ({
createMcpServer: vi.fn().mockReturnValue({
connect: vi.fn().mockResolvedValue(undefined),
close: vi.fn().mockResolvedValue(undefined),
}),
}));
describe('HTTP Server Integration', () => {
let app: express.Application;
beforeAll(() => {
// Create a minimal Express app for testing
app = express();
app.use(express.json());
// Health check endpoint
app.get('/health', (req, res) => {
res.status(200).json({
status: 'healthy',
service: 'kibana-mcp-server',
version: '0.1.0',
timestamp: new Date().toISOString(),
});
});
// Server info endpoint
app.get('/info', (req, res) => {
res.json({
name: 'kibana-mcp-server',
version: '0.1.0',
description: 'Model Context Protocol server for Kibana integration',
capabilities: ['resources', 'tools'],
transport: 'sse',
});
});
// 404 handler
app.use((req, res) => {
res.status(404).json({
error: 'Not found',
path: req.path,
});
});
// Error handler
app.use(
(
err: Error,
req: express.Request,
res: express.Response,
next: express.NextFunction
) => {
res.status(500).json({
error: 'Internal server error',
message: err.message,
});
}
);
});
describe('GET /health', () => {
it('should return 200 and health status', async () => {
const response = await request(app).get('/health');
expect(response.status).toBe(200);
expect(response.body).toHaveProperty('status', 'healthy');
expect(response.body).toHaveProperty('service', 'kibana-mcp-server');
expect(response.body).toHaveProperty('version', '0.1.0');
expect(response.body).toHaveProperty('timestamp');
});
it('should return valid JSON', async () => {
const response = await request(app).get('/health');
expect(response.headers['content-type']).toMatch(/application\/json/);
expect(response.body).toBeDefined();
});
});
describe('GET /info', () => {
it('should return server information', async () => {
const response = await request(app).get('/info');
expect(response.status).toBe(200);
expect(response.body).toEqual({
name: 'kibana-mcp-server',
version: '0.1.0',
description: 'Model Context Protocol server for Kibana integration',
capabilities: ['resources', 'tools'],
transport: 'sse',
});
});
it('should include capabilities array', async () => {
const response = await request(app).get('/info');
expect(response.body.capabilities).toBeInstanceOf(Array);
expect(response.body.capabilities).toContain('resources');
expect(response.body.capabilities).toContain('tools');
});
});
describe('404 handling', () => {
it('should return 404 for unknown routes', async () => {
const response = await request(app).get('/unknown-route');
expect(response.status).toBe(404);
expect(response.body).toEqual({
error: 'Not found',
path: '/unknown-route',
});
});
it('should handle POST to unknown routes', async () => {
const response = await request(app).post('/unknown-route').send({});
expect(response.status).toBe(404);
});
});
describe('Port validation', () => {
it('should reject invalid port numbers', () => {
const originalPort = process.env.HTTP_PORT;
// Test invalid port
process.env.HTTP_PORT = 'invalid';
// In real server, this would cause exit(1)
// For testing, we just verify the logic exists
const port = parseInt(process.env.HTTP_PORT, 10);
expect(isNaN(port)).toBe(true);
process.env.HTTP_PORT = originalPort;
});
it('should reject out-of-range ports', () => {
const originalPort = process.env.HTTP_PORT;
// Test port too high
process.env.HTTP_PORT = '99999';
const port = parseInt(process.env.HTTP_PORT, 10);
expect(port > 65535).toBe(true);
process.env.HTTP_PORT = originalPort;
});
});
describe('Environment validation', () => {
it('should require KIBANA_URL', () => {
expect(process.env.KIBANA_URL).toBeDefined();
expect(process.env.KIBANA_URL).toBeTruthy();
});
it('should require authentication', () => {
const hasApiKey = !!process.env.KIBANA_API_KEY;
const hasBasicAuth = !!(
process.env.KIBANA_USERNAME && process.env.KIBANA_PASSWORD
);
expect(hasApiKey || hasBasicAuth).toBe(true);
});
});
});