@ordojs/cli
Version:
Command-line interface for OrdoJS framework
423 lines (377 loc) • 15.9 kB
text/typescript
/**
* @fileoverview Tests for the monitoring generator
*/
import { beforeEach, describe, expect, it } from 'vitest';
import type { DeploymentConfig } from './adapter-interface.js';
import { MonitoringGenerator } from './monitoring-generator.js';
describe('MonitoringGenerator', () => {
let monitoringGenerator: MonitoringGenerator;
let mockDeploymentConfig: DeploymentConfig;
beforeEach(() => {
monitoringGenerator = new MonitoringGenerator();
mockDeploymentConfig = {
outputDir: 'dist',
isStatic: false,
includeServerFunctions: true,
env: {
NODE_ENV: 'production',
PORT: '3000'
}
};
});
describe('generateMonitoringConfig', () => {
it('should generate complete monitoring configuration', () => {
const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig);
expect(config).toHaveProperty('logger');
expect(config).toHaveProperty('metrics');
expect(config).toHaveProperty('tracing');
expect(config).toHaveProperty('healthCheck');
expect(config).toHaveProperty('errorHandler');
expect(config).toHaveProperty('dockerCompose');
expect(config).toHaveProperty('kubernetes');
});
it('should generate structured logging configuration', () => {
const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig, {
structuredLogging: true,
logLevel: 'info'
});
expect(config.logger).toContain('winston.createLogger');
expect(config.logger).toContain('level: \'info\'');
expect(config.logger).toContain('format.timestamp()');
expect(config.logger).toContain('format.json()');
expect(config.logger).toContain('winston.transports.Console');
expect(config.logger).toContain('winston.transports.File');
expect(config.logger).toContain('requestLogger');
});
it('should generate metrics collection configuration', () => {
const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig, {
metricsCollection: true
});
expect(config.metrics).toContain('prom-client');
expect(config.metrics).toContain('collectDefaultMetrics');
expect(config.metrics).toContain('httpRequestDuration');
expect(config.metrics).toContain('httpRequestTotal');
expect(config.metrics).toContain('activeConnections');
expect(config.metrics).toContain('memoryUsage');
expect(config.metrics).toContain('metricsMiddleware');
expect(config.metrics).toContain('metricsEndpoint');
});
it('should generate distributed tracing configuration', () => {
const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig, {
distributedTracing: true
});
expect(config.tracing).toContain('@opentelemetry/api');
expect(config.tracing).toContain('@opentelemetry/sdk-trace-node');
expect(config.tracing).toContain('@opentelemetry/exporter-jaeger');
expect(config.tracing).toContain('NodeTracerProvider');
expect(config.tracing).toContain('JaegerExporter');
expect(config.tracing).toContain('tracingMiddleware');
expect(config.tracing).toContain('createSpan');
});
it('should generate health check configuration', () => {
const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig, {
healthChecks: true
});
expect(config.healthCheck).toContain('createHealthCheck');
expect(config.healthCheck).toContain('healthChecks');
expect(config.healthCheck).toContain('database:');
expect(config.healthCheck).toContain('redis:');
expect(config.healthCheck).toContain('external:');
expect(config.healthCheck).toContain('healthCheckMiddleware');
expect(config.healthCheck).toContain('healthCheckEndpoint');
});
it('should generate error handler configuration', () => {
const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig, {
errorReporting: true
});
expect(config.errorHandler).toContain('errorHandler');
expect(config.errorHandler).toContain('asyncHandler');
expect(config.errorHandler).toContain('unhandledRejection');
expect(config.errorHandler).toContain('uncaughtException');
expect(config.errorHandler).toContain('logger.error');
expect(config.errorHandler).toContain('span.setStatus');
});
it('should generate Docker Compose monitoring services', () => {
const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig, {
integrations: {
prometheus: true,
grafana: true,
jaeger: true
}
});
expect(config.dockerCompose).toContain('version: \'3.8\'');
expect(config.dockerCompose).toContain('prometheus:');
expect(config.dockerCompose).toContain('grafana:');
expect(config.dockerCompose).toContain('jaeger:');
expect(config.dockerCompose).toContain('redis:');
expect(config.dockerCompose).toContain('image: prom/prometheus:latest');
expect(config.dockerCompose).toContain('image: grafana/grafana:latest');
expect(config.dockerCompose).toContain('image: jaegertracing/all-in-one:latest');
expect(config.dockerCompose).toContain('image: redis:alpine');
});
it('should generate Kubernetes monitoring manifests', () => {
const config = monitoringGenerator.generateMonitoringConfig(mockDeploymentConfig, {
integrations: {
prometheus: true,
grafana: true,
jaeger: true
}
});
expect(config.kubernetes).toContain('apiVersion: v1');
expect(config.kubernetes).toContain('kind: ConfigMap');
expect(config.kubernetes).toContain('name: prometheus-config');
expect(config.kubernetes).toContain('kind: Deployment');
expect(config.kubernetes).toContain('name: prometheus');
expect(config.kubernetes).toContain('name: grafana');
expect(config.kubernetes).toContain('name: jaeger');
expect(config.kubernetes).toContain('kind: Service');
expect(config.kubernetes).toContain('kind: PersistentVolumeClaim');
});
});
describe('generateLoggerConfig', () => {
it('should generate Winston logger configuration', () => {
const config = {
structuredLogging: true,
logLevel: 'info',
metricsCollection: true,
distributedTracing: true,
errorReporting: true,
healthChecks: true,
performanceMonitoring: true,
alerting: true,
integrations: {
datadog: false,
newrelic: false,
sentry: false,
prometheus: true,
grafana: true
}
};
const loggerConfig = monitoringGenerator.generateLoggerConfig(config);
expect(loggerConfig).toContain('import winston from \'winston\'');
expect(loggerConfig).toContain('winston.createLogger');
expect(loggerConfig).toContain('level: \'info\'');
expect(loggerConfig).toContain('format.timestamp()');
expect(loggerConfig).toContain('format.errors({ stack: true })');
expect(loggerConfig).toContain('format.json()');
expect(loggerConfig).toContain('winston.transports.Console');
expect(loggerConfig).toContain('winston.transports.File');
expect(loggerConfig).toContain('requestLogger');
expect(loggerConfig).toContain('export default logger');
});
it('should use custom log level', () => {
const config = {
...monitoringGenerator['defaultConfig'],
logLevel: 'debug'
};
const loggerConfig = monitoringGenerator.generateLoggerConfig(config);
expect(loggerConfig).toContain('level: \'debug\'');
});
});
describe('generateMetricsConfig', () => {
it('should generate Prometheus metrics configuration', () => {
const config = {
structuredLogging: true,
logLevel: 'info',
metricsCollection: true,
distributedTracing: true,
errorReporting: true,
healthChecks: true,
performanceMonitoring: true,
alerting: true,
integrations: {
datadog: false,
newrelic: false,
sentry: false,
prometheus: true,
grafana: true
}
};
const metricsConfig = monitoringGenerator.generateMetricsConfig(config);
expect(metricsConfig).toContain('import prometheus from \'prom-client\'');
expect(metricsConfig).toContain('collectDefaultMetrics');
expect(metricsConfig).toContain('httpRequestDuration');
expect(metricsConfig).toContain('httpRequestTotal');
expect(metricsConfig).toContain('activeConnections');
expect(metricsConfig).toContain('memoryUsage');
expect(metricsConfig).toContain('metricsMiddleware');
expect(metricsConfig).toContain('metricsEndpoint');
expect(metricsConfig).toContain('setInterval');
});
});
describe('generateTracingConfig', () => {
it('should generate OpenTelemetry tracing configuration', () => {
const config = {
structuredLogging: true,
logLevel: 'info',
metricsCollection: true,
distributedTracing: true,
errorReporting: true,
healthChecks: true,
performanceMonitoring: true,
alerting: true,
integrations: {
datadog: false,
newrelic: false,
sentry: false,
prometheus: true,
grafana: true
}
};
const tracingConfig = monitoringGenerator.generateTracingConfig(config);
expect(tracingConfig).toContain('@opentelemetry/api');
expect(tracingConfig).toContain('@opentelemetry/sdk-trace-node');
expect(tracingConfig).toContain('@opentelemetry/exporter-jaeger');
expect(tracingConfig).toContain('NodeTracerProvider');
expect(tracingConfig).toContain('JaegerExporter');
expect(tracingConfig).toContain('BatchSpanProcessor');
expect(tracingConfig).toContain('registerInstrumentations');
expect(tracingConfig).toContain('tracingMiddleware');
expect(tracingConfig).toContain('createSpan');
expect(tracingConfig).toContain('export { tracer }');
});
});
describe('generateHealthCheckConfig', () => {
it('should generate health check configuration', () => {
const config = {
structuredLogging: true,
logLevel: 'info',
metricsCollection: true,
distributedTracing: true,
errorReporting: true,
healthChecks: true,
performanceMonitoring: true,
alerting: true,
integrations: {
datadog: false,
newrelic: false,
sentry: false,
prometheus: true,
grafana: true
}
};
const healthCheckConfig = monitoringGenerator.generateHealthCheckConfig(config);
expect(healthCheckConfig).toContain('createHealthCheck');
expect(healthCheckConfig).toContain('healthChecks');
expect(healthCheckConfig).toContain('database:');
expect(healthCheckConfig).toContain('redis:');
expect(healthCheckConfig).toContain('external:');
expect(healthCheckConfig).toContain('healthCheckMiddleware');
expect(healthCheckConfig).toContain('healthCheckEndpoint');
expect(healthCheckConfig).toContain('status: \'healthy\'');
expect(healthCheckConfig).toContain('status: \'unhealthy\'');
});
});
describe('generateErrorHandlerConfig', () => {
it('should generate error handler configuration', () => {
const config = {
structuredLogging: true,
logLevel: 'info',
metricsCollection: true,
distributedTracing: true,
errorReporting: true,
healthChecks: true,
performanceMonitoring: true,
alerting: true,
integrations: {
datadog: false,
newrelic: false,
sentry: false,
prometheus: true,
grafana: true
}
};
const errorHandlerConfig = monitoringGenerator.generateErrorHandlerConfig(config);
expect(errorHandlerConfig).toContain('import logger from \'./logger.js\'');
expect(errorHandlerConfig).toContain('import { tracer } from \'./tracing.js\'');
expect(errorHandlerConfig).toContain('errorHandler');
expect(errorHandlerConfig).toContain('asyncHandler');
expect(errorHandlerConfig).toContain('unhandledRejection');
expect(errorHandlerConfig).toContain('uncaughtException');
expect(errorHandlerConfig).toContain('logger.error');
expect(errorHandlerConfig).toContain('span.setStatus');
expect(errorHandlerConfig).toContain('process.exit(1)');
});
});
describe('generateDockerComposeMonitoring', () => {
it('should generate Docker Compose monitoring services', () => {
const config = {
structuredLogging: true,
logLevel: 'info',
metricsCollection: true,
distributedTracing: true,
errorReporting: true,
healthChecks: true,
performanceMonitoring: true,
alerting: true,
integrations: {
datadog: false,
newrelic: false,
sentry: false,
prometheus: true,
grafana: true
}
};
const dockerCompose = monitoringGenerator.generateDockerComposeMonitoring(config);
expect(dockerCompose).toContain('version: \'3.8\'');
expect(dockerCompose).toContain('services:');
expect(dockerCompose).toContain('prometheus:');
expect(dockerCompose).toContain('grafana:');
expect(dockerCompose).toContain('jaeger:');
expect(dockerCompose).toContain('redis:');
expect(dockerCompose).toContain('image: prom/prometheus:latest');
expect(dockerCompose).toContain('image: grafana/grafana:latest');
expect(dockerCompose).toContain('image: jaegertracing/all-in-one:latest');
expect(dockerCompose).toContain('image: redis:alpine');
expect(dockerCompose).toContain('volumes:');
expect(dockerCompose).toContain('restart: unless-stopped');
});
});
describe('generateKubernetesMonitoring', () => {
it('should generate Kubernetes monitoring manifests', () => {
const config = {
structuredLogging: true,
logLevel: 'info',
metricsCollection: true,
distributedTracing: true,
errorReporting: true,
healthChecks: true,
performanceMonitoring: true,
alerting: true,
integrations: {
datadog: false,
newrelic: false,
sentry: false,
prometheus: true,
grafana: true
}
};
const kubernetes = monitoringGenerator.generateKubernetesMonitoring(config);
expect(kubernetes).toContain('apiVersion: v1');
expect(kubernetes).toContain('kind: ConfigMap');
expect(kubernetes).toContain('name: prometheus-config');
expect(kubernetes).toContain('kind: Deployment');
expect(kubernetes).toContain('name: prometheus');
expect(kubernetes).toContain('name: grafana');
expect(kubernetes).toContain('name: jaeger');
expect(kubernetes).toContain('kind: Service');
expect(kubernetes).toContain('kind: PersistentVolumeClaim');
expect(kubernetes).toContain('replicas: 1');
expect(kubernetes).toContain('containerPort: 9090');
expect(kubernetes).toContain('containerPort: 3000');
expect(kubernetes).toContain('containerPort: 16686');
});
});
describe('error handling', () => {
it('should throw CLIError when monitoring config generation fails', () => {
// Mock a scenario that would cause generation to fail
const invalidConfig = {
...mockDeploymentConfig,
outputDir: null as any
};
expect(() => {
monitoringGenerator.generateMonitoringConfig(invalidConfig);
}).toThrow();
});
});
});