UNPKG

@ordojs/cli

Version:

Command-line interface for OrdoJS framework

423 lines (377 loc) 15.9 kB
/** * @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(); }); }); });