From 59a2acef57931f1e7a3c096a7b7e1a5717350c74 Mon Sep 17 00:00:00 2001 From: Matatjahu Date: Thu, 24 Mar 2022 17:14:30 +0100 Subject: [PATCH] add tests for convert service --- .eslintignore | 1 + openapi.yaml | 2 +- package-lock.json | 20 +++---- package.json | 2 +- src/controllers/convert.controller.ts | 15 ++--- .../tests/convert.controller.test.ts | 8 +-- src/interfaces.ts | 7 ++- .../document-validation.middleware.ts | 6 +- src/services/convert.service.ts | 23 ++++--- src/services/tests/convert.service.test.ts | 60 +++++++++++++++++++ 10 files changed, 103 insertions(+), 41 deletions(-) create mode 100644 src/services/tests/convert.service.test.ts diff --git a/.eslintignore b/.eslintignore index 591f24c44..91c2a7d1a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -2,4 +2,5 @@ node_modules public docs lib +dist build \ No newline at end of file diff --git a/openapi.yaml b/openapi.yaml index 6aca0ffa9..8bd94ecce 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -215,7 +215,7 @@ components: ConvertResponse: type: object properties: - asyncapi: + converted: $ref: '#/components/schemas/AsyncAPIDocument' Problem: type: object diff --git a/package-lock.json b/package-lock.json index ddc2b44c5..664f76314 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", "@asyncapi/avro-schema-parser": "^1.0.1", - "@asyncapi/converter": "^0.9.0", + "@asyncapi/converter": "^0.10.0", "@asyncapi/dotnet-nats-template": "^0.4.5", "@asyncapi/generator": "^1.9.0", "@asyncapi/go-watermill-template": "^0.1.38", @@ -136,13 +136,12 @@ } }, "node_modules/@asyncapi/converter": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@asyncapi/converter/-/converter-0.9.0.tgz", - "integrity": "sha512-fAKrEwFjdMfoO1vwmifr/pe2Trna9QGSVj8GKY+6Nd2X6hs1OLQ+/OXvqhVnecL5ZcPy7t2pjDz3tcpMwV9Cdg==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@asyncapi/converter/-/converter-0.10.0.tgz", + "integrity": "sha512-PY0RdDuUbCjnjOoCPar4ROm2Rwxb90vMhQ9j7nWFUrBXFCAQgdn1VTmA7gSt/sAt1u7COJ7NUPu550yQEARO5w==", "dependencies": { "commander": "^8.3.0", - "js-yaml": "^3.14.1", - "lodash": "^4.17.21" + "js-yaml": "^3.14.1" }, "bin": { "asyncapi-converter": "cli.js" @@ -19101,13 +19100,12 @@ } }, "@asyncapi/converter": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/@asyncapi/converter/-/converter-0.9.0.tgz", - "integrity": "sha512-fAKrEwFjdMfoO1vwmifr/pe2Trna9QGSVj8GKY+6Nd2X6hs1OLQ+/OXvqhVnecL5ZcPy7t2pjDz3tcpMwV9Cdg==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@asyncapi/converter/-/converter-0.10.0.tgz", + "integrity": "sha512-PY0RdDuUbCjnjOoCPar4ROm2Rwxb90vMhQ9j7nWFUrBXFCAQgdn1VTmA7gSt/sAt1u7COJ7NUPu550yQEARO5w==", "requires": { "commander": "^8.3.0", - "js-yaml": "^3.14.1", - "lodash": "^4.17.21" + "js-yaml": "^3.14.1" }, "dependencies": { "argparse": { diff --git a/package.json b/package.json index 056667b86..89580d321 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "dependencies": { "@apidevtools/json-schema-ref-parser": "^9.0.9", "@asyncapi/avro-schema-parser": "^1.0.1", - "@asyncapi/converter": "^0.9.0", + "@asyncapi/converter": "^0.10.0", "@asyncapi/dotnet-nats-template": "^0.4.5", "@asyncapi/generator": "^1.9.0", "@asyncapi/go-watermill-template": "^0.1.38", diff --git a/src/controllers/convert.controller.ts b/src/controllers/convert.controller.ts index 079e1e8e0..3556b383c 100644 --- a/src/controllers/convert.controller.ts +++ b/src/controllers/convert.controller.ts @@ -1,17 +1,15 @@ import { NextFunction, Request, Response, Router } from 'express'; -import { AsyncAPIDocument } from '@asyncapi/parser'; - -import { Controller, SpecsEnum } from '../interfaces'; +import { Controller, AsyncAPIDocument, SpecsEnum } from '../interfaces'; import { documentValidationMiddleware } from '../middlewares/document-validation.middleware'; import { ConvertService } from '../services/convert.service'; import { ProblemException } from '../exceptions/problem.exception'; -import { parse, prepareParserConfig } from '../utils/parser'; type ConvertRequestDto = { + asyncapi: AsyncAPIDocument; /** * Spec version to upgrade to. * Default is 'latest'. @@ -21,7 +19,6 @@ type ConvertRequestDto = { * Language to convert the file to. */ language?: 'json' | 'yaml' | 'yml', - asyncapi: AsyncAPIDocument } /** @@ -35,16 +32,14 @@ export class ConvertController implements Controller { private async convert(req: Request, res: Response, next: NextFunction) { try { const { version, language, asyncapi } = req.body as ConvertRequestDto; - - await parse(asyncapi, prepareParserConfig(req)); - const convertedSpec = await this.convertService.convertSpec( + const convertedSpec = await this.convertService.convert( asyncapi, + version, language, - version.toString(), ); res.json({ - asyncapi: convertedSpec + converted: convertedSpec }); } catch (err: unknown) { if (err instanceof ProblemException) { diff --git a/src/controllers/tests/convert.controller.test.ts b/src/controllers/tests/convert.controller.test.ts index 07fe80d76..1ce90f23c 100644 --- a/src/controllers/tests/convert.controller.test.ts +++ b/src/controllers/tests/convert.controller.test.ts @@ -21,7 +21,6 @@ info: title: Super test version: 1.0.0 channels: {} -x-parser-spec-parsed: true `; describe('ConvertController', () => { @@ -52,7 +51,7 @@ describe('ConvertController', () => { schemaPath: '#/properties/version/enum', keyword: 'enum', params: { - allowedValues: ALL_SPECS + allowedValues: [...ALL_SPECS, 'latest'], }, message: 'must be equal to one of the allowed values' } @@ -87,14 +86,13 @@ describe('ConvertController', () => { version: '2.3.0' }) .expect(200, { - asyncapi: { + converted: { asyncapi: '2.3.0', info: { title: 'Super test', version: '1.0.0' }, channels: {}, - 'x-parser-spec-parsed': true, }, }); }); @@ -110,7 +108,7 @@ describe('ConvertController', () => { language: 'yaml' }) .expect(200, { - asyncapi: validYamlAsyncAPI2_3_0.trimStart(), + converted: validYamlAsyncAPI2_3_0.trimStart(), }); }); }); diff --git a/src/interfaces.ts b/src/interfaces.ts index b77009898..cde0a3724 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -1,5 +1,6 @@ import specs from '@asyncapi/specs'; import { Router } from 'express'; + export interface Controller { basepath: string; boot(): Router; @@ -14,7 +15,9 @@ export interface Problem { [key: string]: any; } -export const ALL_SPECS = [...Object.keys(specs), 'latest']; +export type AsyncAPIDocument = { asyncapi: string } & Record; + +export const ALL_SPECS = [...Object.keys(specs)]; export const LAST_SPEC_VERSION = ALL_SPECS[ALL_SPECS.length - 1]; -export type SpecsEnum = keyof typeof specs; +export type SpecsEnum = keyof typeof specs | 'latest'; diff --git a/src/middlewares/document-validation.middleware.ts b/src/middlewares/document-validation.middleware.ts index f86e6059e..c952233cd 100644 --- a/src/middlewares/document-validation.middleware.ts +++ b/src/middlewares/document-validation.middleware.ts @@ -7,13 +7,15 @@ import { parse, prepareParserConfig, tryConvertToProblemException } from '../uti */ export async function documentValidationMiddleware(req: Request, _: Response, next: NextFunction) { try { - const asyncapi = req.body?.asyncapi; + let asyncapi = req.body?.asyncapi; if (!asyncapi) { return next(); } + if (typeof asyncapi === 'object') { + asyncapi = JSON.parse(JSON.stringify(asyncapi)); + } const parsedDocument = await parse(asyncapi, prepareParserConfig(req)); - req.parsedDocument = parsedDocument; next(); } catch (err: any) { diff --git a/src/services/convert.service.ts b/src/services/convert.service.ts index 4a66c555d..5a00f47f9 100644 --- a/src/services/convert.service.ts +++ b/src/services/convert.service.ts @@ -1,29 +1,34 @@ import { convert } from '@asyncapi/converter'; -import { AsyncAPIDocument } from '@asyncapi/parser'; import YAML from 'js-yaml'; import { ProblemException } from '../exceptions/problem.exception'; -import { LAST_SPEC_VERSION } from '../interfaces'; +import { AsyncAPIDocument, LAST_SPEC_VERSION, SpecsEnum } from '../interfaces'; + +import type { ConvertVersion } from '@asyncapi/converter'; /** * Service providing `@asyncapi/converter` functionality. */ export class ConvertService { /** - * Convert the given spec to the desired language. + * Convert the given spec to the desired version and format. * @param spec AsyncAPI spec * @param language Language to convert to, YAML or JSON - * @param version [version] AsyncAPI spec version + * @param version AsyncAPI spec version * @returns converted spec */ - public async convertSpec( - spec: AsyncAPIDocument | string, - language: 'json' | 'yaml' | 'yml', - version: string = LAST_SPEC_VERSION, + public async convert( + spec: string | AsyncAPIDocument, + version: SpecsEnum = LAST_SPEC_VERSION, + language?: 'json' | 'yaml' | 'yml', ): Promise { + if (version === 'latest') { + version = LAST_SPEC_VERSION; + } + try { const asyncapiSpec = typeof spec === 'object' ? JSON.stringify(spec) : spec; - const convertedSpec = convert(asyncapiSpec, version); + const convertedSpec = convert(asyncapiSpec, version as ConvertVersion); if (!language) { return convertedSpec; diff --git a/src/services/tests/convert.service.test.ts b/src/services/tests/convert.service.test.ts new file mode 100644 index 000000000..29591188d --- /dev/null +++ b/src/services/tests/convert.service.test.ts @@ -0,0 +1,60 @@ +import { ConvertService } from '../convert.service'; +import { ProblemException } from '../../exceptions/problem.exception'; + +const validJsonAsyncAPI2_0_0 = { + asyncapi: '2.0.0', + info: { + title: 'Super test', + version: '1.0.0' + }, + channels: {} +}; + +const validYamlAsyncAPI2_3_0 = ` +asyncapi: 2.3.0 +info: + title: Super test + version: 1.0.0 +channels: {} +`; + +describe('ConvertService', () => { + const convertService = new ConvertService(); + + describe('.convert()', () => { + it('should throw error that the converter cannot convert to a lower version', async () => { + let err: ProblemException; + try { + await convertService.convert(validJsonAsyncAPI2_0_0, '1.2.0'); + } catch (e) { + err = e; + } + + expect(err).toEqual(new ProblemException({ + type: 'internal-converter-error', + title: 'Could not convert document', + status: 422, + detail: 'Cannot downgrade from 2.0.0 to 1.2.0.', + })); + }); + + it('should pass when converting to 2.3.0 version', async () => { + const converted = await convertService.convert(validJsonAsyncAPI2_0_0, '2.3.0'); + + expect(converted).toEqual({ + asyncapi: '2.3.0', + info: { + title: 'Super test', + version: '1.0.0' + }, + channels: {}, + }); + }); + + it('should correctly convert JSON to YAML', async () => { + const converted = await convertService.convert(validJsonAsyncAPI2_0_0, '2.3.0', 'yaml'); + + expect(converted).toEqual(validYamlAsyncAPI2_3_0.trimStart()); + }); + }); +});