UNPKG

@apistudio/apim-cli

Version:

CLI for API Management Products

166 lines (134 loc) 5.18 kB
/** * Copyright Super iPaaS Integration LLC, an IBM Company 2024 */ import JSZip from 'jszip'; import yaml from 'js-yaml'; import { CollectionCreator } from '../newman/newman-collection.builder.js'; import { AssetParser } from '../parsers/asset.parser.js'; import { addErrorToResponse } from '../helpers/helper.js'; import { AppConstants } from '../constants/app.constants.js'; import { YamlValidator } from '../validator/yaml.validator.js'; import { TestManagerInterface, TestSpec } from '../models/interface.js'; import { NewmanRunner } from '../newman/newman-test.js'; import { GatewayAssetHandler } from '../converter/gateway-asset.handler.js'; import { LogWrapper } from '../service/log-wrapper.js'; export class TestManager implements TestManagerInterface { private async validateEndpoints(buffer: Buffer): Promise<boolean> { LogWrapper.logInfo('0204', 'endpoint'); const zipContent = await this.loadZipContent(buffer); for (const [, file] of Object.entries(zipContent.files)) { if (this.isYamlFile(file.name)) { const parsedYamlDatas = await this.parseYamlFile(file); const isValid = await this.validateYamlData(parsedYamlDatas, buffer); if (!isValid) { return false; } } } LogWrapper.logInfo('0206', 'Endpoint'); return true; } private async loadZipContent(buffer: Buffer): Promise<JSZip> { const zip = new JSZip(); return zip.loadAsync(buffer); } private isYamlFile(fileName: string): boolean { return fileName.endsWith('.yaml') || fileName.endsWith('.yml'); } private async parseYamlFile(file: JSZip.JSZipObject): Promise<TestSpec[]> { const data = await file.async('string'); return yaml.loadAll(data) as TestSpec[]; } private async validateYamlData(parsedYamlDatas: TestSpec[], buffer: Buffer): Promise<boolean> { for (const parsedData of parsedYamlDatas) { if (parsedData.kind?.toLowerCase() !== 'test' || !parsedData.kind) { continue; } const apiReference = parsedData.spec.api?.$ref; const endpointReference = parsedData.spec.api?.$endpoint; if (apiReference) { const isValid = await this.validateApiReference(apiReference, buffer); if (!isValid) { return false; } } else if (!endpointReference) { return false; } } return true; } private async validateApiReference(apiReference: string, buffer: Buffer): Promise<boolean> { const gatewayHandler = new GatewayAssetHandler(buffer); const endpoint = await gatewayHandler.getApiEndpoints(apiReference); if (endpoint[0].length === 0) { addErrorToResponse(AppConstants.VALIDATION_ERROR_CODE, 'endpoint', `Invalid or Empty endpoint for reference ${apiReference}`); LogWrapper.logError('0205', apiReference); return false; } return true; } private async validateReferences(buffer: Buffer) { LogWrapper.logInfo('0204', 'reference'); const obj = new AssetParser(); const refMap = await obj.createAssetReferenceMap(buffer); await obj.updateMapWithGatewayEndpoints(buffer, refMap); const allRefsValid = Array.from(refMap.entries()).every(([key, value]) => { if (!value) { addErrorToResponse(AppConstants.VALIDATION_ERROR_CODE, key, `Validation failed for Reference ${key}`); LogWrapper.logError('0207', key); } return value; }); if (!allRefsValid) { LogWrapper.logError('0003', 'Validation failed: Some references are not valid.'); return false; } LogWrapper.logInfo('0206', 'Reference'); return true; } private async validate(buffer: Buffer): Promise<boolean> { LogWrapper.logDebug('0003', 'Starting overall validation process.'); const validateObj = new YamlValidator(); if (!await validateObj.validateYamlFiles(buffer)) { LogWrapper.logError('0004', 'YAML validation failed.'); return false; } if (!await this.validateEndpoints(buffer)) { LogWrapper.logError('0004', 'Endpoint validation failed.'); return false; } if (!await this.validateReferences(buffer)) { LogWrapper.logError('0004', 'Reference validation failed.'); return false; } LogWrapper.logInfo('0003', 'Overall validation process completed successfully.'); return true; } async processFile(buffer: Buffer) { LogWrapper.logInfo('0003', 'Starting file processing.'); if (!await this.validate(buffer)) { LogWrapper.logError('0004', 'File processing aborted due to validation failure.'); return null; } const zipContent = await this.loadZipContent(buffer); const summaries = []; for (const [, file] of Object.entries(zipContent.files)) { const data = await file.async('string'); const parsedYamlDatas = yaml.loadAll(data) as TestSpec[]; for (const parsedData of parsedYamlDatas) { if (parsedData.kind?.toLowerCase() !== 'test') { continue; } LogWrapper.logInfo('0208', file.name); const collectionCreator = new CollectionCreator(); const collection = await collectionCreator.createCollection(parsedData, buffer); const runner = new NewmanRunner(collection); const summary = await runner.run(); summaries.push(summary); LogWrapper.logInfo('0209', file.name); } } LogWrapper.logInfo('0003', 'File processing completed.'); return summaries; } }