UNPKG

network-performance-analyzer

Version:

Automated analysis tool for network performance test datasets containing DNS testing results and iperf3 performance measurements

472 lines 17.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.DataValidator = void 0; /** * Data validator class for validating input data */ class DataValidator { /** * Creates a new DataValidator instance * @param errorHandler Error handler for logging validation errors */ constructor(errorHandler) { this.errorHandler = errorHandler; } /** * Validates a dataset object * @param dataset The dataset to validate * @returns Validation result */ validateDataset(dataset) { const errors = []; // Check required fields if (!dataset.name) { errors.push({ field: 'name', message: 'Dataset name is required', severity: 'error' }); } if (!dataset.parametersFile) { errors.push({ field: 'parametersFile', message: 'Parameters file path is missing (optional if results file exists)', severity: 'warning' }); } if (!dataset.resultsFile) { errors.push({ field: 'resultsFile', message: 'Results file path is required', severity: 'error' }); } // Validate configuration if (!dataset.configuration) { errors.push({ field: 'configuration', message: 'Configuration is required', severity: 'error' }); } else { // Validate MTU if (typeof dataset.configuration.mtu !== 'number' || dataset.configuration.mtu <= 0) { errors.push({ field: 'configuration.mtu', message: 'MTU must be a positive number', severity: 'error' }); } // Validate AWS logging if (typeof dataset.configuration.awsLogging !== 'boolean') { errors.push({ field: 'configuration.awsLogging', message: 'AWS logging must be a boolean', severity: 'error' }); } // Validate backend server if (!dataset.configuration.backendServer) { errors.push({ field: 'configuration.backendServer', message: 'Backend server is required', severity: 'warning' }); } // Validate test date if (!dataset.configuration.testDate) { errors.push({ field: 'configuration.testDate', message: 'Test date is required', severity: 'warning' }); } } const isValid = errors.filter(e => e.severity === 'error').length === 0; if (!isValid) { this.errorHandler.handleValidationError(new Error(`Dataset validation failed with ${errors.length} errors`), 'Dataset', dataset.name || 'unknown'); } return { isValid, data: isValid ? dataset : null, errors }; } /** * Validates test parameters * @param params The test parameters to validate * @returns Validation result */ validateTestParameters(params) { const errors = []; // Check required fields if (!params.backendServer) { errors.push({ field: 'backendServer', message: 'Backend server is required', severity: 'warning' }); } // Validate MTU if (typeof params.mtu !== 'number' || params.mtu <= 0) { errors.push({ field: 'mtu', message: 'MTU must be a positive number', severity: 'error' }); } // Validate query logging if (params.queryLogging !== 'enabled' && params.queryLogging !== 'disabled') { errors.push({ field: 'queryLogging', message: "Query logging must be 'enabled' or 'disabled'", severity: 'error' }); } const isValid = errors.filter(e => e.severity === 'error').length === 0; if (!isValid) { this.errorHandler.handleValidationError(new Error(`Test parameters validation failed with ${errors.length} errors`), 'TestParameters', 'unknown'); } return { isValid, data: isValid ? params : null, errors }; } /** * Validates test results * @param results The test results to validate * @returns Validation result */ validateTestResults(results) { const errors = []; // Check if iperfTests array exists if (!Array.isArray(results.iperfTests)) { errors.push({ field: 'iperfTests', message: 'iperfTests must be an array', severity: 'error' }); } else { // Validate each iperf test result results.iperfTests.forEach((test, index) => { const iperfErrors = this.validateIperfTestResult(test); iperfErrors.forEach(error => { errors.push({ field: `iperfTests[${index}].${error.field}`, message: error.message, severity: error.severity }); }); }); } // Check if dnsResults array exists if (!Array.isArray(results.dnsResults)) { errors.push({ field: 'dnsResults', message: 'dnsResults must be an array', severity: 'error' }); } else { // Validate each DNS test result results.dnsResults.forEach((test, index) => { const dnsErrors = this.validateDnsTestResult(test); dnsErrors.forEach(error => { errors.push({ field: `dnsResults[${index}].${error.field}`, message: error.message, severity: error.severity }); }); }); } const isValid = errors.filter(e => e.severity === 'error').length === 0; if (!isValid) { this.errorHandler.handleValidationError(new Error(`Test results validation failed with ${errors.length} errors`), 'TestResults', 'unknown'); } return { isValid, data: isValid ? this.sanitizeTestResults(results) : null, errors }; } /** * Validates an iperf test result * @param test The iperf test result to validate * @returns Array of validation errors */ validateIperfTestResult(test) { const errors = []; // Check required fields if (!test.server) { errors.push({ field: 'server', message: 'Server is required', severity: 'error' }); } if (!test.scenario) { errors.push({ field: 'scenario', message: 'Scenario is required', severity: 'error' }); } // Validate success flag if (typeof test.success !== 'boolean') { errors.push({ field: 'success', message: 'Success must be a boolean', severity: 'error' }); } // If test failed, ensure error message exists if (test.success === false && !test.error) { errors.push({ field: 'error', message: 'Error message is required for failed tests', severity: 'warning' }); } // Validate numeric fields if they exist if (test.startTime !== undefined && (typeof test.startTime !== 'number' || test.startTime < 0)) { errors.push({ field: 'startTime', message: 'Start time must be a non-negative number', severity: 'warning' }); } if (test.endTime !== undefined && (typeof test.endTime !== 'number' || test.endTime < 0)) { errors.push({ field: 'endTime', message: 'End time must be a non-negative number', severity: 'warning' }); } if (test.duration !== undefined && (typeof test.duration !== 'number' || test.duration <= 0)) { errors.push({ field: 'duration', message: 'Duration must be a positive number', severity: 'warning' }); } // Validate bandwidth if (test.success && test.bandwidthMbps !== undefined && (typeof test.bandwidthMbps !== 'number' || test.bandwidthMbps < 0)) { errors.push({ field: 'bandwidthMbps', message: 'Bandwidth must be a non-negative number', severity: 'error' }); } return errors; } /** * Validates a DNS test result * @param test The DNS test result to validate * @returns Array of validation errors */ validateDnsTestResult(test) { const errors = []; // Check required fields if (!test.domain) { errors.push({ field: 'domain', message: 'Domain is required', severity: 'error' }); } if (!test.dnsServer) { errors.push({ field: 'dnsServer', message: 'DNS server is required', severity: 'error' }); } // Validate success flag if (typeof test.success !== 'boolean') { errors.push({ field: 'success', message: 'Success must be a boolean', severity: 'error' }); } // If test failed, ensure error message exists if (test.success === false && !test.error) { errors.push({ field: 'error', message: 'Error message is required for failed tests', severity: 'warning' }); } // Validate response time if (test.success && test.responseTimeMs !== undefined && (typeof test.responseTimeMs !== 'number' || test.responseTimeMs < 0)) { errors.push({ field: 'responseTimeMs', message: 'Response time must be a non-negative number', severity: 'error' }); } // Validate query time if (test.success && test.queryTimeMs !== undefined && (typeof test.queryTimeMs !== 'number' || test.queryTimeMs < 0)) { errors.push({ field: 'queryTimeMs', message: 'Query time must be a non-negative number', severity: 'warning' }); } // Validate resolved IPs if (test.success && test.resolvedIps !== undefined && !Array.isArray(test.resolvedIps)) { errors.push({ field: 'resolvedIps', message: 'Resolved IPs must be an array', severity: 'warning' }); } return errors; } /** * Sanitizes test results by removing invalid data and providing defaults * @param results The test results to sanitize * @returns Sanitized test results */ sanitizeTestResults(results) { const sanitized = { iperfTests: [], dnsResults: [] }; // Sanitize iperf tests if (Array.isArray(results.iperfTests)) { sanitized.iperfTests = results.iperfTests .filter(test => test && typeof test === 'object') .map(test => this.sanitizeIperfTestResult(test)); } // Sanitize DNS results if (Array.isArray(results.dnsResults)) { sanitized.dnsResults = results.dnsResults .filter(test => test && typeof test === 'object') .map(test => this.sanitizeDnsTestResult(test)); } return sanitized; } /** * Sanitizes an iperf test result * @param test The iperf test result to sanitize * @returns Sanitized iperf test result */ sanitizeIperfTestResult(test) { const sanitized = { server: test.server || 'unknown', scenario: test.scenario || 'unknown', success: typeof test.success === 'boolean' ? test.success : false }; // Copy valid properties if (typeof test.startTime === 'number' && test.startTime >= 0) { sanitized.startTime = test.startTime; } if (typeof test.endTime === 'number' && test.endTime >= 0) { sanitized.endTime = test.endTime; } if (typeof test.duration === 'number' && test.duration > 0) { sanitized.duration = test.duration; } else if (sanitized.startTime !== undefined && sanitized.endTime !== undefined) { sanitized.duration = sanitized.endTime - sanitized.startTime; } if (typeof test.numStreams === 'number' && test.numStreams > 0) { sanitized.numStreams = test.numStreams; } if (typeof test.cpuUtilizationHost === 'number' && test.cpuUtilizationHost >= 0) { sanitized.cpuUtilizationHost = test.cpuUtilizationHost; } if (typeof test.cpuUtilizationRemote === 'number' && test.cpuUtilizationRemote >= 0) { sanitized.cpuUtilizationRemote = test.cpuUtilizationRemote; } // TCP specific if (typeof test.tcpMssDefault === 'number' && test.tcpMssDefault > 0) { sanitized.tcpMssDefault = test.tcpMssDefault; } if (typeof test.retransmits === 'number' && test.retransmits >= 0) { sanitized.retransmits = test.retransmits; } if (typeof test.sndCwnd === 'number' && test.sndCwnd > 0) { sanitized.sndCwnd = test.sndCwnd; } // UDP specific if (typeof test.jitterMs === 'number' && test.jitterMs >= 0) { sanitized.jitterMs = test.jitterMs; } if (typeof test.packets === 'number' && test.packets >= 0) { sanitized.packets = test.packets; } if (typeof test.lostPackets === 'number' && test.lostPackets >= 0) { sanitized.lostPackets = test.lostPackets; } if (typeof test.packetLoss === 'number' && test.packetLoss >= 0) { sanitized.packetLoss = test.packetLoss; } else if (sanitized.packets && sanitized.lostPackets) { sanitized.packetLoss = (sanitized.lostPackets / sanitized.packets) * 100; } // Common metrics if (typeof test.blksize === 'number' && test.blksize > 0) { sanitized.blksize = test.blksize; } if (typeof test.bytes === 'number' && test.bytes >= 0) { sanitized.bytes = test.bytes; } if (typeof test.bitsPerSecond === 'number' && test.bitsPerSecond >= 0) { sanitized.bitsPerSecond = test.bitsPerSecond; } if (typeof test.bandwidthMbps === 'number' && test.bandwidthMbps >= 0) { sanitized.bandwidthMbps = test.bandwidthMbps; } else if (sanitized.bitsPerSecond) { sanitized.bandwidthMbps = sanitized.bitsPerSecond / 1000000; } if (test.error) { sanitized.error = test.error; } // Keep raw data if available if (test.allRawData) { sanitized.allRawData = test.allRawData; } return sanitized; } /** * Sanitizes a DNS test result * @param test The DNS test result to sanitize * @returns Sanitized DNS test result */ sanitizeDnsTestResult(test) { const sanitized = { domain: test.domain || 'unknown', dnsServer: test.dnsServer || 'unknown', success: typeof test.success === 'boolean' ? test.success : false }; // Copy valid properties if (typeof test.responseTimeMs === 'number' && test.responseTimeMs >= 0) { sanitized.responseTimeMs = test.responseTimeMs; } if (typeof test.queryTimeMs === 'number' && test.queryTimeMs >= 0) { sanitized.queryTimeMs = test.queryTimeMs; } if (test.status) { sanitized.status = test.status; } if (Array.isArray(test.resolvedIps)) { sanitized.resolvedIps = test.resolvedIps.filter(ip => typeof ip === 'string'); } if (test.error) { sanitized.error = test.error; } return sanitized; } } exports.DataValidator = DataValidator; //# sourceMappingURL=DataValidator.js.map