diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bb8bbfd2..361b4f8c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -54,13 +54,14 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Added `plugins` to NodeInfoSettings ([#442](https://github.com/opensearch-project/opensearch-api-specification/pull/442)) - Added test coverage ([#443](https://github.com/opensearch-project/opensearch-api-specification/pull/443)) - Added `--opensearch-version` to `merger` that excludes schema elements per semver ([#428](https://github.com/opensearch-project/opensearch-api-specification/pull/428)) -- Added `retry` to `tester` to support asynchronous tasks ([453](https://github.com/opensearch-project/opensearch-api-specification/pull/453)) +- Added `retry` to `tester` to support asynchronous tasks ([#453](https://github.com/opensearch-project/opensearch-api-specification/pull/453)) - Added passing OPENSEARCH_JAVA_OPTS into the docker container used for tests ([#454](https://github.com/opensearch-project/opensearch-api-specification/pull/454)) - Added a warning on mulitple paths being tested in the same file ([#452](https://github.com/opensearch-project/opensearch-api-specification/pull/452)) - Added validation of titles and descriptions in info and schema objects ([#463](https://github.com/opensearch-project/opensearch-api-specification/pull/463)) - Added `/_plugins/_query/settings` ([#456](https://github.com/opensearch-project/opensearch-api-specification/pull/456)) - Added `/_plugins/_ppl`, `explain` and `stats` ([#460](https://github.com/opensearch-project/opensearch-api-specification/pull/460)) - Added tests against OpenSearch 3.0 ([#459](https://github.com/opensearch-project/opensearch-api-specification/pull/459)) +- Added support for request headers in tests [#461](https://github.com/opensearch-project/opensearch-api-specification/pull/461) ### Changed diff --git a/TESTING_GUIDE.md b/TESTING_GUIDE.md index 948ce228f..31323efcf 100644 --- a/TESTING_GUIDE.md +++ b/TESTING_GUIDE.md @@ -75,10 +75,12 @@ chapters: - synopsis: Create an index named `books` with mappings and settings. path: /{index} # The test will fail if "PUT /{index}" operation is not found in the spec. method: PUT - parameters: # All parameters are validated against their schemas in the spec + parameters: # All parameters are validated against their schemas in the spec. index: books - request_body: # The request body is validated against the schema of the requestBody in the spec - payload: + request: # The request. + headers: # Optional headers. + user-agent: OpenSearch API Spec/1.0 + payload: # The request body is validated against the schema of the requestBody in the spec. mappings: properties: name: @@ -88,7 +90,8 @@ chapters: settings: number_of_shards: 5 number_of_replicas: 2 - response: # The response body is validated against the schema of the corresponding response in the spec + response: # The response. + payload: # Matching response payload. The entire payload is validated against the schema of the corresponding response in the spec. status: 200 # This is the expected status code of the response. Any other status code will fail the test. - synopsis: Retrieve the mappings and settings of the `books` index. @@ -113,7 +116,7 @@ Consider the following chapters in [ml/model_groups](tests/ml/model_groups.yaml) id: create_model_group # Only needed if you want to refer to this chapter in another chapter. path: /_plugins/_ml/model_groups/_register method: POST - request_body: + request: payload: name: NLP_Group description: Model group for NLP models. diff --git a/json_schemas/test_story.schema.yaml b/json_schemas/test_story.schema.yaml index d0b09e5ce..829eb5286 100644 --- a/json_schemas/test_story.schema.yaml +++ b/json_schemas/test_story.schema.yaml @@ -77,8 +77,8 @@ definitions: type: object additionalProperties: $ref: '#/definitions/Parameter' - request_body: - $ref: '#/definitions/RequestBody' + request: + $ref: '#/definitions/Request' output: $ref: '#/definitions/Output' version: @@ -119,15 +119,18 @@ definitions: required: - count - RequestBody: + Request: type: object properties: content_type: type: string default: application/json + headers: + type: object + additionalProperties: + $ref: '#/definitions/Header' payload: $ref: '#/definitions/Payload' - required: [payload] additionalProperties: false ExpectedResponse: @@ -163,6 +166,12 @@ definitions: required: [content_type, payload, status] additionalProperties: false + Header: + anyOf: + - type: string + - type: number + - type: boolean + Payload: anyOf: - type: object diff --git a/package.json b/package.json index 04e7116e4..d73f0868d 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "scripts": { "coverage:spec": "ts-node tools/src/coverage/coverage.ts", "dump-cluster-spec": "ts-node tools/src/dump-cluster-spec/dump-cluster-spec.ts", + "generate-types": "ts-node tools/src/tester/_generate_story_types.ts", "lint:spec": "ts-node tools/src/linter/lint.ts", "lint": "eslint . --report-unused-disable-directives", "lint--fix": "eslint . --fix --report-unused-disable-directives", diff --git a/tests/_core/bulk.yaml b/tests/_core/bulk.yaml index c480b926e..abcbb438f 100644 --- a/tests/_core/bulk.yaml +++ b/tests/_core/bulk.yaml @@ -9,7 +9,7 @@ chapters: - synopsis: Create an index. path: /_bulk method: POST - request_body: + request: content_type: application/x-ndjson payload: - {create: {_index: movies}} @@ -17,7 +17,7 @@ chapters: - synopsis: Bulk document CRUD. path: /_bulk method: POST - request_body: + request: content_type: application/x-ndjson payload: - {create: {_index: books, _id: book_1392214}} diff --git a/tests/_core/mapping.yaml b/tests/_core/mapping.yaml index 99973978f..936cf021e 100644 --- a/tests/_core/mapping.yaml +++ b/tests/_core/mapping.yaml @@ -6,7 +6,7 @@ prologues: method: PUT parameters: index: movies - request_body: + request: payload: mappings: properties: diff --git a/tests/_core/reindex.yaml b/tests/_core/reindex.yaml index 1cf82fde1..2b349d341 100644 --- a/tests/_core/reindex.yaml +++ b/tests/_core/reindex.yaml @@ -17,7 +17,7 @@ prologues: parameters: index: movies refresh: true - request_body: + request: payload: title: Beauty and the Beast year: 91 @@ -26,7 +26,7 @@ chapters: - synopsis: Reindex from movies to films. path: /_reindex method: POST - request_body: + request: payload: source: index: movies @@ -39,7 +39,7 @@ chapters: - synopsis: Reindex a subset of documents (match). path: /_reindex method: POST - request_body: + request: payload: source: index: movies @@ -55,7 +55,7 @@ chapters: - synopsis: Reindex a subset of documents (no match). path: /_reindex method: POST - request_body: + request: payload: source: index: movies @@ -71,7 +71,7 @@ chapters: - synopsis: Combine two indexes. path: /_reindex method: POST - request_body: + request: payload: source: index: @@ -86,7 +86,7 @@ chapters: - synopsis: Reindex only unique documents. path: /_reindex method: POST - request_body: + request: payload: conflicts: proceed source: @@ -101,7 +101,7 @@ chapters: - synopsis: Transform documents during reindex. path: /_reindex method: POST - request_body: + request: payload: source: index: movies @@ -120,7 +120,7 @@ chapters: parameters: max_docs: 1 slices: 1 - request_body: + request: payload: source: index: movies diff --git a/tests/_core/reindex/pipeline.yaml b/tests/_core/reindex/pipeline.yaml index f8e263ae7..fbb6e1065 100644 --- a/tests/_core/reindex/pipeline.yaml +++ b/tests/_core/reindex/pipeline.yaml @@ -14,7 +14,7 @@ epilogues: prologues: - path: /_ingest/pipeline/transform-and-count method: PUT - request_body: + request: payload: description: | Splits the `title`` field into a `words` list. @@ -35,7 +35,7 @@ prologues: parameters: index: movies refresh: true - request_body: + request: payload: title: Beauty and the Beast year: 91 @@ -44,7 +44,7 @@ chapters: - synopsis: Transform documents using a pipeline. path: /_reindex method: POST - request_body: + request: payload: source: index: movies @@ -67,7 +67,7 @@ chapters: method: POST parameters: index: videos - request_body: + request: payload: query: match_all: {} diff --git a/tests/_core/search/_source.yaml b/tests/_core/search/_source.yaml index 973eb3585..de34a143b 100644 --- a/tests/_core/search/_source.yaml +++ b/tests/_core/search/_source.yaml @@ -6,7 +6,7 @@ prologues: method: POST parameters: refresh: true - request_body: + request: payload: director: Bennett Miller title: Moneyball @@ -22,7 +22,7 @@ chapters: parameters: index: movies method: POST - request_body: + request: payload: _source: true query: @@ -48,7 +48,7 @@ chapters: parameters: index: movies method: POST - request_body: + request: payload: _source: false query: @@ -70,7 +70,7 @@ chapters: parameters: index: movies method: POST - request_body: + request: payload: _source: - director @@ -97,7 +97,7 @@ chapters: parameters: index: movies method: POST - request_body: + request: payload: _source: includes: director @@ -123,7 +123,7 @@ chapters: parameters: index: movies method: POST - request_body: + request: payload: _source: includes: '*' diff --git a/tests/_core/search/cancel_after_time_interval.yaml b/tests/_core/search/cancel_after_time_interval.yaml index 012a7972e..b5bd3b510 100644 --- a/tests/_core/search/cancel_after_time_interval.yaml +++ b/tests/_core/search/cancel_after_time_interval.yaml @@ -6,7 +6,7 @@ prologues: method: POST parameters: refresh: true - request_body: + request: payload: director: Bennett Miller title: Moneyball diff --git a/tests/_core/search/geo_distance.yaml b/tests/_core/search/geo_distance.yaml index 8ce5712d0..844df33c2 100644 --- a/tests/_core/search/geo_distance.yaml +++ b/tests/_core/search/geo_distance.yaml @@ -4,7 +4,7 @@ description: Test search endpoint with geo_distance query. prologues: - path: /map method: PUT - request_body: + request: payload: mappings: properties: @@ -14,7 +14,7 @@ prologues: method: POST parameters: refresh: true - request_body: + request: payload: field: lat: 74 @@ -30,7 +30,7 @@ chapters: parameters: index: map method: GET - request_body: + request: payload: query: geo_distance: diff --git a/tests/_core/search/match.yaml b/tests/_core/search/match.yaml index 78afe3ddf..2766f3ac1 100644 --- a/tests/_core/search/match.yaml +++ b/tests/_core/search/match.yaml @@ -6,7 +6,7 @@ prologues: method: POST parameters: refresh: true - request_body: + request: payload: director: Bennett Miller title: Moneyball @@ -22,7 +22,7 @@ chapters: parameters: index: movies method: POST - request_body: + request: payload: size: 1 query: @@ -34,7 +34,7 @@ chapters: parameters: index: movies method: POST - request_body: + request: payload: size: 1 query: diff --git a/tests/_core/search/multi_match.yaml b/tests/_core/search/multi_match.yaml index 4ea41f74a..b5c7b3c76 100644 --- a/tests/_core/search/multi_match.yaml +++ b/tests/_core/search/multi_match.yaml @@ -6,7 +6,7 @@ prologues: method: POST parameters: refresh: true - request_body: + request: payload: director: Bennett Miller title: Moneyball @@ -22,7 +22,7 @@ chapters: parameters: index: movies method: POST - request_body: + request: payload: size: 1 query: diff --git a/tests/_core/search/phase_took.yaml b/tests/_core/search/phase_took.yaml index 846d0fe86..3e061ae0f 100644 --- a/tests/_core/search/phase_took.yaml +++ b/tests/_core/search/phase_took.yaml @@ -6,7 +6,7 @@ prologues: method: POST parameters: refresh: true - request_body: + request: payload: director: Bennett Miller title: Moneyball diff --git a/tests/_core/search/seq_no_primary_term.yaml b/tests/_core/search/seq_no_primary_term.yaml index 07b0d5834..8082de549 100644 --- a/tests/_core/search/seq_no_primary_term.yaml +++ b/tests/_core/search/seq_no_primary_term.yaml @@ -6,7 +6,7 @@ prologues: method: POST parameters: refresh: true - request_body: + request: payload: director: Bennett Miller title: Moneyball diff --git a/tests/_core/search/size.yaml b/tests/_core/search/size.yaml index 154f34638..64b2b8ca9 100644 --- a/tests/_core/search/size.yaml +++ b/tests/_core/search/size.yaml @@ -6,7 +6,7 @@ prologues: method: POST parameters: refresh: true - request_body: + request: payload: director: Bennett Miller title: Moneyball @@ -22,7 +22,7 @@ chapters: parameters: index: movies method: POST - request_body: + request: payload: size: 0 response: @@ -40,7 +40,7 @@ chapters: parameters: index: movies method: POST - request_body: + request: payload: size: 1 query: diff --git a/tests/cat/indices.yaml b/tests/cat/indices.yaml index 90c7d81b5..c8d3fcb42 100644 --- a/tests/cat/indices.yaml +++ b/tests/cat/indices.yaml @@ -6,7 +6,7 @@ prologues: method: PUT parameters: index: books - request_body: + request: payload: {} epilogues: - path: /books diff --git a/tests/cat/pit_segments/all.yaml b/tests/cat/pit_segments/all.yaml index 5b8a1f9ff..91b4ccdd1 100644 --- a/tests/cat/pit_segments/all.yaml +++ b/tests/cat/pit_segments/all.yaml @@ -11,7 +11,7 @@ prologues: method: POST parameters: refresh: true - request_body: + request: payload: title: Monopoly status: [201] diff --git a/tests/cat/pit_segments/pit_segments.yaml b/tests/cat/pit_segments/pit_segments.yaml index 172988830..21ea56af0 100644 --- a/tests/cat/pit_segments/pit_segments.yaml +++ b/tests/cat/pit_segments/pit_segments.yaml @@ -11,7 +11,7 @@ prologues: method: POST parameters: refresh: true - request_body: + request: payload: title: Monopoly status: [201] @@ -30,7 +30,7 @@ chapters: method: GET parameters: format: json - request_body: + request: payload: pit_id: - ${create_pit.pit_id} diff --git a/tests/cat/repositories.yaml b/tests/cat/repositories.yaml index 80222e5ba..72cd80dce 100644 --- a/tests/cat/repositories.yaml +++ b/tests/cat/repositories.yaml @@ -12,7 +12,7 @@ prologues: method: PUT parameters: repository: my-fs-repository - request_body: + request: payload: type: fs settings: diff --git a/tests/cat/snapshots.yaml b/tests/cat/snapshots.yaml index 1163c5db5..962827112 100644 --- a/tests/cat/snapshots.yaml +++ b/tests/cat/snapshots.yaml @@ -8,7 +8,7 @@ epilogues: prologues: - path: /_snapshot/my-fs-repository method: PUT - request_body: + request: payload: type: fs settings: diff --git a/tests/cat/templates.yaml b/tests/cat/templates.yaml index b72262fe7..3f233a76b 100644 --- a/tests/cat/templates.yaml +++ b/tests/cat/templates.yaml @@ -8,7 +8,7 @@ epilogues: prologues: - path: /_index_template/daily_logs method: PUT - request_body: + request: payload: index_patterns: - 'logs*' diff --git a/tests/cluster/component_template.yaml b/tests/cluster/component_template.yaml index 05838d5db..783393591 100644 --- a/tests/cluster/component_template.yaml +++ b/tests/cluster/component_template.yaml @@ -11,7 +11,7 @@ chapters: method: POST parameters: name: template1 - request_body: + request: payload: template: settings: @@ -31,7 +31,7 @@ chapters: method: PUT parameters: name: template1 - request_body: + request: payload: template: settings: diff --git a/tests/indices/alias/alias.yaml b/tests/indices/alias/alias.yaml index 5bd41501c..09962aff6 100644 --- a/tests/indices/alias/alias.yaml +++ b/tests/indices/alias/alias.yaml @@ -48,7 +48,7 @@ chapters: parameters: index: games name: jeux - request_body: + request: payload: index_routing: test1 search_routing: test2 @@ -63,6 +63,6 @@ chapters: parameters: index: games name: jeux - request_body: + request: payload: is_hidden: true diff --git a/tests/indices/aliases/aliases.yaml b/tests/indices/aliases/aliases.yaml index a1bc2baac..22bcd95f1 100644 --- a/tests/indices/aliases/aliases.yaml +++ b/tests/indices/aliases/aliases.yaml @@ -18,7 +18,7 @@ chapters: - synopsis: Multiple alias operations. path: /_aliases method: POST - request_body: + request: payload: actions: - remove: diff --git a/tests/indices/aliases/put_alias.yaml b/tests/indices/aliases/put_alias.yaml index 7dd73fe9c..ea65d3c53 100644 --- a/tests/indices/aliases/put_alias.yaml +++ b/tests/indices/aliases/put_alias.yaml @@ -30,7 +30,7 @@ chapters: method: PUT parameters: index: test_index - request_body: + request: payload: alias: test_alias_1 response: @@ -43,7 +43,7 @@ chapters: method: PUT parameters: name: test_alias_2 - request_body: + request: payload: index: test_index response: @@ -54,7 +54,7 @@ chapters: - synopsis: Create an alias - specifying index & alias in body. path: /_alias method: PUT - request_body: + request: payload: index: test_index alias: test_alias_3 diff --git a/tests/indices/clone.yaml b/tests/indices/clone.yaml index f3132ec78..dfc56119c 100644 --- a/tests/indices/clone.yaml +++ b/tests/indices/clone.yaml @@ -6,7 +6,7 @@ prologues: method: PUT - path: /movies/_settings method: PUT - request_body: + request: payload: settings: index.blocks.write: true diff --git a/tests/indices/component_template.yaml b/tests/indices/component_template.yaml index c77477f0c..d05b88f4c 100644 --- a/tests/indices/component_template.yaml +++ b/tests/indices/component_template.yaml @@ -20,7 +20,7 @@ chapters: method: POST parameters: name: component_template_1 - request_body: + request: payload: template: mappings: @@ -41,7 +41,7 @@ chapters: method: POST parameters: name: component_template_2 - request_body: + request: payload: template: mappings: @@ -57,7 +57,7 @@ chapters: method: POST parameters: name: daily_logs - request_body: + request: payload: index_patterns: - 'logs*' diff --git a/tests/indices/data_stream/data_stream.yaml b/tests/indices/data_stream/data_stream.yaml index d4b7952b2..051451286 100644 --- a/tests/indices/data_stream/data_stream.yaml +++ b/tests/indices/data_stream/data_stream.yaml @@ -4,7 +4,7 @@ description: Test data streams. prologues: - path: /_index_template/logs-template-nginx method: PUT - request_body: + request: payload: index_patterns: - logs-* @@ -33,7 +33,7 @@ chapters: method: POST parameters: index: logs-nginx - request_body: + request: payload: message: login attempt failed request_time: '2013-03-01T00:00:00' diff --git a/tests/indices/data_stream/rollover.yaml b/tests/indices/data_stream/rollover.yaml index 2607b1c69..f8640db10 100644 --- a/tests/indices/data_stream/rollover.yaml +++ b/tests/indices/data_stream/rollover.yaml @@ -4,7 +4,7 @@ description: Test data streams rollover. prologues: - path: /_index_template/logs-template-nginx method: PUT - request_body: + request: payload: index_patterns: - logs-* @@ -17,7 +17,7 @@ prologues: method: PUT - path: /logs-nginx/_doc method: POST - request_body: + request: payload: message: login attempt failed request_time: '2013-03-01T00:00:00' diff --git a/tests/indices/data_stream/stats.yaml b/tests/indices/data_stream/stats.yaml index c963997be..8052ff670 100644 --- a/tests/indices/data_stream/stats.yaml +++ b/tests/indices/data_stream/stats.yaml @@ -4,7 +4,7 @@ description: Test data streams. prologues: - path: /_index_template/logs-template-nginx method: PUT - request_body: + request: payload: index_patterns: - logs-* @@ -17,7 +17,7 @@ prologues: method: PUT - path: /logs-nginx/_doc method: POST - request_body: + request: payload: message: login attempt failed request_time: '2013-03-01T00:00:00' diff --git a/tests/indices/doc.yaml b/tests/indices/doc.yaml index cf01403b8..325602d75 100644 --- a/tests/indices/doc.yaml +++ b/tests/indices/doc.yaml @@ -11,7 +11,7 @@ chapters: method: POST parameters: index: movies - request_body: + request: payload: title: Beauty and the Beast year: 1991 @@ -23,7 +23,7 @@ chapters: parameters: index: movies id: '1' - request_body: + request: payload: title: Beauty and the Beast (Id) year: 1991 @@ -35,7 +35,7 @@ chapters: parameters: index: movies id: '1' - request_body: + request: payload: title: Beauty and the Beast (Updated) year: 1991 diff --git a/tests/indices/index.yaml b/tests/indices/index.yaml index 22ee0a3d7..186b7df8f 100644 --- a/tests/indices/index.yaml +++ b/tests/indices/index.yaml @@ -14,7 +14,7 @@ chapters: method: PUT parameters: index: books - request_body: + request: payload: mappings: properties: diff --git a/tests/indices/index_template.yaml b/tests/indices/index_template.yaml index c61011894..09a6ce7f4 100644 --- a/tests/indices/index_template.yaml +++ b/tests/indices/index_template.yaml @@ -11,7 +11,7 @@ chapters: method: POST parameters: name: daily_logs - request_body: + request: payload: index_patterns: - 'logs*' @@ -27,7 +27,7 @@ chapters: method: PUT parameters: name: daily_logs - request_body: + request: payload: index_patterns: - 'logs*' diff --git a/tests/indices/mapping.yml b/tests/indices/mapping.yml index af2b29518..00a11407d 100644 --- a/tests/indices/mapping.yml +++ b/tests/indices/mapping.yml @@ -10,7 +10,7 @@ prologues: method: PUT parameters: index: movies - request_body: + request: payload: mappings: properties: @@ -68,7 +68,7 @@ chapters: ignore_unavailable: true timeout: 10s write_index_only: true - request_body: + request: payload: dynamic: 'true' properties: @@ -85,7 +85,7 @@ chapters: parameters: index: movies cluster_manager_timeout: 1s - request_body: + request: payload: properties: producer: @@ -104,7 +104,7 @@ chapters: ignore_unavailable: true timeout: 10s write_index_only: true - request_body: + request: payload: dynamic: 'false' response: @@ -121,7 +121,7 @@ chapters: ignore_unavailable: true timeout: 10s write_index_only: true - request_body: + request: payload: dynamic: strict response: @@ -139,7 +139,7 @@ chapters: ignore_unavailable: true timeout: 10s write_index_only: true - request_body: + request: payload: dynamic: strict_allow_templates response: diff --git a/tests/indices/refresh.yaml b/tests/indices/refresh.yaml index d4aff0cef..587168962 100644 --- a/tests/indices/refresh.yaml +++ b/tests/indices/refresh.yaml @@ -8,7 +8,7 @@ epilogues: prologues: - path: /movies/_doc method: POST - request_body: + request: payload: title: Beauty and the Beast year: 1991 diff --git a/tests/indices/settings.yaml b/tests/indices/settings.yaml index dc5a85f7b..a5835fdb0 100644 --- a/tests/indices/settings.yaml +++ b/tests/indices/settings.yaml @@ -41,7 +41,7 @@ chapters: method: PUT parameters: index: movies - request_body: + request: payload: settings: index.blocks.write: true diff --git a/tests/indices/shrink.yaml b/tests/indices/shrink.yaml index 58b8fee23..1803889ab 100644 --- a/tests/indices/shrink.yaml +++ b/tests/indices/shrink.yaml @@ -4,13 +4,13 @@ description: Test shrinking an index. prologues: - path: /movies method: PUT - request_body: + request: payload: settings: index.number_of_shards: 3 - path: /movies/_settings method: PUT - request_body: + request: payload: settings: index.blocks.write: true diff --git a/tests/indices/split.yaml b/tests/indices/split.yaml index ae6204060..980feb287 100644 --- a/tests/indices/split.yaml +++ b/tests/indices/split.yaml @@ -4,13 +4,13 @@ description: Test splitting an index. prologues: - path: /movies method: PUT - request_body: + request: payload: settings: index.number_of_shards: 3 - path: /movies/_settings method: PUT - request_body: + request: payload: settings: index.blocks.write: true @@ -39,7 +39,7 @@ chapters: target: movies1 wait_for_active_shards: 1 timeout: 10s - request_body: + request: payload: settings: index: @@ -58,7 +58,7 @@ chapters: index: movies target: movies2 wait_for_completion: true - request_body: + request: payload: settings: index: @@ -73,7 +73,7 @@ chapters: target: movies3 wait_for_active_shards: 1 timeout: 10s - request_body: + request: payload: settings: index: @@ -94,7 +94,7 @@ chapters: wait_for_active_shards: 1 cluster_manager_timeout: 10s timeout: 10s - request_body: + request: payload: settings: index: diff --git a/tests/indices/update_by_query.yaml b/tests/indices/update_by_query.yaml index 4043dc496..a58853f3f 100644 --- a/tests/indices/update_by_query.yaml +++ b/tests/indices/update_by_query.yaml @@ -10,7 +10,7 @@ prologues: method: POST parameters: refresh: true - request_body: + request: content_type: application/x-ndjson payload: - {create: {_index: books, _id: book_1392214}} @@ -33,7 +33,7 @@ chapters: method: POST parameters: index: books - request_body: + request: payload: query: term: @@ -56,7 +56,7 @@ chapters: method: POST parameters: index: books - request_body: + request: payload: query: term: diff --git a/tests/ingest/pipeline.yaml b/tests/ingest/pipeline.yaml index ee8e539ea..3319d7026 100644 --- a/tests/ingest/pipeline.yaml +++ b/tests/ingest/pipeline.yaml @@ -13,7 +13,7 @@ chapters: method: PUT parameters: id: books_pipeline - request_body: + request: payload: description: Extracts text from field and embeds it. processors: diff --git a/tests/ml/model_groups.yaml b/tests/ml/model_groups.yaml index 46f8595d7..778863820 100644 --- a/tests/ml/model_groups.yaml +++ b/tests/ml/model_groups.yaml @@ -6,7 +6,7 @@ version: '>= 2.11' prologues: - path: /_cluster/settings method: PUT - request_body: + request: payload: persistent: plugins: @@ -25,7 +25,7 @@ chapters: id: create_model_group path: /_plugins/_ml/model_groups/_register method: POST - request_body: + request: payload: name: NLP_Group description: Model group for NLP models diff --git a/tests/ml/models.yaml b/tests/ml/models.yaml index 452f7bacf..f82d2ecda 100644 --- a/tests/ml/models.yaml +++ b/tests/ml/models.yaml @@ -6,7 +6,7 @@ version: '>= 2.11' prologues: - path: /_cluster/settings method: PUT - request_body: + request: payload: persistent: plugins: @@ -17,7 +17,7 @@ chapters: id: create_model path: /_plugins/_ml/models/_register method: POST - request_body: + request: payload: name: huggingface/sentence-transformers/msmarco-distilbert-base-tas-b version: 1.0.1 diff --git a/tests/ppl/explain.yaml b/tests/ppl/explain.yaml index 0dbc465ea..89421fb70 100644 --- a/tests/ppl/explain.yaml +++ b/tests/ppl/explain.yaml @@ -5,7 +5,7 @@ description: Test how a query is executed against OpenSearch. prologues: - path: /books method: PUT - request_body: + request: payload: {} epilogues: - path: /books @@ -15,7 +15,7 @@ chapters: - synopsis: Get explain of SQL Query path: /_plugins/_ppl/_explain method: POST - request_body: + request: payload: query: search source=books response: diff --git a/tests/ppl/query.yaml b/tests/ppl/query.yaml index 53a9720d3..b9b3548be 100644 --- a/tests/ppl/query.yaml +++ b/tests/ppl/query.yaml @@ -7,7 +7,7 @@ prologues: method: PUT parameters: index: books - request_body: + request: payload: {} epilogues: - path: /books @@ -17,7 +17,7 @@ chapters: - synopsis: Get PPL query path: /_plugins/_ppl method: POST - request_body: + request: payload: query: search source=books response: diff --git a/tests/sql/close.yaml b/tests/sql/close.yaml index df2910ae9..0f70d62c8 100644 --- a/tests/sql/close.yaml +++ b/tests/sql/close.yaml @@ -7,11 +7,11 @@ prologues: method: PUT parameters: index: books - request_body: + request: payload: {} - path: /_bulk method: POST - request_body: + request: content_type: application/x-ndjson payload: - {create: {_index: books, _id: book_1392214}} @@ -24,14 +24,14 @@ prologues: index: books - path: _plugins/_query/settings method: PUT - request_body: + request: payload: transient: plugins.query.memory_limit: 100% - id: sql_query path: /_plugins/_sql method: POST - request_body: + request: payload: fetch_size: 1 query: 'SELECT * FROM books' @@ -45,7 +45,7 @@ chapters: - synopsis: Close cursor. path: /_plugins/_sql/close method: POST - request_body: + request: payload: cursor: ${sql_query.cursor} response: diff --git a/tests/sql/explain.yaml b/tests/sql/explain.yaml index 3679dcb29..245d65d83 100644 --- a/tests/sql/explain.yaml +++ b/tests/sql/explain.yaml @@ -5,11 +5,11 @@ description: Test how a query is executed against OpenSearch. prologues: - path: /books method: PUT - request_body: + request: payload: {} - path: _plugins/_query/settings method: PUT - request_body: + request: payload: transient: plugins.query.memory_limit: 100% @@ -21,7 +21,7 @@ chapters: - synopsis: Get explain of SQL Query path: /_plugins/_sql/_explain method: POST - request_body: + request: payload: query: SELECT * FROM books response: diff --git a/tests/sql/query.yaml b/tests/sql/query.yaml index e66942606..ba1d34317 100644 --- a/tests/sql/query.yaml +++ b/tests/sql/query.yaml @@ -7,11 +7,11 @@ prologues: method: PUT parameters: index: books - request_body: + request: payload: {} - path: _plugins/_query/settings method: PUT - request_body: + request: payload: transient: plugins.query.memory_limit: 100% @@ -25,7 +25,7 @@ chapters: method: POST parameters: sanitize: false - request_body: + request: payload: query: 'SELECT * FROM books' response: diff --git a/tests/sql/settings.yaml b/tests/sql/settings.yaml index 68e5f91c7..6a826806f 100644 --- a/tests/sql/settings.yaml +++ b/tests/sql/settings.yaml @@ -6,7 +6,7 @@ chapters: - synopsis: Update SQL settings. path: /_plugins/_query/settings method: PUT - request_body: + request: payload: transient: plugins: @@ -25,7 +25,7 @@ chapters: - synopsis: Update SQL settings with plain request body. path: /_plugins/_query/settings method: PUT - request_body: + request: payload: transient: plugins.sql.enabled: true diff --git a/tools/src/_utils/SpecificationVisitor.ts b/tools/src/_utils/SpecificationVisitor.ts index b97a636e4..ee8fb276d 100644 --- a/tools/src/_utils/SpecificationVisitor.ts +++ b/tools/src/_utils/SpecificationVisitor.ts @@ -58,13 +58,13 @@ export class SpecificationVisitor { visit_operation (ctx: SpecificationContext, operation: OpenAPIV3.OperationObject): void { visit_each(ctx, operation, 'parameters', this.visit_parameter.bind(this)) - visit(ctx, operation, 'requestBody', this.visit_request_body.bind(this)) + visit(ctx, operation, 'requestBody', this.visit_request.bind(this)) visit_each(ctx, operation, 'responses', this.visit_response.bind(this)) } visit_components (ctx: SpecificationContext, components: OpenAPIV3.ComponentsObject): void { visit_each(ctx, components, 'parameters', this.visit_parameter.bind(this)) - visit_each(ctx, components, 'requestBodies', this.visit_request_body.bind(this)) + visit_each(ctx, components, 'requestBodies', this.visit_request.bind(this)) visit_each(ctx, components, 'responses', this.visit_response.bind(this)) visit_each(ctx, components, 'schemas', this.visit_schema.bind(this)) } @@ -75,10 +75,10 @@ export class SpecificationVisitor { visit(ctx, parameter, 'schema', this.visit_schema.bind(this)) } - visit_request_body (ctx: SpecificationContext, request_body: MaybeRef): void { - if (is_ref(request_body)) return + visit_request (ctx: SpecificationContext, request: MaybeRef): void { + if (is_ref(request)) return - visit_each(ctx, request_body, 'content', this.visit_media_type.bind(this)) + visit_each(ctx, request, 'content', this.visit_media_type.bind(this)) } visit_response (ctx: SpecificationContext, response: MaybeRef): void { diff --git a/tools/src/linter/SchemasValidator.ts b/tools/src/linter/SchemasValidator.ts index d22c0beaa..06672285b 100644 --- a/tools/src/linter/SchemasValidator.ts +++ b/tools/src/linter/SchemasValidator.ts @@ -38,7 +38,7 @@ export default class SchemasValidator { if (named_schemas_errors.length > 0) return named_schemas_errors return [ ...this.validate_parameter_schemas(), - ...this.validate_request_body_schemas(), + ...this.validate_request_schemas(), ...this.validate_response_schemas() ] } @@ -66,7 +66,7 @@ export default class SchemasValidator { }).filter((error) => error != null) as ValidationError[] } - validate_request_body_schemas (): ValidationError[] { + validate_request_schemas (): ValidationError[] { return Object.entries(this.spec.requestBodies as Record).flatMap(([namespace, body]) => { const file = `namespaces/${namespace}.yaml` const location = `#/components/requestBodies/${namespace}` diff --git a/tools/src/linter/components/Operation.ts b/tools/src/linter/components/Operation.ts index bb06233ad..f55b29e27 100644 --- a/tools/src/linter/components/Operation.ts +++ b/tools/src/linter/components/Operation.ts @@ -40,7 +40,7 @@ export default class Operation extends ValidatorBase { return [ this.validate_operation_id(), this.validate_description(), - this.validate_request_body(), + this.validate_request(), this.validate_parameters(), this.validate_path_parameters(), this.validate_order_of_parameters(), @@ -77,7 +77,7 @@ export default class Operation extends ValidatorBase { if (!regex.test(id)) { return this.error(`Invalid operationId '${id}'. Must be in {x-operation-group}.{number} format.`) } } - validate_request_body (): ValidationError | undefined { + validate_request (): ValidationError | undefined { const body = this.spec.requestBody if (!body) return const expected = `#/components/requestBodies/${this.group}` diff --git a/tools/src/linter/components/OperationGroup.ts b/tools/src/linter/components/OperationGroup.ts index 5daa6adce..dc45765bc 100644 --- a/tools/src/linter/components/OperationGroup.ts +++ b/tools/src/linter/components/OperationGroup.ts @@ -32,7 +32,7 @@ export default class OperationGroup extends ValidatorBase { return [ this.validate_description(), this.validate_external_docs(), - this.validate_request_body(), + this.validate_request(), this.validate_responses(), this.validate_query_parameters() ].filter((e) => e) as ValidationError[] @@ -48,7 +48,7 @@ export default class OperationGroup extends ValidatorBase { if (uniq_external_docs.size > 1) { return this.error(`${this.operations.length} '${this.name}' operations must have identical externalDocs property.`) } } - validate_request_body (): ValidationError | undefined { + validate_request (): ValidationError | undefined { const uniq_request_bodies = new Set(this.operations.map((op) => op.spec.requestBody?.$ref)) if (uniq_request_bodies.size > 1) { return this.error(`${this.operations.length} '${this.name}' operations must have identical requestBody property.`) } } diff --git a/tools/src/tester/ChapterEvaluator.ts b/tools/src/tester/ChapterEvaluator.ts index 43157d2b8..e06fca445 100644 --- a/tools/src/tester/ChapterEvaluator.ts +++ b/tools/src/tester/ChapterEvaluator.ts @@ -64,7 +64,7 @@ export default class ChapterEvaluator { async #evaluate(chapter: Chapter, operation: ParsedOperation, story_outputs: StoryOutputs, retries?: number): Promise { const response = await this._chapter_reader.read(chapter, story_outputs) const params = this.#evaluate_parameters(chapter, operation) - const request_body = this.#evaluate_request_body(chapter, operation) + const request = this.#evaluate_request(chapter, operation) const status = this.#evaluate_status(chapter, response) const payload_body_evaluation = status.result === Result.PASSED ? this.#evaluate_payload_body(response, chapter.response?.payload) : { result: Result.SKIPPED } const payload_schema_evaluation = status.result === Result.PASSED ? this.#evaluate_payload_schema(chapter, response, operation) : { result: Result.SKIPPED } @@ -72,7 +72,7 @@ export default class ChapterEvaluator { const evaluations = _.compact(_.concat( Object.values(params), - request_body, + request, status, payload_body_evaluation, payload_schema_evaluation, @@ -83,7 +83,7 @@ export default class ChapterEvaluator { title: chapter.synopsis, path: `${chapter.method} ${chapter.path}`, overall: { result: overall_result(evaluations) }, - request: { parameters: params, request_body }, + request: { parameters: params, request }, retries, response: { status, @@ -109,12 +109,12 @@ export default class ChapterEvaluator { })) } - #evaluate_request_body(chapter: Chapter, operation: ParsedOperation): Evaluation { - if (!chapter.request_body) return { result: Result.PASSED } - const content_type = chapter.request_body.content_type ?? APPLICATION_JSON + #evaluate_request(chapter: Chapter, operation: ParsedOperation): Evaluation { + if (chapter.request?.payload === undefined) return { result: Result.PASSED } + const content_type = chapter.request.content_type ?? APPLICATION_JSON const schema = operation.requestBody?.content[content_type]?.schema if (schema == null) return { result: Result.FAILED, message: `Schema for "${content_type}" request body not found in the spec.` } - return this._schema_validator.validate(schema, chapter.request_body?.payload ?? {}) + return this._schema_validator.validate(schema, chapter.request?.payload ?? {}) } #evaluate_status(chapter: Chapter, response: ActualResponse): Evaluation { diff --git a/tools/src/tester/ChapterReader.ts b/tools/src/tester/ChapterReader.ts index 9467976d0..ae26e9920 100644 --- a/tools/src/tester/ChapterReader.ts +++ b/tools/src/tester/ChapterReader.ts @@ -17,6 +17,7 @@ import YAML from 'yaml' import CBOR from 'cbor' import SMILE from 'smile-js' import { APPLICATION_CBOR, APPLICATION_JSON, APPLICATION_SMILE, APPLICATION_YAML, TEXT_PLAIN } from "./MimeTypes"; +import _ from 'lodash' export default class ChapterReader { private readonly _client: OpenSearchHttpClient @@ -31,16 +32,16 @@ export default class ChapterReader { const response: Record = {} const resolved_params = story_outputs.resolve_params(chapter.parameters ?? {}) const [url_path, params] = this.#parse_url(chapter.path, resolved_params) - const content_type = chapter.request_body?.content_type ?? APPLICATION_JSON - const request_data = chapter.request_body?.payload !== undefined ? this.#serialize_payload( - story_outputs.resolve_value(chapter.request_body.payload), + const [headers, content_type] = this.#serialize_headers(chapter.request?.headers, chapter.request?.content_type) + const request_data = chapter.request?.payload !== undefined ? this.#serialize_payload( + story_outputs.resolve_value(chapter.request.payload), content_type ) : undefined - this.logger.info(`=> ${chapter.method} ${url_path} (${to_json(params)}) [${content_type}] | ${to_json(request_data)}`) + this.logger.info(`=> ${chapter.method} ${url_path} (${to_json(params)}) [${content_type}] ${_.compact([to_json(headers), to_json(request_data)]).join(' | ')}`) await this._client.request({ url: url_path, method: chapter.method, - headers: { 'Content-Type' : content_type }, + headers: { 'Content-Type' : content_type, ...headers }, params, data: request_data, paramsSerializer: (params) => { // eslint-disable-line @typescript-eslint/naming-convention @@ -49,7 +50,8 @@ export default class ChapterReader { }).then(r => { response.status = r.status response.content_type = r.headers['content-type']?.split(';')[0] - response.payload = this.#deserialize_payload(r.data, response.content_type) + const payload = this.#deserialize_payload(r.data, response.content_type) + if (payload !== undefined) response.payload = payload this.logger.info(`<= ${r.status} (${r.headers['content-type']}) | ${to_json(response.payload)}`) }).catch(e => { if (e.response == null) { @@ -59,7 +61,7 @@ export default class ChapterReader { response.status = e.response.status response.content_type = e.response.headers['content-type']?.split(';')[0] const payload = this.#deserialize_payload(e.response.data, response.content_type) - response.payload = payload?.error + if (payload !== undefined) response.payload = payload.error response.message = payload.error?.reason ?? e.response.statusText response.error = e @@ -68,6 +70,19 @@ export default class ChapterReader { return response as ActualResponse } + #serialize_headers(headers?: Record, content_type?: string): [Record | undefined, string] { + headers = _.cloneDeep(headers) + content_type = content_type ?? APPLICATION_JSON + if (!headers) return [headers, content_type] + _.forEach(headers, (v, k) => { + if (k.toLowerCase() == 'content-type') { + content_type = v.toString() + if (headers) delete headers[k] + } + }) + return [headers, content_type] + } + #serialize_payload(payload: any, content_type: string): any { if (payload === undefined) return undefined switch (content_type) { diff --git a/tools/src/tester/ResultLogger.ts b/tools/src/tester/ResultLogger.ts index ddfead55c..d2ef339c2 100644 --- a/tools/src/tester/ResultLogger.ts +++ b/tools/src/tester/ResultLogger.ts @@ -62,7 +62,7 @@ export class ConsoleResultLogger implements ResultLogger { #log_chapter (chapter: ChapterEvaluation): void { this.#log_evaluation(chapter.overall, ansi.i(chapter.title), this._tab_width * 2) this.#log_parameters(chapter.request?.parameters ?? {}) - this.#log_request_body(chapter.request?.request_body) + this.#log_request(chapter.request?.request) this.#log_status(chapter.response?.status) this.#log_payload_body(chapter.response?.payload_body) this.#log_payload_schema(chapter.response?.payload_schema) @@ -79,7 +79,7 @@ export class ConsoleResultLogger implements ResultLogger { } } - #log_request_body (evaluation: Evaluation | undefined): void { + #log_request (evaluation: Evaluation | undefined): void { if (evaluation == null) return this.#log_evaluation(evaluation, 'REQUEST BODY', this._tab_width * 3) } diff --git a/tools/src/tester/StoryEvaluator.ts b/tools/src/tester/StoryEvaluator.ts index 1e2a95d52..fede2e397 100644 --- a/tools/src/tester/StoryEvaluator.ts +++ b/tools/src/tester/StoryEvaluator.ts @@ -170,7 +170,7 @@ export default class StoryEvaluator { const variables = new Set() const title = `${chapter.method} ${chapter.path}` StoryEvaluator.#extract_params_variables(chapter.parameters ?? {}, variables) - StoryEvaluator.#extract_request_body_variables(chapter.request_body?.payload ?? {}, variables) + StoryEvaluator.#extract_request_variables(chapter.request?.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}`) @@ -192,24 +192,24 @@ export default class StoryEvaluator { }) } - static #extract_request_body_variables(request_body: any, variables: Set): void { - const request_body_type = typeof request_body - switch (request_body_type) { + static #extract_request_variables(request: any, variables: Set): void { + const request_type = typeof request + switch (request_type) { case 'string': { - const ref = OutputReference.parse(request_body as string) + const ref = OutputReference.parse(request as string) if (ref !== undefined) { variables.add(ref) } break } case 'object': { - if (Array.isArray(request_body)) { - for (const value of request_body) { - StoryEvaluator.#extract_request_body_variables(value, variables) + if (Array.isArray(request)) { + for (const value of request) { + StoryEvaluator.#extract_request_variables(value, variables) } } else { - for (const [, value] of Object.entries(request_body as Record)) { - StoryEvaluator.#extract_request_body_variables(value, variables) + for (const [, value] of Object.entries(request as Record)) { + StoryEvaluator.#extract_request_variables(value, variables) } } break diff --git a/tools/src/tester/_generate_story_types.ts b/tools/src/tester/_generate_story_types.ts index d4ab6271e..d520fc02d 100644 --- a/tools/src/tester/_generate_story_types.ts +++ b/tools/src/tester/_generate_story_types.ts @@ -28,7 +28,7 @@ void js2ts.compile(schema, 'Story', * This file was automatically generated by json-schema-to-typescript. * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, * and run json-schema-to-typescript to regenerate this file by running: -* "npx ts-node tools/src/tester/_generate_story_types.ts" in a terminal. +* "npm run generate-types" in a terminal. */ ` }) diff --git a/tools/src/tester/types/eval.types.ts b/tools/src/tester/types/eval.types.ts index a89352eb0..a95104c50 100644 --- a/tools/src/tester/types/eval.types.ts +++ b/tools/src/tester/types/eval.types.ts @@ -39,7 +39,7 @@ export interface ChapterEvaluation { path?: string, request?: { parameters?: Record - request_body?: Evaluation + request?: Evaluation } response?: { status: Evaluation diff --git a/tools/src/tester/types/spec.types.ts b/tools/src/tester/types/spec.types.ts index 06689a9eb..6a6f0f10c 100644 --- a/tools/src/tester/types/spec.types.ts +++ b/tools/src/tester/types/spec.types.ts @@ -11,11 +11,11 @@ import { type OpenAPIV3 } from 'openapi-types' export type ParsedOperation = OpenAPIV3.OperationObject & { parameters: Record - requestBody: ParsedRequestBody + requestBody: ParsedRequest responses: Record } -export type ParsedRequestBody = OpenAPIV3.RequestBodyObject & { +export type ParsedRequest = OpenAPIV3.RequestBodyObject & { content: Record } diff --git a/tools/src/tester/types/story.types.ts b/tools/src/tester/types/story.types.ts index 3b7fbe18b..e418ff762 100644 --- a/tools/src/tester/types/story.types.ts +++ b/tools/src/tester/types/story.types.ts @@ -14,7 +14,7 @@ * This file was automatically generated by json-schema-to-typescript. * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file, * and run json-schema-to-typescript to regenerate this file by running: - * "npx ts-node tools/src/tester/_generate_story_types.ts" in a terminal. + * "npm run generate-types" in a terminal. */ /** @@ -32,6 +32,11 @@ export type SupplementalChapter = ChapterRequest & { * via the `definition` "Parameter". */ export type Parameter = (string | number | boolean)[] | string | number | boolean; +/** + * This interface was referenced by `Story`'s JSON-Schema + * via the `definition` "Header". + */ +export type Header = string | number | boolean; /** * This interface was referenced by `Story`'s JSON-Schema * via the `definition` "Payload". @@ -104,18 +109,21 @@ export interface ChapterRequest { parameters?: { [k: string]: Parameter; }; - request_body?: RequestBody; + request?: Request; output?: Output; version?: Version; retry?: Retry; } /** * This interface was referenced by `Story`'s JSON-Schema - * via the `definition` "RequestBody". + * via the `definition` "Request". */ -export interface RequestBody { +export interface Request { content_type?: string; - payload: Payload; + headers?: { + [k: string]: Header; + }; + payload?: Payload; } /** * Describes output for a chapter. diff --git a/tools/tests/linter/Operation.test.ts b/tools/tests/linter/Operation.test.ts index c5154eb0a..4634ba4cc 100644 --- a/tools/tests/linter/Operation.test.ts +++ b/tools/tests/linter/Operation.test.ts @@ -78,15 +78,15 @@ test('validate_description()', () => { test('validate_requestBody()', () => { const no_body = operation({ 'x-operation-group': 'indices.create' }) - expect(no_body.validate_request_body()) + expect(no_body.validate_request()) .toBeUndefined() const valid_body = operation({ 'x-operation-group': 'indices.create', requestBody: { $ref: '#/components/requestBodies/indices.create' } }) - expect(valid_body.validate_request_body()) + expect(valid_body.validate_request()) .toBeUndefined() const invalid_body = operation({ 'x-operation-group': 'indices.create', requestBody: { $ref: '#/components/requestBodies/indices.create.1' } }) - expect(invalid_body.validate_request_body()) + expect(invalid_body.validate_request()) .toEqual(invalid_body.error('The requestBody must be a reference object to \'#/components/requestBodies/indices.create\'.')) }) diff --git a/tools/tests/linter/OperationGroup.test.ts b/tools/tests/linter/OperationGroup.test.ts index 9ad7c1f65..92351abf2 100644 --- a/tools/tests/linter/OperationGroup.test.ts +++ b/tools/tests/linter/OperationGroup.test.ts @@ -45,13 +45,13 @@ test('validate_requestBody()', () => { const valid_request_bodies = operation_group([ { requestBody: { $ref: '#/components/requestBodies/indices.create' } }, { requestBody: { $ref: '#/components/requestBodies/indices.create' } }]) - expect(valid_request_bodies.validate_request_body()) + expect(valid_request_bodies.validate_request()) .toBeUndefined() const invalid_request_bodies = operation_group([ { requestBody: { $ref: '#/components/requestBodies/indices.create' } }, {}]) - expect(invalid_request_bodies.validate_request_body()) + expect(invalid_request_bodies.validate_request()) .toEqual(invalid_request_bodies.error('2 \'indices.create\' operations must have identical requestBody property.')) }) diff --git a/tools/tests/linter/factories/operation.ts b/tools/tests/linter/factories/operation.ts index b4f90363e..2a87677be 100644 --- a/tools/tests/linter/factories/operation.ts +++ b/tools/tests/linter/factories/operation.ts @@ -40,7 +40,7 @@ export function mocked_operation (returned_values: MockedReturnedValues): Operat op.validate_namespace = jest.fn() op.validate_operation_id = jest.fn() op.validate_description = jest.fn() - op.validate_request_body = jest.fn() + op.validate_request = jest.fn() op.validate_responses = jest.fn() op.validate_parameters = jest.fn() op.validate_path_parameters = jest.fn() @@ -49,7 +49,7 @@ export function mocked_operation (returned_values: MockedReturnedValues): Operat if (returned_values.validate_namespace != null) (op.validate_namespace as jest.Mock).mockReturnValue(returned_values.validate_namespace) if (returned_values.validate_operationId != null) (op.validate_operation_id as jest.Mock).mockReturnValue(returned_values.validate_operationId) if (returned_values.validate_description != null) (op.validate_description as jest.Mock).mockReturnValue(returned_values.validate_description) - if (returned_values.validate_requestBody != null) (op.validate_request_body as jest.Mock).mockReturnValue(returned_values.validate_requestBody) + if (returned_values.validate_requestBody != null) (op.validate_request as jest.Mock).mockReturnValue(returned_values.validate_requestBody) if (returned_values.validate_responses != null) (op.validate_responses as jest.Mock).mockReturnValue(returned_values.validate_responses) if (returned_values.validate_parameters != null) (op.validate_parameters as jest.Mock).mockReturnValue(returned_values.validate_parameters) if (returned_values.validate_path_parameters != null) (op.validate_path_parameters as jest.Mock).mockReturnValue(returned_values.validate_path_parameters) diff --git a/tools/tests/linter/factories/operation_group.ts b/tools/tests/linter/factories/operation_group.ts index 1e5fa04c6..ab68e3ea5 100644 --- a/tools/tests/linter/factories/operation_group.ts +++ b/tools/tests/linter/factories/operation_group.ts @@ -38,13 +38,13 @@ export function mocked_operation_group (returned_values: MockedReturnedValues, o op_group.validate_description = jest.fn() op_group.validate_external_docs = jest.fn() - op_group.validate_request_body = jest.fn() + op_group.validate_request = jest.fn() op_group.validate_responses = jest.fn() op_group.validate_query_parameters = jest.fn() if (returned_values.validate_description != null) (op_group.validate_description as jest.Mock).mockReturnValue(returned_values.validate_description) if (returned_values.validate_externalDocs != null) (op_group.validate_external_docs as jest.Mock).mockReturnValue(returned_values.validate_externalDocs) - if (returned_values.validate_requestBody != null) (op_group.validate_request_body as jest.Mock).mockReturnValue(returned_values.validate_requestBody) + if (returned_values.validate_requestBody != null) (op_group.validate_request as jest.Mock).mockReturnValue(returned_values.validate_requestBody) if (returned_values.validate_responses != null) (op_group.validate_responses as jest.Mock).mockReturnValue(returned_values.validate_responses) if (returned_values.validate_query_parameters != null) (op_group.validate_query_parameters as jest.Mock).mockReturnValue(returned_values.validate_query_parameters) diff --git a/tools/tests/tester/ChapterReader.test.ts b/tools/tests/tester/ChapterReader.test.ts index 34eb6e893..7e1776bb2 100644 --- a/tools/tests/tester/ChapterReader.test.ts +++ b/tools/tests/tester/ChapterReader.test.ts @@ -44,11 +44,11 @@ describe('ChapterReader', () => { path: 'path', method: 'GET', parameters: undefined, - request_body: undefined, + request: undefined, output: undefined }, new StoryOutputs()) - expect(result).toEqual({ status: 200, content_type: 'application/json', payload: undefined }) + expect(result).toStrictEqual({ status: 200, content_type: 'application/json' }) expect(mocked_axios.request.mock.calls).toEqual([ [{ url: 'path', @@ -67,19 +67,19 @@ describe('ChapterReader', () => { path: '{index}/path', method: 'GET', parameters: { index: 'books' }, - request_body: undefined, + request: undefined, output: undefined }, new StoryOutputs()) - expect(result).toEqual({ status: 200, content_type: 'application/json', payload: undefined }) + expect(result).toEqual({ status: 200, content_type: 'application/json' }) expect(mocked_axios.request.mock.calls).toEqual([ [{ url: 'books/path', method: 'GET', + data: undefined, headers: { 'Content-Type': 'application/json' }, params: {}, - paramsSerializer: expect.any(Function), - data: undefined + paramsSerializer: expect.any(Function) }] ]) }) @@ -90,11 +90,11 @@ describe('ChapterReader', () => { path: '/path', method: 'GET', parameters: { indexes: ['book1', 'book2'] }, - request_body: undefined, + request: undefined, output: undefined }, new StoryOutputs()) - expect(result).toEqual({ status: 200, content_type: 'application/json', payload: undefined }) + expect(result).toEqual({ status: 200, content_type: 'application/json' }) expect(mocked_axios.request.mock.calls).toEqual([ [{ url: '/path', @@ -116,11 +116,11 @@ describe('ChapterReader', () => { path: 'path', method: 'POST', parameters: { 'x': 1 }, - request_body: { payload: { "body": "present" } }, + request: { payload: { "body": "present" } }, output: undefined }, new StoryOutputs()) - expect(result).toEqual({ status: 200, content_type: 'application/json', payload: undefined }) + expect(result).toEqual({ status: 200, content_type: 'application/json' }) expect(mocked_axios.request.mock.calls).toEqual([ [{ url: 'path', @@ -139,14 +139,14 @@ describe('ChapterReader', () => { path: 'path', method: 'POST', parameters: { 'x': 1 }, - request_body: { + request: { content_type: 'application/x-ndjson', payload: [{ "body": "present" }] }, output: undefined }, new StoryOutputs()) - expect(result).toEqual({ status: 200, content_type: 'application/json', payload: undefined }) + expect(result).toEqual({ status: 200, content_type: 'application/json' }) expect(mocked_axios.request.mock.calls).toEqual([ [{ url: 'path', @@ -158,6 +158,67 @@ describe('ChapterReader', () => { }] ]) }) + + it('sends headers', async () => { + const result = await reader.read({ + id: 'id', + path: 'path', + method: 'GET', + request: { + headers: { + 'string': 'bar', + 'number': 1, + 'boolean': true + }, + }, + output: undefined + }, new StoryOutputs()) + + expect(result).toStrictEqual({ status: 200, content_type: 'application/json' }) + expect(mocked_axios.request.mock.calls).toStrictEqual([ + [{ + url: 'path', + method: 'GET', + data: undefined, + headers: { + 'Content-Type': 'application/json', + 'string': 'bar', + 'number': 1, + 'boolean': true + }, + params: {}, + paramsSerializer: expect.any(Function) + }] + ]) + }) + + it('overwrites case-insensitive content-type', async () => { + const result = await reader.read({ + id: 'id', + path: 'path', + method: 'GET', + request: { + headers: { + 'content-type': 'application/overwritten' + }, + }, + output: undefined + }, new StoryOutputs()) + + expect(result).toStrictEqual({ status: 200, content_type: 'application/json' }) + expect(mocked_axios.request.mock.calls).toStrictEqual([ + [{ + url: 'path', + method: 'GET', + data: undefined, + headers: { + 'Content-Type': 'application/overwritten', + }, + params: {}, + paramsSerializer: expect.any(Function) + }] + ]) + }) }) describe('deserialize_payload', () => { diff --git a/tools/tests/tester/fixtures/evals/error/chapter_error.yaml b/tools/tests/tester/fixtures/evals/error/chapter_error.yaml index 775bffb2e..450d9c5a3 100644 --- a/tools/tests/tester/fixtures/evals/error/chapter_error.yaml +++ b/tools/tests/tester/fixtures/evals/error/chapter_error.yaml @@ -26,7 +26,7 @@ chapters: path: DELETE /{index} request: parameters: {} - request_body: + request: result: PASSED response: status: diff --git a/tools/tests/tester/fixtures/evals/error/output_error.yaml b/tools/tests/tester/fixtures/evals/error/output_error.yaml index ed4e57ac3..27ac940d3 100644 --- a/tools/tests/tester/fixtures/evals/error/output_error.yaml +++ b/tools/tests/tester/fixtures/evals/error/output_error.yaml @@ -16,7 +16,7 @@ chapters: parameters: format: result: PASSED - request_body: + request: result: PASSED response: payload_body: diff --git a/tools/tests/tester/fixtures/evals/failed/invalid_data.yaml b/tools/tests/tester/fixtures/evals/failed/invalid_data.yaml index 91aeca18b..3f59fe0e8 100644 --- a/tools/tests/tester/fixtures/evals/failed/invalid_data.yaml +++ b/tools/tests/tester/fixtures/evals/failed/invalid_data.yaml @@ -14,7 +14,7 @@ chapters: index: result: FAILED message: data must be string - request_body: + request: result: PASSED response: status: @@ -33,7 +33,7 @@ chapters: parameters: index: result: PASSED - request_body: + request: result: FAILED message: 'data contains unsupported properties: aliases' response: @@ -55,7 +55,7 @@ chapters: result: PASSED index: result: PASSED - request_body: + request: result: PASSED response: status: @@ -75,7 +75,7 @@ chapters: parameters: index: result: PASSED - request_body: + request: result: PASSED response: status: @@ -96,7 +96,7 @@ chapters: parameters: index: result: PASSED - request_body: + request: result: PASSED response: status: diff --git a/tools/tests/tester/fixtures/evals/failed/not_found.yaml b/tools/tests/tester/fixtures/evals/failed/not_found.yaml index ec760c0b1..ecbd88992 100644 --- a/tools/tests/tester/fixtures/evals/failed/not_found.yaml +++ b/tools/tests/tester/fixtures/evals/failed/not_found.yaml @@ -25,7 +25,7 @@ chapters: timeout: result: FAILED message: Schema for "timeout" parameter not found. - request_body: + request: result: PASSED response: status: @@ -44,7 +44,7 @@ chapters: parameters: index: result: PASSED - request_body: + request: result: FAILED message: Schema for "application/json" request body not found in the spec. response: @@ -64,7 +64,7 @@ chapters: parameters: index: result: PASSED - request_body: + request: result: PASSED response: status: diff --git a/tools/tests/tester/fixtures/evals/passed.yaml b/tools/tests/tester/fixtures/evals/passed.yaml index f0118f111..bb74087e8 100644 --- a/tools/tests/tester/fixtures/evals/passed.yaml +++ b/tools/tests/tester/fixtures/evals/passed.yaml @@ -13,7 +13,7 @@ chapters: parameters: index: result: PASSED - request_body: + request: result: PASSED response: status: @@ -30,7 +30,24 @@ chapters: path: GET /_cat request: parameters: {} - request_body: + request: + result: PASSED + response: + status: + result: PASSED + payload_body: + result: PASSED + payload_schema: + result: PASSED + output_values: + result: SKIPPED + - title: This GET /_cat chapter with a header should pass. + overall: + result: PASSED + path: GET /_cat + request: + parameters: {} + request: result: PASSED response: status: @@ -49,7 +66,7 @@ chapters: parameters: format: result: PASSED - request_body: + request: result: PASSED response: status: @@ -68,7 +85,7 @@ chapters: parameters: format: result: PASSED - request_body: + request: result: PASSED response: status: @@ -87,7 +104,7 @@ chapters: parameters: format: result: PASSED - request_body: + request: result: PASSED response: status: @@ -106,7 +123,7 @@ chapters: parameters: format: result: PASSED - request_body: + request: result: PASSED response: status: @@ -125,7 +142,7 @@ chapters: parameters: format: result: PASSED - request_body: + request: result: PASSED response: status: @@ -144,7 +161,7 @@ chapters: parameters: format: result: PASSED - request_body: + request: result: PASSED response: status: diff --git a/tools/tests/tester/fixtures/fail_non_existent_variable.yaml b/tools/tests/tester/fixtures/fail_non_existent_variable.yaml index cb4e80d61..3dc1a8c9d 100644 --- a/tools/tests/tester/fixtures/fail_non_existent_variable.yaml +++ b/tools/tests/tester/fixtures/fail_non_existent_variable.yaml @@ -7,7 +7,7 @@ chapters: id: create_model_group path: /_plugins/_ml/model_groups/_register method: POST - request_body: + request: payload: name: NLP_Group description: Model group for NLP models diff --git a/tools/tests/tester/fixtures/stories/failed/invalid_data.yaml b/tools/tests/tester/fixtures/stories/failed/invalid_data.yaml index ba84d4200..45b00ee0b 100644 --- a/tools/tests/tester/fixtures/stories/failed/invalid_data.yaml +++ b/tools/tests/tester/fixtures/stories/failed/invalid_data.yaml @@ -19,7 +19,7 @@ chapters: method: PUT parameters: index: books - request_body: + request: payload: aliases: {} - synopsis: This chapter should fail because the response content type does not match. diff --git a/tools/tests/tester/fixtures/stories/failed/not_found.yaml b/tools/tests/tester/fixtures/stories/failed/not_found.yaml index 0c0778268..0b61b03a9 100644 --- a/tools/tests/tester/fixtures/stories/failed/not_found.yaml +++ b/tools/tests/tester/fixtures/stories/failed/not_found.yaml @@ -20,7 +20,7 @@ chapters: method: HEAD parameters: index: books - request_body: + request: payload: {} - synopsis: This chapter should fail because the response 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 b1d458f25..b4b08b963 100644 --- a/tools/tests/tester/fixtures/stories/passed.yaml +++ b/tools/tests/tester/fixtures/stories/passed.yaml @@ -21,6 +21,17 @@ chapters: response: status: 200 content_type: text/plain + - synopsis: This GET /_cat chapter with a header should pass. + path: /_cat + method: GET + warnings: + multiple-paths-detected: false + request: + headers: + User-Agent: OpenSearch API Spec/1.0 + response: + status: 200 + content_type: text/plain - synopsis: This GET /_cat/health chapter returns application/json and should pass. path: /_cat/health parameters: diff --git a/tools/tests/tester/helpers.ts b/tools/tests/tester/helpers.ts index 57cbcff16..5ee331a14 100644 --- a/tools/tests/tester/helpers.ts +++ b/tools/tests/tester/helpers.ts @@ -97,7 +97,7 @@ export function flatten_errors (evaluation: StoryEvaluation): StoryEvaluation { if (c.request !== undefined) { result.request = { - request_body: flatten(c.request.request_body) + request: flatten(c.request.request) } if (c.request.parameters !== undefined) { diff --git a/tools/tests/tester/test.test.ts b/tools/tests/tester/test.test.ts index a7db537d7..ee76c19b9 100644 --- a/tools/tests/tester/test.test.ts +++ b/tools/tests/tester/test.test.ts @@ -10,7 +10,7 @@ import { spawnSync } from 'child_process' import * as ansi from 'tester/Ansi' import * as path from 'path' -import { type Chapter, type ChapterRequest, type Output, type RequestBody, type ActualResponse, Story } from 'tester/types/story.types' +import { type Chapter, type ChapterRequest, type Output, type Request, type ActualResponse, Story } from 'tester/types/story.types' import { type EvaluationWithOutput, Result, ChapterEvaluation, StoryEvaluation } from 'tester/types/eval.types' import { ChapterOutput } from 'tester/ChapterOutput' import StoryEvaluator from 'tester/StoryEvaluator' @@ -102,11 +102,11 @@ function dummy_chapter_request(id?: string, output?: Output): ChapterRequest { } } -function dummy_chapter_request_with_input(parameters?: Record, request_body?: RequestBody, id?: string, output?: Output): ChapterRequest { +function dummy_chapter_request_with_input(parameters?: Record, request?: Request, id?: string, output?: Output): ChapterRequest { return { ...dummy_chapter_request(id, output), parameters, - request_body + request } }