From b2e5573e93ac7e5aeca4b7c270a3fbefaaaa71d1 Mon Sep 17 00:00:00 2001 From: dblock Date: Wed, 26 Jun 2024 15:17:22 -0400 Subject: [PATCH] Added application/yaml support and responses to cat APIs. Signed-off-by: dblock --- CHANGELOG.md | 1 + spec/namespaces/cat.yaml | 5 +++ tests/cat/health.yaml | 15 +++++++- tools/src/tester/ChapterEvaluator.ts | 16 +++++++-- .../fixtures/evals/failed/not_found.yaml | 2 +- tools/tests/tester/fixtures/evals/passed.yaml | 35 +++++++++++++++++-- .../tests/tester/fixtures/specs/excerpt.yaml | 33 +++++++++++++++++ .../fixtures/stories/failed/not_found.yaml | 2 +- .../tests/tester/fixtures/stories/passed.yaml | 22 +++++++++++- 9 files changed, 123 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12bef5fb..c687cae4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Added SPECIFICATION_TESTING.md [#359](https://github.com/opensearch-project/opensearch-api-specification/pull/359) - Added StoryValidator to validate stories before running them ([#354](https://github.com/opensearch-project/opensearch-api-specification/issues/354)) - Added support for `text/plain` responses in `_cat` APIs ([#360](https://github.com/opensearch-project/opensearch-api-specification/pull/360)) +- Added support for `application/yaml` responses ([#363](https://github.com/opensearch-project/opensearch-api-specification/pull/363)) ### Changed diff --git a/spec/namespaces/cat.yaml b/spec/namespaces/cat.yaml index 316fd086..e62e86ea 100644 --- a/spec/namespaces/cat.yaml +++ b/spec/namespaces/cat.yaml @@ -848,6 +848,11 @@ components: type: array items: $ref: '../schemas/cat.health.yaml#/components/schemas/HealthRecord' + application/yaml: + schema: + type: array + items: + $ref: '../schemas/cat.health.yaml#/components/schemas/HealthRecord' cat.help@200: description: '' content: diff --git a/tests/cat/health.yaml b/tests/cat/health.yaml index 0a462fe9..26184eb8 100644 --- a/tests/cat/health.yaml +++ b/tests/cat/health.yaml @@ -43,7 +43,7 @@ chapters: response: status: 200 content_type: text/plain - - synopsis: Cat with a json response. + - synopsis: Cat in different formats (format=json). method: GET path: /_cat/health parameters: @@ -56,3 +56,16 @@ chapters: status: yellow node.data: '1' discovered_cluster_manager: 'true' + - synopsis: Cat in different formats (format=yaml). + method: GET + path: /_cat/health + parameters: + format: yaml + response: + status: 200 + content_type: application/yaml + payload: + - node.total: '1' + status: yellow + node.data: '1' + discovered_cluster_manager: 'true' diff --git a/tools/src/tester/ChapterEvaluator.ts b/tools/src/tester/ChapterEvaluator.ts index c9f60f50..6206bfd5 100644 --- a/tools/src/tester/ChapterEvaluator.ts +++ b/tools/src/tester/ChapterEvaluator.ts @@ -17,6 +17,7 @@ import type SchemaValidator from './SchemaValidator' import { type StoryOutputs } from './StoryOutputs' import { ChapterOutput } from './ChapterOutput' import { Operation, atomizeChangeset, diff } from 'json-diff-ts' +import YAML from 'yaml' import _ from 'lodash' export default class ChapterEvaluator { @@ -85,7 +86,9 @@ export default class ChapterEvaluator { #evaluate_payload_body(response: ActualResponse, expected_payload?: Payload): Evaluation { if (expected_payload == null) return { result: Result.PASSED } - const delta = atomizeChangeset(diff(expected_payload, response.payload)) + const content_type = response.content_type ?? 'application/json' + const payload = this.#deserialize_payload(response.payload, content_type) + const delta = atomizeChangeset(diff(expected_payload, payload)) const messages: string[] = _.compact(delta.map((value, _index, _array) => { switch (value.type) { case Operation.UPDATE: @@ -103,6 +106,15 @@ export default class ChapterEvaluator { const schema = content?.schema if (schema == null && content != null) return { result: Result.PASSED } if (schema == null) return { result: Result.FAILED, message: `Schema for "${response.status}: ${response.content_type}" response not found in the spec.` } - return this._schema_validator.validate(schema, response.payload) + console.log(this.#deserialize_payload(response.payload, content_type)) + return this._schema_validator.validate(schema, this.#deserialize_payload(response.payload, content_type)) + } + + #deserialize_payload(payload: any, content_type: string): any { + if (payload === undefined) return undefined + switch(content_type) { + case 'application/yaml': return YAML.parse(payload as string) + default: return payload + } } } diff --git a/tools/tests/tester/fixtures/evals/failed/not_found.yaml b/tools/tests/tester/fixtures/evals/failed/not_found.yaml index 92ab0155..766fb3b9 100644 --- a/tools/tests/tester/fixtures/evals/failed/not_found.yaml +++ b/tools/tests/tester/fixtures/evals/failed/not_found.yaml @@ -10,7 +10,7 @@ chapters: - title: This chapter should fail because the operation is not defined in the spec. overall: result: FAILED - message: Operation "GET /_cat/health" not found in the spec. + message: Operation "GET /_cat/does_not_exist" not found in the spec. - title: This chapter should fail because the parameter is not defined in the spec. overall: result: FAILED diff --git a/tools/tests/tester/fixtures/evals/passed.yaml b/tools/tests/tester/fixtures/evals/passed.yaml index 50104169..a1e26484 100644 --- a/tools/tests/tester/fixtures/evals/passed.yaml +++ b/tools/tests/tester/fixtures/evals/passed.yaml @@ -23,7 +23,7 @@ chapters: result: PASSED payload_schema: result: PASSED - - title: This GET /_cat chapter should pass. + - title: This GET /_cat chapter returns text/plain and should pass. overall: result: PASSED request: @@ -37,7 +37,38 @@ chapters: result: PASSED payload_schema: result: PASSED - + - title: This GET /_cat/health chapter returns application/json and should pass. + overall: + result: PASSED + request: + parameters: + format: + result: PASSED + request_body: + result: PASSED + response: + status: + result: PASSED + payload_body: + result: PASSED + payload_schema: + result: PASSED + - title: This GET /_cat/health chapter returns application/yaml and should pass. + overall: + result: PASSED + request: + parameters: + format: + result: PASSED + request_body: + result: PASSED + response: + status: + result: PASSED + payload_body: + result: PASSED + payload_schema: + result: PASSED epilogues: - title: DELETE /books overall: diff --git a/tools/tests/tester/fixtures/specs/excerpt.yaml b/tools/tests/tester/fixtures/specs/excerpt.yaml index 4914a30b..136f0851 100644 --- a/tools/tests/tester/fixtures/specs/excerpt.yaml +++ b/tools/tests/tester/fixtures/specs/excerpt.yaml @@ -9,9 +9,22 @@ paths: x-operation-group: cat.help x-version-added: '1.0' description: Returns help for the Cat APIs. + parameters: + - $ref: '#/components/parameters/cat.help::query.format' responses: '200': $ref: '#/components/responses/cat.help@200' + /_cat/health: + get: + operationId: cat.health.0 + x-operation-group: cat.health + x-version-added: '1.0' + description: Returns health for the Cat APIs. + parameters: + - $ref: '#/components/parameters/cat.health::query.format' + responses: + '200': + $ref: '#/components/responses/cat.health@200' /{index}: delete: operationId: indices.delete.0 @@ -73,6 +86,21 @@ components: text/plain: schema: type: string + cat.health@200: + content: + text/plain: + schema: + type: string + application/json: + schema: + type: array + items: + type: object + application/yaml: + schema: + type: array + items: + type: object indices.delete@200: description: '' content: @@ -101,6 +129,11 @@ components: - shards_acknowledged - acknowledged parameters: + cat.health::query.format: + in: query + name: format + schema: + type: string indices.delete::path.index: in: path name: index diff --git a/tools/tests/tester/fixtures/stories/failed/not_found.yaml b/tools/tests/tester/fixtures/stories/failed/not_found.yaml index b210f74e..6f1b7573 100644 --- a/tools/tests/tester/fixtures/stories/failed/not_found.yaml +++ b/tools/tests/tester/fixtures/stories/failed/not_found.yaml @@ -7,7 +7,7 @@ epilogues: status: [200, 404] chapters: - synopsis: This chapter should fail because the operation is not defined in the spec. - path: /_cat/health + path: /_cat/does_not_exist method: GET - synopsis: This chapter should fail because the parameter is not defined in the spec. path: /{index} diff --git a/tools/tests/tester/fixtures/stories/passed.yaml b/tools/tests/tester/fixtures/stories/passed.yaml index 17f1e57d..c4a3c5c2 100644 --- a/tools/tests/tester/fixtures/stories/passed.yaml +++ b/tools/tests/tester/fixtures/stories/passed.yaml @@ -11,6 +11,26 @@ chapters: method: PUT parameters: index: books - - synopsis: This GET /_cat chapter should pass. + - synopsis: This GET /_cat chapter returns text/plain and should pass. path: /_cat method: GET + - synopsis: This GET /_cat/health chapter returns application/json and should pass. + path: /_cat/health + parameters: + format: json + method: GET + response: + status: 200 + content_type: application/json + payload: + - node.total: '1' + - synopsis: This GET /_cat/health chapter returns application/yaml and should pass. + path: /_cat/health + parameters: + format: yaml + method: GET + response: + status: 200 + content_type: application/yaml + payload: + - node.total: '1'