From 833dbce5bbff25bc1ff784e2ddecfd068fc14787 Mon Sep 17 00:00:00 2001 From: Matatjahu Date: Thu, 25 Aug 2022 16:16:08 +0200 Subject: [PATCH] add tests for schema parsing --- src/custom-operations/parse-schema.ts | 5 +- src/parse.ts | 5 +- src/parser.ts | 2 + src/utils.ts | 4 + test/custom-operations/parse-schema.spec.ts | 96 +++++++++++++++++++ .../asyncapi-schema-parser.spec.ts | 1 - test/schema-parser/spectral-rule-v2.spec.ts | 46 ++++++--- 7 files changed, 139 insertions(+), 20 deletions(-) create mode 100644 test/custom-operations/parse-schema.spec.ts diff --git a/src/custom-operations/parse-schema.ts b/src/custom-operations/parse-schema.ts index fcb44ef74..6fb36bb77 100644 --- a/src/custom-operations/parse-schema.ts +++ b/src/custom-operations/parse-schema.ts @@ -2,7 +2,7 @@ import { JSONPath } from 'jsonpath-plus'; import { toPath } from 'lodash'; import { parseSchema, getSchemaFormat, getDefaultSchemaFormat } from '../schema-parser'; -import { xParserOriginalSchemaFormat, xParserOriginalPayload } from '../constants'; +import { xParserOriginalPayload } from '../constants'; import type { Parser } from '../parser'; import type { ParseSchemaInput } from "../schema-parser"; @@ -67,7 +67,6 @@ export async function parseSchemasV2(parser: Parser, detailed: DetailedAsyncAPI) } async function parseSchemaV2(parser: Parser, item: ToParseItem) { - item.value[xParserOriginalSchemaFormat] = item.input.schemaFormat; - item.value[xParserOriginalPayload] = item.input; + item.value[xParserOriginalPayload] = item.input.data; item.value.payload = await parseSchema(parser, item.input); } diff --git a/src/parse.ts b/src/parse.ts index 80c952e84..fb7d6822a 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -2,7 +2,7 @@ import { AsyncAPIDocumentInterface, newAsyncAPIDocument } from "./models"; import { customOperations } from './custom-operations'; import { validate } from "./lint"; -import { createDetailedAsyncAPI, normalizeInput, toAsyncAPIDocument } from "./utils"; +import { createDetailedAsyncAPI, normalizeInput, toAsyncAPIDocument, unfreezeObject } from "./utils"; import { xParserSpecParsed } from './constants'; @@ -47,7 +47,7 @@ export async function parse(parser: Parser, asyncapi: ParseInput, options?: Pars } // unfreeze the object - Spectral makes resolved document "freezed" - const validatedDoc = JSON.parse(JSON.stringify(validated)); + const validatedDoc = unfreezeObject(validated); validatedDoc[String(xParserSpecParsed)] = true; const detailed = createDetailedAsyncAPI(asyncapi as string | Record, validatedDoc); @@ -67,6 +67,7 @@ export async function parse(parser: Parser, asyncapi: ParseInput, options?: Pars const defaultOptions: ParseOptions = { applyTraits: true, + parseSchemas: true, }; function normalizeOptions(options?: ParseOptions): ParseOptions { if (!options || typeof options !== 'object') { diff --git a/src/parser.ts b/src/parser.ts index 8692ce55e..5681e5047 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -3,6 +3,7 @@ import { Spectral } from "@stoplight/spectral-core"; import { parse } from "./parse"; import { lint, validate } from "./lint"; import { registerSchemaParser } from './schema-parser'; +import { AsyncAPISchemaParser } from "./schema-parser/asyncapi-schema-parser"; import { configureSpectral } from "./spectral"; import type { IConstructorOpts } from "@stoplight/spectral-core"; @@ -28,6 +29,7 @@ export class Parser { this.spectral = new Spectral(spectral); } + this.registerSchemaParser(AsyncAPISchemaParser()); configureSpectral(this); } diff --git a/src/utils.ts b/src/utils.ts index f2ea335d2..48c0cd5f1 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -68,6 +68,10 @@ export function normalizeInput(asyncapi: string | MaybeAsyncAPI): string { return JSON.stringify(asyncapi, undefined, 2); }; +export function unfreezeObject(data: unknown) { + return JSON.parse(JSON.stringify(data)) +} + export function hasErrorDiagnostic(diagnostics: ISpectralDiagnostic[]): boolean { return diagnostics.some(diagnostic => diagnostic.severity === DiagnosticSeverity.Error); } diff --git a/test/custom-operations/parse-schema.spec.ts b/test/custom-operations/parse-schema.spec.ts new file mode 100644 index 000000000..08ba25a8a --- /dev/null +++ b/test/custom-operations/parse-schema.spec.ts @@ -0,0 +1,96 @@ +import { AsyncAPIDocumentV2 } from '../../src/models'; +import { Parser } from '../../src/parser'; +import { parse } from '../../src/parse'; +import { xParserOriginalPayload } from '../../src/constants'; + +describe('custom operations - parse schemas', function() { + const parser = new Parser(); + + it('should parse valid schema format', async function() { + const document = { + asyncapi: '2.0.0', + info: { + title: 'Valid AsyncApi document', + version: '1.0', + }, + channels: { + channel: { + publish: { + operationId: 'operationId', + message: { + schemaFormat: 'application/vnd.aai.asyncapi;version=2.0.0', + payload: { + type: 'object', + } + } + } + } + } + } + const { parsed, diagnostics } = await parse(parser, document); + + expect(parsed).toBeInstanceOf(AsyncAPIDocumentV2); + expect(diagnostics.length > 0).toEqual(true); + + expect(parsed?.json()['channels']['channel']['publish']['message']['payload']).toEqual({ type: 'object' }); + expect(parsed?.json()['channels']['channel']['publish']['message'][xParserOriginalPayload]).toEqual({ type: 'object' }); + expect(parsed?.json()['channels']['channel']['publish']['message']['payload']).toEqual(parsed?.json()['channels']['channel']['publish']['message'][xParserOriginalPayload]); + }); + + it('should parse valid default schema format', async function() { + const document = { + asyncapi: '2.0.0', + info: { + title: 'Valid AsyncApi document', + version: '1.0', + }, + channels: { + channel: { + publish: { + operationId: 'operationId', + message: { + payload: { + type: 'object', + } + } + } + } + } + } + const { parsed, diagnostics } = await parse(parser, document); + + expect(parsed).toBeInstanceOf(AsyncAPIDocumentV2); + expect(diagnostics.length > 0).toEqual(true); + + expect(parsed?.json()['channels']['channel']['publish']['message']['payload']).toEqual({ type: 'object' }); + expect(parsed?.json()['channels']['channel']['publish']['message'][xParserOriginalPayload]).toEqual({ type: 'object' }); + expect(parsed?.json()['channels']['channel']['publish']['message']['payload']).toEqual(parsed?.json()['channels']['channel']['publish']['message'][xParserOriginalPayload]); + }); + + it('should parse invalid schema format', async function() { + const document = { + asyncapi: '2.0.0', + info: { + title: 'Valid AsyncApi document', + version: '1.0', + }, + channels: { + channel: { + publish: { + operationId: 'operationId', + message: { + schemaFormat: 'not existing', + payload: { + type: 'object', + } + } + } + } + } + } + const { parsed, diagnostics } = await parse(parser, document); + + expect(parsed).toBeUndefined(); + expect(diagnostics.length > 0).toEqual(true); + }); +}); diff --git a/test/schema-parser/asyncapi-schema-parser.spec.ts b/test/schema-parser/asyncapi-schema-parser.spec.ts index 26be8359e..58867f01b 100644 --- a/test/schema-parser/asyncapi-schema-parser.spec.ts +++ b/test/schema-parser/asyncapi-schema-parser.spec.ts @@ -4,7 +4,6 @@ import { AsyncAPISchemaParser } from '../../src/schema-parser/asyncapi-schema-pa import type { SchemaValidateResult } from '../../src/types'; describe('AsyncAPISchemaParser', function () { - const validSchema = { asyncapi: { semver: { diff --git a/test/schema-parser/spectral-rule-v2.spec.ts b/test/schema-parser/spectral-rule-v2.spec.ts index bb4af0842..26208a348 100644 --- a/test/schema-parser/spectral-rule-v2.spec.ts +++ b/test/schema-parser/spectral-rule-v2.spec.ts @@ -1,13 +1,11 @@ import { Parser } from '../../src/parser'; import { validate } from '../../src/lint'; -import { AsyncAPISchemaParser } from '../../src/schema-parser/asyncapi-schema-parser'; import type { ISpectralDiagnostic } from '@stoplight/spectral-core'; import type { SchemaValidateResult } from '../../src/types'; describe('aas2schemaParserRule', function() { const parser = new Parser(); - parser.registerSchemaParser(AsyncAPISchemaParser()); // use that parser for testing it('should validate AsyncAPI Schema with valid schema', async function() { const document = { @@ -37,7 +35,7 @@ describe('aas2schemaParserRule', function() { const document = { asyncapi: '2.0.0', info: { - title: 'Valid AsyncApi document', + title: 'Invalid AsyncApi document', version: '1.0', }, channels: { @@ -78,7 +76,7 @@ describe('aas2schemaParserRule', function() { const document = { asyncapi: '2.0.0', info: { - title: 'Valid AsyncApi document', + title: 'Invalid AsyncApi document', version: '1.0', }, channels: {}, @@ -118,7 +116,7 @@ describe('aas2schemaParserRule', function() { const document = { asyncapi: '2.0.0', info: { - title: 'Valid AsyncApi document', + title: 'Invalid AsyncApi document', version: '1.0', }, channels: {}, @@ -162,7 +160,7 @@ describe('aas2schemaParserRule', function() { const document = { asyncapi: '2.0.0', info: { - title: 'Valid AsyncApi document', + title: 'Invalid AsyncApi document', version: '1.0', }, channels: { @@ -212,25 +210,45 @@ describe('aas2schemaParserRule', function() { expect(filteredDiagnostics).toEqual(expectedResult.map(e => expect.objectContaining(e))); }); - it('should validate AsyncAPI Schema with non supported schema format', async function() { + it('should validate AsyncAPI Schema with supported schema format', async function() { const document = { asyncapi: '2.0.0', info: { title: 'Valid AsyncApi document', version: '1.0', }, + channels: { + channel: { + publish: { + message: { + schemaFormat: 'application/vnd.aai.asyncapi;version=2.0.0', + payload: { + type: 'object', + } + } + } + } + } + } + const { diagnostics } = await validate(parser, document); + const filteredDiagnostics = filterDiagnostics(diagnostics, 'asyncapi-schemas-v2'); + expect(filteredDiagnostics).toHaveLength(0); + }); + + it('should validate AsyncAPI Schema with non supported schema format', async function() { + const document = { + asyncapi: '2.0.0', + info: { + title: 'Invalid AsyncApi document', + version: '1.0', + }, channels: { channel: { publish: { message: { schemaFormat: 'not existing', payload: { - oneOf: "this should be an array", - properties: { - name: { - if: "this should be an if" - } - } + type: 'object', } } } @@ -254,7 +272,7 @@ describe('aas2schemaParserRule', function() { const document = { asyncapi: '2.0.0', info: { - title: 'Valid AsyncApi document', + title: 'Invalid AsyncApi document', version: '1.0', }, channels: {