From 39afe0d1201a529268fbf9eb7b2e3dd150c6b856 Mon Sep 17 00:00:00 2001 From: "Daniel (dB.) Doubrovkine" Date: Wed, 19 Jun 2024 10:19:10 -0400 Subject: [PATCH] Fail on missing properties. (#342) * Fail on missing properties. Signed-off-by: dblock --- CHANGELOG.md | 1 + package-lock.json | 27 ++++---- package.json | 1 + spec/namespaces/ml.yaml | 6 ++ tools/src/helpers.ts | 6 +- tools/src/linter/SchemaRefsValidator.ts | 2 +- .../linter/components/base/FileValidator.ts | 4 +- tools/src/merger/OpenApiMerger.ts | 6 +- tools/src/tester/ChapterReader.ts | 14 +++- tools/src/tester/MergedOpenApiSpec.ts | 49 ++++++++++++++ tools/src/tester/ResultLogger.ts | 5 -- tools/src/tester/SchemaValidator.ts | 13 +++- tools/src/tester/StoryEvaluator.ts | 3 +- tools/src/tester/test.ts | 9 ++- tools/tests/tester/MergedOpenApiSpec.test.ts | 36 ++++++++++ ...y_outputs.test.ts => StoryOutputs.test.ts} | 0 .../specs/complete/_global_parameters.yaml | 4 ++ .../tester/fixtures/specs/complete/_info.yaml | 5 ++ .../complete/_superseded_operations.yaml | 1 + .../specs/complete/namespaces/index.yaml | 65 +++++++++++++++++++ .../specs/complete/schemas/actions.yaml | 5 ++ tools/tests/tester/helpers.ts | 6 +- 22 files changed, 233 insertions(+), 35 deletions(-) create mode 100644 tools/src/tester/MergedOpenApiSpec.ts create mode 100644 tools/tests/tester/MergedOpenApiSpec.test.ts rename tools/tests/tester/{story_outputs.test.ts => StoryOutputs.test.ts} (100%) create mode 100644 tools/tests/tester/fixtures/specs/complete/_global_parameters.yaml create mode 100644 tools/tests/tester/fixtures/specs/complete/_info.yaml create mode 100644 tools/tests/tester/fixtures/specs/complete/_superseded_operations.yaml create mode 100644 tools/tests/tester/fixtures/specs/complete/namespaces/index.yaml create mode 100644 tools/tests/tester/fixtures/specs/complete/schemas/actions.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index de90a38f5..1e4bb3b3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Added support to read outputs from requests in tests([#324](https://github.com/opensearch-project/opensearch-api-specification/pull/324)) - Added `eslint-plugin-eslint-comments` ([#333](https://github.com/opensearch-project/opensearch-api-specification/pull/333)) - Added `distribution` field to `OpenSearchVersionInfo` ([#336](https://github.com/opensearch-project/opensearch-api-specification/pull/336)) +- Added `created_time` and `last_updated_time` to `ml.get_model_group@200` ([#342](https://github.com/opensearch-project/opensearch-api-specification/pull/342)) ### Changed diff --git a/package-lock.json b/package-lock.json index c2733c976..1dfb29beb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "@eslint/js": "^9.1.1", "@types/jest": "^29.5.12", "@typescript-eslint/eslint-plugin": "^6.21.0", + "ajv-errors": "^3.0.0", "eslint": "^8.57.0", "eslint-config-standard-with-typescript": "^43.0.1", "eslint-plugin-eslint-comments": "^3.2.0", @@ -1826,14 +1827,14 @@ } }, "node_modules/ajv": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.15.0.tgz", - "integrity": "sha512-15BTtQUOsSrmHCy+B4VnAiJAJxJ8IFgu6fcjFQF3jQYZ78nLSQthlFg4ehp+NLIyfvFgOlxNsjKIEhydtFPVHQ==", + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.16.0.tgz", + "integrity": "sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==", "dependencies": { "fast-deep-equal": "^3.1.3", - "fast-uri": "^2.3.0", "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "require-from-string": "^2.0.2", + "uri-js": "^4.4.1" }, "funding": { "type": "github", @@ -1853,6 +1854,15 @@ } } }, + "node_modules/ajv-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", + "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", + "dev": true, + "peerDependencies": { + "ajv": "^8.0.1" + } + }, "node_modules/ajv-formats": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", @@ -3744,11 +3754,6 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, - "node_modules/fast-uri": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-2.3.0.tgz", - "integrity": "sha512-eel5UKGn369gGEWOqBShmFJWfq/xSJvsgDzgLYC845GneayWvXBf0lJCBn5qTABfewy1ZDPoaR5OZCP+kssfuw==" - }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", @@ -6285,7 +6290,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, "engines": { "node": ">=6" } @@ -7237,7 +7241,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "dependencies": { "punycode": "^2.1.0" } diff --git a/package.json b/package.json index ddd263966..52563c920 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "@eslint/js": "^9.1.1", "@types/jest": "^29.5.12", "@typescript-eslint/eslint-plugin": "^6.21.0", + "ajv-errors": "^3.0.0", "eslint": "^8.57.0", "eslint-config-standard-with-typescript": "^43.0.1", "eslint-plugin-eslint-comments": "^3.2.0", diff --git a/spec/namespaces/ml.yaml b/spec/namespaces/ml.yaml index 4e7b09c56..161e613a6 100644 --- a/spec/namespaces/ml.yaml +++ b/spec/namespaces/ml.yaml @@ -177,6 +177,12 @@ components: access: type: string description: The model group access. + created_time: + type: integer + format: int64 + last_updated_time: + type: integer + format: int64 required: - name - latest_version diff --git a/tools/src/helpers.ts b/tools/src/helpers.ts index 790407497..bb95fd253 100644 --- a/tools/src/helpers.ts +++ b/tools/src/helpers.ts @@ -93,8 +93,12 @@ export function write_yaml (file_path: string, content: any): void { })) } +export function to_json(content: any, replacer?: (this: any, key: string, value: any) => any): string { + return JSON.stringify(content, replacer, 2) +} + export function write_json (file_path: string, content: any, replacer?: (this: any, key: string, value: any) => any): void { - write_text(file_path, JSON.stringify(content, replacer, 2)) + write_text(file_path, to_json(content, replacer)) } export async function sleep (ms: number): Promise { diff --git a/tools/src/linter/SchemaRefsValidator.ts b/tools/src/linter/SchemaRefsValidator.ts index f39ec20e0..bf66f4fa8 100644 --- a/tools/src/linter/SchemaRefsValidator.ts +++ b/tools/src/linter/SchemaRefsValidator.ts @@ -28,7 +28,7 @@ export default class SchemaRefsValidator { #find_refs_in_namespaces_folder (): void { const search = (obj: any): void => { - const ref: string = obj.$ref ?? '' + const ref: string = obj?.$ref ?? '' if (ref !== '') { const file = ref.split('#')[0].replace('../', '') const name = ref.split('/').pop() ?? '' diff --git a/tools/src/linter/components/base/FileValidator.ts b/tools/src/linter/components/base/FileValidator.ts index 53a887014..a6f9da82e 100644 --- a/tools/src/linter/components/base/FileValidator.ts +++ b/tools/src/linter/components/base/FileValidator.ts @@ -10,7 +10,7 @@ import ValidatorBase from './ValidatorBase' import { type ValidationError } from 'types' import { type OpenAPIV3 } from 'openapi-types' -import { read_yaml } from '../../../helpers' +import { read_yaml, to_json } from '../../../helpers' import AJV from 'ajv' import addFormats from 'ajv-formats' @@ -65,7 +65,7 @@ export default class FileValidator extends ValidatorBase { addFormats(ajv) const validator = ajv.compile(schema) if (!validator(this.spec())) { - return this.error(`File content does not match JSON schema found in '${json_schema_path}':\n ${JSON.stringify(validator.errors, null, 2)}`) + return this.error(`File content does not match JSON schema found in '${json_schema_path}':\n ${to_json(validator.errors)}`) } } } diff --git a/tools/src/merger/OpenApiMerger.ts b/tools/src/merger/OpenApiMerger.ts index 5d38ddeca..3ff33be8d 100644 --- a/tools/src/merger/OpenApiMerger.ts +++ b/tools/src/merger/OpenApiMerger.ts @@ -85,7 +85,9 @@ export default class OpenApiMerger { const spec = read_yaml(`${folder}/${file}`) const category = file.split('.yaml')[0] this.redirect_refs_in_schema(category, spec) - this.schemas[category] = spec.components.schemas as Record + if (spec.components?.schemas !== undefined) { + this.schemas[category] = spec.components?.schemas + } }) Object.entries(this.schemas).forEach(([category, schemas]) => { @@ -97,7 +99,7 @@ export default class OpenApiMerger { // Redirect schema references in schema files to local references in single-file spec. redirect_refs_in_schema (category: string, obj: any): void { - const ref: string = obj.$ref ?? '' + const ref: string = obj?.$ref ?? '' if (ref !== '') { if (ref.startsWith('#/components/schemas')) { obj.$ref = `#/components/schemas/${category}:${ref.split('/').pop()}` } else { const other_category = ref.match(/(.*)\.yaml/)?.[1] ?? '' diff --git a/tools/src/tester/ChapterReader.ts b/tools/src/tester/ChapterReader.ts index fa976b113..04ff18b1d 100644 --- a/tools/src/tester/ChapterReader.ts +++ b/tools/src/tester/ChapterReader.ts @@ -10,13 +10,17 @@ import { type ChapterRequest, type ActualResponse, type Parameter } from './types/story.types' import { type OpenSearchHttpClient } from '../OpenSearchHttpClient' import { type StoryOutputs } from './StoryOutputs' +import { Logger } from 'Logger' +import { to_json } from '../helpers' // A lightweight client for testing the API export default class ChapterReader { private readonly _client: OpenSearchHttpClient + private readonly logger: Logger - constructor (client: OpenSearchHttpClient) { + constructor (client: OpenSearchHttpClient, logger: Logger) { this._client = client + this.logger = logger } async read (chapter: ChapterRequest, story_outputs: StoryOutputs): Promise { @@ -24,17 +28,23 @@ export default class ChapterReader { const resolved_params = story_outputs.resolve_params(chapter.parameters ?? {}) const [url_path, params] = this.#parse_url(chapter.path, resolved_params) const request_data = chapter.request_body?.payload !== undefined ? story_outputs.resolve_value(chapter.request_body.payload) : undefined + this.logger.info(`=> ${chapter.method} ${url_path} (${to_json(params)}) | ${to_json(request_data)}`) await this._client.request({ url: url_path, method: chapter.method, params, data: request_data }).then(r => { + this.logger.info(`<= ${r.status} (${r.headers['content-type']}) | ${to_json(r.data)}`) response.status = r.status response.content_type = r.headers['content-type'].split(';')[0] response.payload = r.data }).catch(e => { - if (e.response == null) throw e + if (e.response == null) { + this.logger.info(`<= ERROR: ${e}`) + throw e + } + this.logger.info(`<= ${e.response.status} (${e.response.headers['content-type']}) | ${to_json(e.response.data)}`) response.status = e.response.status response.content_type = e.response.headers['content-type'].split(';')[0] response.payload = e.response.data?.error diff --git a/tools/src/tester/MergedOpenApiSpec.ts b/tools/src/tester/MergedOpenApiSpec.ts new file mode 100644 index 000000000..6ae5dd410 --- /dev/null +++ b/tools/src/tester/MergedOpenApiSpec.ts @@ -0,0 +1,49 @@ +/* +* Copyright OpenSearch Contributors +* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +import { type OpenAPIV3 } from 'openapi-types' +import { Logger } from '../Logger' +import { SpecificationContext } from '../linter/utils'; +import { SchemaVisitor } from '../linter/utils/SpecificationVisitor'; +import OpenApiMerger from '../merger/OpenApiMerger'; + +// An augmented spec with additionalProperties: false. +export default class MergedOpenApiSpec { + logger: Logger + file_path: string + protected _spec: OpenAPIV3.Document | undefined + + constructor (spec_path: string, logger: Logger = new Logger()) { + this.logger = logger + this.file_path = spec_path + } + + spec (): OpenAPIV3.Document { + if (this._spec) return this._spec + const spec = (new OpenApiMerger(this.file_path, this.logger)).merge() + const ctx = new SpecificationContext(this.file_path) + this.inject_additional_properties(ctx, spec) + this._spec = spec + return this._spec + } + + private inject_additional_properties(ctx: SpecificationContext, spec: OpenAPIV3.Document): void { + const visitor = new SchemaVisitor((_ctx, schema: any) => { + if (schema.required !== undefined && schema.properties !== undefined && schema.additionalProperties === undefined) { + // causes any undeclared field in the response to produce an error + schema.additionalProperties = { + not: true, + errorMessage: "property is not defined in the spec" + } + } + }) + + visitor.visit_specification(ctx, spec) + } +} diff --git a/tools/src/tester/ResultLogger.ts b/tools/src/tester/ResultLogger.ts index a364263fc..1707eab58 100644 --- a/tools/src/tester/ResultLogger.ts +++ b/tools/src/tester/ResultLogger.ts @@ -84,11 +84,6 @@ export class ConsoleResultLogger implements ResultLogger { const result = ansi.padding(this.#result(evaluation.result), 0, prefix) const message = evaluation.message != null ? `${ansi.gray('(' + evaluation.message + ')')}` : '' console.log(`${result} ${title} ${message}`) - if (evaluation.error != null && this._verbose) { - console.log('-'.repeat(100)) - console.error(evaluation.error) - console.log('-'.repeat(100)) - } } #result (r: Result): string { diff --git a/tools/src/tester/SchemaValidator.ts b/tools/src/tester/SchemaValidator.ts index c96d88575..7d13320f9 100644 --- a/tools/src/tester/SchemaValidator.ts +++ b/tools/src/tester/SchemaValidator.ts @@ -8,15 +8,22 @@ */ import AJV from 'ajv' +import ajv_errors from 'ajv-errors' import addFormats from 'ajv-formats' import { type OpenAPIV3 } from 'openapi-types' import { type Evaluation, Result } from './types/eval.types' +import { Logger } from 'Logger' +import { to_json } from '../helpers' export default class SchemaValidator { private readonly ajv: AJV - constructor (spec: OpenAPIV3.Document) { + private readonly logger: Logger + + constructor (spec: OpenAPIV3.Document, logger: Logger) { + this.logger = logger this.ajv = new AJV({ allErrors: true, strict: true }) addFormats(this.ajv) + ajv_errors(this.ajv, { singleError: true }) this.ajv.addKeyword('discriminator') const schemas = spec.components?.schemas ?? {} for (const key in schemas) this.ajv.addSchema(schemas[key], `#/components/schemas/${key}`) @@ -25,6 +32,10 @@ export default class SchemaValidator { validate (schema: OpenAPIV3.SchemaObject, data: any): Evaluation { const validate = this.ajv.compile(schema) const valid = validate(data) + if (! valid) { + this.logger.info(`# ${to_json(schema)}`) + this.logger.info(`* ${to_json(data)}`) + } return { result: valid ? Result.PASSED : Result.FAILED, message: valid ? undefined : this.ajv.errorsText(validate.errors) diff --git a/tools/src/tester/StoryEvaluator.ts b/tools/src/tester/StoryEvaluator.ts index f77f586ce..231fe7d03 100644 --- a/tools/src/tester/StoryEvaluator.ts +++ b/tools/src/tester/StoryEvaluator.ts @@ -152,7 +152,7 @@ export default class StoryEvaluator { StoryEvaluator.#extract_request_body_variables(chapter.request_body?.payload ?? {}, variables) for (const { chapter_id, output_name } of variables) { if (!story_outputs.has_chapter(chapter_id)) { - return StoryEvaluator.#failed_evaluation(title, `Chapter makes reference to non existent chapter "${chapter_id}`) + return StoryEvaluator.#failed_evaluation(title, `Chapter makes reference to non existent chapter "${chapter_id}`) } if (!story_outputs.has_output_value(chapter_id, output_name)) { return StoryEvaluator.#failed_evaluation(title, `Chapter makes reference to non existent output "${output_name}" in chapter "${chapter_id}"`) @@ -202,5 +202,4 @@ export default class StoryEvaluator { static #failed_evaluation(title: string, message: string): ChapterEvaluation { return { title, overall: { result: Result.FAILED, message } } } - } diff --git a/tools/src/tester/test.ts b/tools/src/tester/test.ts index 0d002df95..db7a23664 100644 --- a/tools/src/tester/test.ts +++ b/tools/src/tester/test.ts @@ -7,7 +7,6 @@ * compatible open source license. */ -import OpenApiMerger from '../merger/OpenApiMerger' import { LogLevel, Logger } from '../Logger' import TestRunner from './TestRunner' import { Command, Option } from '@commander-js/extra-typings' @@ -26,6 +25,7 @@ import StoryEvaluator from './StoryEvaluator' import { ConsoleResultLogger } from './ResultLogger' import * as process from 'node:process' import SupplementalChapterEvaluator from './SupplementalChapterEvaluator' +import MergedOpenApiSpec from './MergedOpenApiSpec' const command = new Command() .description('Run test stories against the OpenSearch spec.') @@ -48,11 +48,10 @@ const command = new Command() const opts = command.opts() const logger = new Logger(opts.verbose ? LogLevel.info : LogLevel.warn) -const spec = (new OpenApiMerger(opts.specPath, logger)).merge() - +const spec = (new MergedOpenApiSpec(opts.specPath, logger)).spec() const http_client = new OpenSearchHttpClient(get_opensearch_opts_from_cli(opts)) -const chapter_reader = new ChapterReader(http_client) -const chapter_evaluator = new ChapterEvaluator(new OperationLocator(spec), chapter_reader, new SchemaValidator(spec)) +const chapter_reader = new ChapterReader(http_client, logger) +const chapter_evaluator = new ChapterEvaluator(new OperationLocator(spec), chapter_reader, new SchemaValidator(spec, logger)) const supplemental_chapter_evaluator = new SupplementalChapterEvaluator(chapter_reader) const story_evaluator = new StoryEvaluator(chapter_evaluator, supplemental_chapter_evaluator) const result_logger = new ConsoleResultLogger(opts.tabWidth, opts.verbose) diff --git a/tools/tests/tester/MergedOpenApiSpec.test.ts b/tools/tests/tester/MergedOpenApiSpec.test.ts new file mode 100644 index 000000000..c35699dc6 --- /dev/null +++ b/tools/tests/tester/MergedOpenApiSpec.test.ts @@ -0,0 +1,36 @@ +/* +* Copyright OpenSearch Contributors +* SPDX-License-Identifier: Apache-2.0 +* +* The OpenSearch Contributors require contributions made to +* this file be licensed under the Apache-2.0 license or a +* compatible open source license. +*/ + +import { Logger } from 'Logger' +import MergedOpenApiSpec from "tester/MergedOpenApiSpec" + +describe('additionalProperties', () => { + const spec = new MergedOpenApiSpec('tools/tests/tester/fixtures/specs/complete', new Logger()) + const responses: any = spec.spec().components?.responses + + test('is added with required fields', () => { + const schema = responses['info@200'].content['application/json'].schema + expect(schema.additionalProperties).toEqual({ not: true, errorMessage: 'property is not defined in the spec' }) + }) + + test('is not added when true', () => { + const schema = responses['info@201'].content['application/json'].schema + expect(schema.additionalProperties).toEqual(true) + }) + + test('is not added when object', () => { + const schema = responses['info@404'].content['application/json'].schema + expect(schema.additionalProperties).toEqual({ type: 'object' }) + }) + + test('is not added unless required is present', () => { + const schema = responses['info@500'].content['application/json'].schema + expect(schema.additionalProperties).toBeUndefined() + }) +}) diff --git a/tools/tests/tester/story_outputs.test.ts b/tools/tests/tester/StoryOutputs.test.ts similarity index 100% rename from tools/tests/tester/story_outputs.test.ts rename to tools/tests/tester/StoryOutputs.test.ts diff --git a/tools/tests/tester/fixtures/specs/complete/_global_parameters.yaml b/tools/tests/tester/fixtures/specs/complete/_global_parameters.yaml new file mode 100644 index 000000000..2355a0c60 --- /dev/null +++ b/tools/tests/tester/fixtures/specs/complete/_global_parameters.yaml @@ -0,0 +1,4 @@ +openapi: 3.1.0 +info: + title: '' + version: '' diff --git a/tools/tests/tester/fixtures/specs/complete/_info.yaml b/tools/tests/tester/fixtures/specs/complete/_info.yaml new file mode 100644 index 000000000..721aed8c9 --- /dev/null +++ b/tools/tests/tester/fixtures/specs/complete/_info.yaml @@ -0,0 +1,5 @@ +$schema: should-be-ignored + +title: OpenSearch API +description: OpenSearch API +version: 1.0.0 \ No newline at end of file diff --git a/tools/tests/tester/fixtures/specs/complete/_superseded_operations.yaml b/tools/tests/tester/fixtures/specs/complete/_superseded_operations.yaml new file mode 100644 index 000000000..a5d5e9940 --- /dev/null +++ b/tools/tests/tester/fixtures/specs/complete/_superseded_operations.yaml @@ -0,0 +1 @@ +$schema: should-be-ignored \ No newline at end of file diff --git a/tools/tests/tester/fixtures/specs/complete/namespaces/index.yaml b/tools/tests/tester/fixtures/specs/complete/namespaces/index.yaml new file mode 100644 index 000000000..c0f53c899 --- /dev/null +++ b/tools/tests/tester/fixtures/specs/complete/namespaces/index.yaml @@ -0,0 +1,65 @@ +openapi: 3.1.0 +info: + title: OpenSearch API + description: OpenSearch API + version: 1.0.0 +paths: + '/index': + get: + operationId: get.0 + responses: + '200': + $ref: '#/components/responses/info@200' + '201': + $ref: '#/components/responses/info@201' + '404': + $ref: '#/components/responses/info@404' + '500': + $ref: '#/components/responses/info@500' +components: + responses: + info@200: + description: '' + content: + application/json: + schema: + type: object + properties: + tagline: + type: string + required: + - tagline + info@201: + description: '' + content: + application/json: + schema: + type: object + properties: + tagline: + type: string + required: + - tagline + additionalProperties: true + info@404: + description: '' + content: + application/json: + schema: + type: object + properties: + tagline: + type: string + required: + - tagline + additionalProperties: + type: object + info@500: + description: '' + content: + application/json: + schema: + type: object + properties: + tagline: + type: string diff --git a/tools/tests/tester/fixtures/specs/complete/schemas/actions.yaml b/tools/tests/tester/fixtures/specs/complete/schemas/actions.yaml new file mode 100644 index 000000000..e0a27b499 --- /dev/null +++ b/tools/tests/tester/fixtures/specs/complete/schemas/actions.yaml @@ -0,0 +1,5 @@ +openapi: 3.1.0 +info: + title: OpenSearch API + description: OpenSearch API + version: 1.0.0 diff --git a/tools/tests/tester/helpers.ts b/tools/tests/tester/helpers.ts index f10debdc7..61c9a6070 100644 --- a/tools/tests/tester/helpers.ts +++ b/tools/tests/tester/helpers.ts @@ -21,6 +21,7 @@ import TestRunner from 'tester/TestRunner' import { NoOpResultLogger, type ResultLogger } from 'tester/ResultLogger' import * as process from 'node:process' import SupplementalChapterEvaluator from 'tester/SupplementalChapterEvaluator' +import { Logger } from 'Logger' export function construct_tester_components (spec_path: string): { specification: OpenAPIV3.Document @@ -33,6 +34,7 @@ export function construct_tester_components (spec_path: string): { result_logger: ResultLogger test_runner: TestRunner } { + const logger = new Logger() const specification: OpenAPIV3.Document = read_yaml(spec_path) const operation_locator = new OperationLocator(specification) const opensearch_http_client = new OpenSearchHttpClient({ @@ -40,8 +42,8 @@ export function construct_tester_components (spec_path: string): { username: process.env.OPENSEARCH_USERNAME ?? 'admin', password: process.env.OPENSEARCH_PASSWORD ?? 'myStrongPassword123!' }) - const chapter_reader = new ChapterReader(opensearch_http_client) - const schema_validator = new SchemaValidator(specification) + const chapter_reader = new ChapterReader(opensearch_http_client, logger) + const schema_validator = new SchemaValidator(specification, logger) const chapter_evaluator = new ChapterEvaluator(operation_locator, chapter_reader, schema_validator) const supplemental_chapter_evaluator = new SupplementalChapterEvaluator(chapter_reader) const story_evaluator = new StoryEvaluator(chapter_evaluator, supplemental_chapter_evaluator)