From 51cb05aa996803e4527388723222ba381923f842 Mon Sep 17 00:00:00 2001 From: kolchfa-aws <105444904+kolchfa-aws@users.noreply.github.com> Date: Thu, 18 Jul 2024 08:10:17 -0400 Subject: [PATCH 1/6] Add geodistance query test (#427) * Add geodistance query test Signed-off-by: Fanit Kolchina * Correct linting errors Signed-off-by: Fanit Kolchina * Correct method name Signed-off-by: Fanit Kolchina * Fixed merge conflicts Signed-off-by: Fanit Kolchina --------- Signed-off-by: Fanit Kolchina Signed-off-by: Daniel (dB.) Doubrovkine Co-authored-by: Daniel (dB.) Doubrovkine --- CHANGELOG.md | 1 + spec/schemas/_common.query_dsl.yaml | 9 ++ tests/_core/search.yaml | 151 ------------------ .../search/cancel_after_time_interval.yaml | 28 ++++ tests/_core/search/geo_distance.yaml | 60 +++++++ tests/_core/search/match.yaml | 56 +++++++ tests/_core/search/multi_match.yaml | 45 ++++++ tests/_core/search/phase_took.yaml | 28 ++++ tests/_core/search/seq_no_primary_term.yaml | 41 +++++ tests/_core/search/size.yaml | 64 ++++++++ 10 files changed, 332 insertions(+), 151 deletions(-) delete mode 100644 tests/_core/search.yaml create mode 100644 tests/_core/search/cancel_after_time_interval.yaml create mode 100644 tests/_core/search/geo_distance.yaml create mode 100644 tests/_core/search/match.yaml create mode 100644 tests/_core/search/multi_match.yaml create mode 100644 tests/_core/search/phase_took.yaml create mode 100644 tests/_core/search/seq_no_primary_term.yaml create mode 100644 tests/_core/search/size.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index e3a357757..777129425 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,6 +47,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Added missing metrics options to `/_nodes/stats` ([#422](https://github.com/opensearch-project/opensearch-api-specification/pull/422)) - Added tests against OpenSearch 1.3 ([#424](https://github.com/opensearch-project/opensearch-api-specification/pull/424)) - Added `is_hidden` to `/{index}/_alias/{name}` and `/{index}/_aliases/{name}` ([#429](https://github.com/opensearch-project/opensearch-api-specification/pull/429)) +- Added `ignore_unmapped` to `GeoDistanceQuery` ([#427](https://github.com/opensearch-project/opensearch-api-specification/pull/427)) ### Changed diff --git a/spec/schemas/_common.query_dsl.yaml b/spec/schemas/_common.query_dsl.yaml index 7ad1e78ff..3fab6cef8 100644 --- a/spec/schemas/_common.query_dsl.yaml +++ b/spec/schemas/_common.query_dsl.yaml @@ -625,8 +625,17 @@ components: $ref: '_common.yaml#/components/schemas/GeoDistanceType' validation_method: $ref: '#/components/schemas/GeoValidationMethod' + ignore_unmapped: + description: |- + Set to `true` to ignore an unmapped field and not match any documents for this query. + Set to `false` to throw an exception if the field is not mapped. + type: boolean + default: false + field: + type: object required: - distance + - field GeoPolygonQuery: allOf: - $ref: '#/components/schemas/QueryBase' diff --git a/tests/_core/search.yaml b/tests/_core/search.yaml deleted file mode 100644 index a1760ee51..000000000 --- a/tests/_core/search.yaml +++ /dev/null @@ -1,151 +0,0 @@ -$schema: ../../json_schemas/test_story.schema.yaml - -description: Test search endpoint. -prologues: - - path: /movies/_doc - method: POST - parameters: - refresh: true - request_body: - payload: - director: Bennett Miller - title: Moneyball - year: 2011 - status: [201] -epilogues: - - path: /movies - method: DELETE - status: [200, 404] -chapters: - - synopsis: Search with size=0. - path: /{index}/_search - parameters: - index: movies - method: POST - request_body: - payload: - size: 0 - response: - status: 200 - payload: - timed_out: false - hits: - total: - value: 1 - relation: eq - max_score: null - hits: [] - - synopsis: Search with size=1. - path: /{index}/_search - parameters: - index: movies - method: POST - request_body: - payload: - size: 1 - query: - match_all: {} - response: - status: 200 - payload: - timed_out: false - hits: - total: - value: 1 - relation: eq - max_score: 1 - hits: - - _index: movies - _score: 1 - _source: - director: Bennett Miller - title: Moneyball - year: 2011 - - synopsis: Search with a match query object. - path: /{index}/_search - parameters: - index: movies - method: POST - request_body: - payload: - size: 1 - query: - match: - director: - query: Bennett Miller - - synopsis: Search with a match query field. - path: /{index}/_search - parameters: - index: movies - method: POST - request_body: - payload: - size: 1 - query: - match: - director: Bennett Miller - - synopsis: Search with multi_match query. - path: /{index}/_search - parameters: - index: movies - method: POST - request_body: - payload: - size: 1 - query: - multi_match: - query: miller - fields: [director, title^2] - response: - status: 200 - payload: - timed_out: false - hits: - total: - value: 1 - relation: eq - hits: - - _index: movies - _source: - director: Bennett Miller - title: Moneyball - year: 2011 - - synopsis: Search with cancel_after_time_interval. - path: /{index}/_search - parameters: - index: movies - cancel_after_time_interval: 10s - method: POST - response: - status: 200 - - synopsis: Search with phase_took. - version: '>= 2.12' - path: /{index}/_search - parameters: - index: movies - phase_took: true - method: POST - response: - status: 200 - - synopsis: Search with seq_no_primary_term. - path: /{index}/_search - parameters: - index: movies - seq_no_primary_term: true - method: POST - response: - status: 200 - payload: - timed_out: false - hits: - total: - value: 1 - relation: eq - hits: - - _index: movies - _source: - director: Bennett Miller - title: Moneyball - year: 2011 - _seq_no: 0 - _primary_term: 1 diff --git a/tests/_core/search/cancel_after_time_interval.yaml b/tests/_core/search/cancel_after_time_interval.yaml new file mode 100644 index 000000000..012a7972e --- /dev/null +++ b/tests/_core/search/cancel_after_time_interval.yaml @@ -0,0 +1,28 @@ +$schema: ../../../json_schemas/test_story.schema.yaml + +description: Test search endpoint with cancel_after_time_interval. +prologues: + - path: /movies/_doc + method: POST + parameters: + refresh: true + request_body: + payload: + director: Bennett Miller + title: Moneyball + year: 2011 + status: [201] +epilogues: + - path: /movies + method: DELETE + status: [200, 404] +chapters: + - synopsis: Search with cancel_after_time_interval. + path: /{index}/_search + parameters: + index: movies + cancel_after_time_interval: 10s + method: POST + response: + status: 200 + diff --git a/tests/_core/search/geo_distance.yaml b/tests/_core/search/geo_distance.yaml new file mode 100644 index 000000000..8ce5712d0 --- /dev/null +++ b/tests/_core/search/geo_distance.yaml @@ -0,0 +1,60 @@ +$schema: ../../../json_schemas/test_story.schema.yaml + +description: Test search endpoint with geo_distance query. +prologues: + - path: /map + method: PUT + request_body: + payload: + mappings: + properties: + field: + type: geo_point + - path: /map/_doc/1 + method: POST + parameters: + refresh: true + request_body: + payload: + field: + lat: 74 + lon: 40.71 + status: [201] +epilogues: + - path: /map + method: DELETE + status: [200, 404] +chapters: + - synopsis: Search for documents whose point objects are within the specified distance from the specified point. + path: /{index}/_search + parameters: + index: map + method: GET + request_body: + payload: + query: + geo_distance: + distance: 50mi + distance_type: arc + validation_method: strict + ignore_unmapped: true + field: + lat: 73.5 + lon: 40.5 + response: + status: 200 + payload: + timed_out: false + hits: + total: + value: 1 + relation: eq + max_score: 1 + hits: + - _index: map + _score: 1 + _source: + field: + lat: 74 + lon: 40.71 + diff --git a/tests/_core/search/match.yaml b/tests/_core/search/match.yaml new file mode 100644 index 000000000..78afe3ddf --- /dev/null +++ b/tests/_core/search/match.yaml @@ -0,0 +1,56 @@ +$schema: ../../../json_schemas/test_story.schema.yaml + +description: Test search endpoint with match query. +prologues: + - path: /movies/_doc + method: POST + parameters: + refresh: true + request_body: + payload: + director: Bennett Miller + title: Moneyball + year: 2011 + status: [201] +epilogues: + - path: /movies + method: DELETE + status: [200, 404] +chapters: + - synopsis: Search with a match query object. + path: /{index}/_search + parameters: + index: movies + method: POST + request_body: + payload: + size: 1 + query: + match: + director: + query: Bennett Miller + - synopsis: Search with a match query field. + path: /{index}/_search + parameters: + index: movies + method: POST + request_body: + payload: + size: 1 + query: + match: + director: Bennett Miller + response: + status: 200 + payload: + timed_out: false + hits: + total: + value: 1 + relation: eq + hits: + - _index: movies + _source: + director: Bennett Miller + title: Moneyball + year: 2011 diff --git a/tests/_core/search/multi_match.yaml b/tests/_core/search/multi_match.yaml new file mode 100644 index 000000000..4ea41f74a --- /dev/null +++ b/tests/_core/search/multi_match.yaml @@ -0,0 +1,45 @@ +$schema: ../../../json_schemas/test_story.schema.yaml + +description: Test search endpoint with multi_match query. +prologues: + - path: /movies/_doc + method: POST + parameters: + refresh: true + request_body: + payload: + director: Bennett Miller + title: Moneyball + year: 2011 + status: [201] +epilogues: + - path: /movies + method: DELETE + status: [200, 404] +chapters: + - synopsis: Search with multi_match query. + path: /{index}/_search + parameters: + index: movies + method: POST + request_body: + payload: + size: 1 + query: + multi_match: + query: miller + fields: [director, title^2] + response: + status: 200 + payload: + timed_out: false + hits: + total: + value: 1 + relation: eq + hits: + - _index: movies + _source: + director: Bennett Miller + title: Moneyball + year: 2011 diff --git a/tests/_core/search/phase_took.yaml b/tests/_core/search/phase_took.yaml new file mode 100644 index 000000000..846d0fe86 --- /dev/null +++ b/tests/_core/search/phase_took.yaml @@ -0,0 +1,28 @@ +$schema: ../../../json_schemas/test_story.schema.yaml + +description: Test search endpoint with phase_took. +prologues: + - path: /movies/_doc + method: POST + parameters: + refresh: true + request_body: + payload: + director: Bennett Miller + title: Moneyball + year: 2011 + status: [201] +epilogues: + - path: /movies + method: DELETE + status: [200, 404] +chapters: + - synopsis: Search with phase_took. + version: '>= 2.12' + path: /{index}/_search + parameters: + index: movies + phase_took: true + method: POST + response: + status: 200 diff --git a/tests/_core/search/seq_no_primary_term.yaml b/tests/_core/search/seq_no_primary_term.yaml new file mode 100644 index 000000000..07b0d5834 --- /dev/null +++ b/tests/_core/search/seq_no_primary_term.yaml @@ -0,0 +1,41 @@ +$schema: ../../../json_schemas/test_story.schema.yaml + +description: Test search endpoint with seq_no_primary_term. +prologues: + - path: /movies/_doc + method: POST + parameters: + refresh: true + request_body: + payload: + director: Bennett Miller + title: Moneyball + year: 2011 + status: [201] +epilogues: + - path: /movies + method: DELETE + status: [200, 404] +chapters: + - synopsis: Search with seq_no_primary_term. + path: /{index}/_search + parameters: + index: movies + seq_no_primary_term: true + method: POST + response: + status: 200 + payload: + timed_out: false + hits: + total: + value: 1 + relation: eq + hits: + - _index: movies + _source: + director: Bennett Miller + title: Moneyball + year: 2011 + _seq_no: 0 + _primary_term: 1 diff --git a/tests/_core/search/size.yaml b/tests/_core/search/size.yaml new file mode 100644 index 000000000..154f34638 --- /dev/null +++ b/tests/_core/search/size.yaml @@ -0,0 +1,64 @@ +$schema: ../../../json_schemas/test_story.schema.yaml + +description: Test search endpoint with size. +prologues: + - path: /movies/_doc + method: POST + parameters: + refresh: true + request_body: + payload: + director: Bennett Miller + title: Moneyball + year: 2011 + status: [201] +epilogues: + - path: /movies + method: DELETE + status: [200, 404] +chapters: + - synopsis: Search with size=0. + path: /{index}/_search + parameters: + index: movies + method: POST + request_body: + payload: + size: 0 + response: + status: 200 + payload: + timed_out: false + hits: + total: + value: 1 + relation: eq + max_score: null + hits: [] + - synopsis: Search with size=1. + path: /{index}/_search + parameters: + index: movies + method: POST + request_body: + payload: + size: 1 + query: + match_all: {} + response: + status: 200 + payload: + timed_out: false + hits: + total: + value: 1 + relation: eq + max_score: 1 + hits: + - _index: movies + _score: 1 + _source: + director: Bennett Miller + title: Moneyball + year: 2011 + \ No newline at end of file From 0453dbe35080bf31eebac1d75f8022667d019e9f Mon Sep 17 00:00:00 2001 From: Thomas Farr Date: Fri, 19 Jul 2024 00:14:07 +1200 Subject: [PATCH 2/6] Add variants of indices.put_alias (#434) * Add test for variants of indices.put_alias Signed-off-by: Thomas Farr * Add specs for variants of indices.put_alias Signed-off-by: Thomas Farr * Add CHANGELOG entry Signed-off-by: Thomas Farr --------- Signed-off-by: Thomas Farr Signed-off-by: Daniel (dB.) Doubrovkine Co-authored-by: Daniel (dB.) Doubrovkine --- CHANGELOG.md | 1 + spec/namespaces/indices.yaml | 132 ++++++++++++++++++++++- tests/indices/{ => aliases}/aliases.yaml | 2 +- tests/indices/aliases/put_alias.yaml | 79 ++++++++++++++ 4 files changed, 209 insertions(+), 5 deletions(-) rename tests/indices/{ => aliases}/aliases.yaml (97%) create mode 100644 tests/indices/aliases/put_alias.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index 777129425..ef6e64159 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -48,6 +48,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Added tests against OpenSearch 1.3 ([#424](https://github.com/opensearch-project/opensearch-api-specification/pull/424)) - Added `is_hidden` to `/{index}/_alias/{name}` and `/{index}/_aliases/{name}` ([#429](https://github.com/opensearch-project/opensearch-api-specification/pull/429)) - Added `ignore_unmapped` to `GeoDistanceQuery` ([#427](https://github.com/opensearch-project/opensearch-api-specification/pull/427)) +- Added missing variants of `indices.put_alias` ([#434](https://github.com/opensearch-project/opensearch-api-specification/pull/434)) ### Changed diff --git a/spec/namespaces/indices.yaml b/spec/namespaces/indices.yaml index 99895bbea..f1865f021 100644 --- a/spec/namespaces/indices.yaml +++ b/spec/namespaces/indices.yaml @@ -20,6 +20,22 @@ paths: responses: '200': $ref: '#/components/responses/indices.get_alias@200' + put: + operationId: indices.put_alias.0 + x-operation-group: indices.put_alias + x-version-added: '1.0' + description: Creates or updates an alias. + externalDocs: + url: https://opensearch.org/docs/latest/im-plugin/index-alias/#create-aliases + parameters: + - $ref: '#/components/parameters/indices.put_alias::query.cluster_manager_timeout' + - $ref: '#/components/parameters/indices.put_alias::query.master_timeout' + - $ref: '#/components/parameters/indices.put_alias::query.timeout' + requestBody: + $ref: '#/components/requestBodies/indices.put_alias' + responses: + '200': + $ref: '#/components/responses/indices.put_alias@200' /_alias/{name}: get: operationId: indices.get_alias.1 @@ -53,6 +69,40 @@ paths: responses: '200': $ref: '#/components/responses/indices.exists_alias@200' + post: + operationId: indices.put_alias.1 + x-operation-group: indices.put_alias + x-version-added: '1.0' + description: Creates or updates an alias. + externalDocs: + url: https://opensearch.org/docs/latest/im-plugin/index-alias/#create-aliases + parameters: + - $ref: '#/components/parameters/indices.put_alias::path.name' + - $ref: '#/components/parameters/indices.put_alias::query.cluster_manager_timeout' + - $ref: '#/components/parameters/indices.put_alias::query.master_timeout' + - $ref: '#/components/parameters/indices.put_alias::query.timeout' + requestBody: + $ref: '#/components/requestBodies/indices.put_alias' + responses: + '200': + $ref: '#/components/responses/indices.put_alias@200' + put: + operationId: indices.put_alias.2 + x-operation-group: indices.put_alias + x-version-added: '1.0' + description: Creates or updates an alias. + externalDocs: + url: https://opensearch.org/docs/latest/im-plugin/index-alias/#create-aliases + parameters: + - $ref: '#/components/parameters/indices.put_alias::path.name' + - $ref: '#/components/parameters/indices.put_alias::query.cluster_manager_timeout' + - $ref: '#/components/parameters/indices.put_alias::query.master_timeout' + - $ref: '#/components/parameters/indices.put_alias::query.timeout' + requestBody: + $ref: '#/components/requestBodies/indices.put_alias' + responses: + '200': + $ref: '#/components/responses/indices.put_alias@200' /_aliases: post: operationId: indices.update_aliases.0 @@ -70,6 +120,41 @@ paths: responses: '200': $ref: '#/components/responses/indices.update_aliases@200' + /_aliases/{name}: + post: + operationId: indices.put_alias.3 + x-operation-group: indices.put_alias + x-version-added: '1.0' + description: Creates or updates an alias. + externalDocs: + url: https://opensearch.org/docs/latest/im-plugin/index-alias/#create-aliases + parameters: + - $ref: '#/components/parameters/indices.put_alias::path.name' + - $ref: '#/components/parameters/indices.put_alias::query.cluster_manager_timeout' + - $ref: '#/components/parameters/indices.put_alias::query.master_timeout' + - $ref: '#/components/parameters/indices.put_alias::query.timeout' + requestBody: + $ref: '#/components/requestBodies/indices.put_alias' + responses: + '200': + $ref: '#/components/responses/indices.put_alias@200' + put: + operationId: indices.put_alias.4 + x-operation-group: indices.put_alias + x-version-added: '1.0' + description: Creates or updates an alias. + externalDocs: + url: https://opensearch.org/docs/latest/im-plugin/index-alias/#create-aliases + parameters: + - $ref: '#/components/parameters/indices.put_alias::path.name' + - $ref: '#/components/parameters/indices.put_alias::query.cluster_manager_timeout' + - $ref: '#/components/parameters/indices.put_alias::query.master_timeout' + - $ref: '#/components/parameters/indices.put_alias::query.timeout' + requestBody: + $ref: '#/components/requestBodies/indices.put_alias' + responses: + '200': + $ref: '#/components/responses/indices.put_alias@200' /_analyze: get: operationId: indices.analyze.0 @@ -958,6 +1043,23 @@ paths: responses: '200': $ref: '#/components/responses/indices.get_alias@200' + put: + operationId: indices.put_alias.5 + x-operation-group: indices.put_alias + x-version-added: '1.0' + description: Creates or updates an alias. + externalDocs: + url: https://opensearch.org/docs/latest/im-plugin/index-alias/#create-aliases + parameters: + - $ref: '#/components/parameters/indices.put_alias::path.index' + - $ref: '#/components/parameters/indices.put_alias::query.cluster_manager_timeout' + - $ref: '#/components/parameters/indices.put_alias::query.master_timeout' + - $ref: '#/components/parameters/indices.put_alias::query.timeout' + requestBody: + $ref: '#/components/requestBodies/indices.put_alias' + responses: + '200': + $ref: '#/components/responses/indices.put_alias@200' /{index}/_alias/{name}: get: operationId: indices.get_alias.3 @@ -994,7 +1096,7 @@ paths: '200': $ref: '#/components/responses/indices.exists_alias@200' post: - operationId: indices.put_alias.0 + operationId: indices.put_alias.6 x-operation-group: indices.put_alias x-version-added: '1.0' description: Creates or updates an alias. @@ -1012,7 +1114,7 @@ paths: '200': $ref: '#/components/responses/indices.put_alias@200' put: - operationId: indices.put_alias.1 + operationId: indices.put_alias.7 x-operation-group: indices.put_alias x-version-added: '1.0' description: Creates or updates an alias. @@ -1045,9 +1147,27 @@ paths: responses: '200': $ref: '#/components/responses/indices.delete_alias@200' + /{index}/_aliases: + put: + operationId: indices.put_alias.8 + x-operation-group: indices.put_alias + x-version-added: '1.0' + description: Creates or updates an alias. + externalDocs: + url: https://opensearch.org/docs/latest/im-plugin/index-alias/#create-aliases + parameters: + - $ref: '#/components/parameters/indices.put_alias::path.index' + - $ref: '#/components/parameters/indices.put_alias::query.cluster_manager_timeout' + - $ref: '#/components/parameters/indices.put_alias::query.master_timeout' + - $ref: '#/components/parameters/indices.put_alias::query.timeout' + requestBody: + $ref: '#/components/requestBodies/indices.put_alias' + responses: + '200': + $ref: '#/components/responses/indices.put_alias@200' /{index}/_aliases/{name}: post: - operationId: indices.put_alias.2 + operationId: indices.put_alias.9 x-operation-group: indices.put_alias x-version-added: '1.0' description: Creates or updates an alias. @@ -1065,7 +1185,7 @@ paths: '200': $ref: '#/components/responses/indices.put_alias@200' put: - operationId: indices.put_alias.3 + operationId: indices.put_alias.10 x-operation-group: indices.put_alias x-version-added: '1.0' description: Creates or updates an alias. @@ -1845,8 +1965,12 @@ components: schema: type: object properties: + alias: + type: string filter: $ref: '../schemas/_common.query_dsl.yaml#/components/schemas/QueryContainer' + index: + type: string index_routing: $ref: '../schemas/_common.yaml#/components/schemas/Routing' is_write_index: diff --git a/tests/indices/aliases.yaml b/tests/indices/aliases/aliases.yaml similarity index 97% rename from tests/indices/aliases.yaml rename to tests/indices/aliases/aliases.yaml index 1e28a2638..e68a6a4d6 100644 --- a/tests/indices/aliases.yaml +++ b/tests/indices/aliases/aliases.yaml @@ -1,4 +1,4 @@ -$schema: ../../json_schemas/test_story.schema.yaml +$schema: ../../../json_schemas/test_story.schema.yaml description: Test aliases endpoints. epilogues: diff --git a/tests/indices/aliases/put_alias.yaml b/tests/indices/aliases/put_alias.yaml new file mode 100644 index 000000000..7dd73fe9c --- /dev/null +++ b/tests/indices/aliases/put_alias.yaml @@ -0,0 +1,79 @@ +$schema: ../../../json_schemas/test_story.schema.yaml + +description: Test put_alias variants. +epilogues: + - path: /test_index/_alias/test_alias* + method: DELETE + status: [200, 404] + - path: /test_index + method: DELETE + status: [200, 404] +prologues: + - path: /{index} + method: PUT + parameters: + index: test_index +chapters: + - synopsis: Create an alias - specifying index & alias in path. + path: /{index}/_alias/{name} + method: PUT + parameters: + index: test_index + name: test_alias + response: + status: 200 + payload: + acknowledged: true + + - synopsis: Create an alias - specifying index in path & alias in body. + path: /{index}/_alias + method: PUT + parameters: + index: test_index + request_body: + payload: + alias: test_alias_1 + response: + status: 200 + payload: + acknowledged: true + + - synopsis: Create an alias - specifying index in body & alias in path. + path: /_alias/{name} + method: PUT + parameters: + name: test_alias_2 + request_body: + payload: + index: test_index + response: + status: 200 + payload: + acknowledged: true + + - synopsis: Create an alias - specifying index & alias in body. + path: /_alias + method: PUT + request_body: + payload: + index: test_index + alias: test_alias_3 + response: + status: 200 + payload: + acknowledged: true + + - synopsis: Retrieve aliases + path: /{index}/_alias + method: GET + parameters: + index: test_index + response: + status: 200 + payload: + test_index: + aliases: + test_alias: {} + test_alias_1: {} + test_alias_2: {} + test_alias_3: {} \ No newline at end of file From e1cd369c67149567bd4d6746f3e56e7e9a103bc8 Mon Sep 17 00:00:00 2001 From: "Daniel (dB.) Doubrovkine" Date: Thu, 18 Jul 2024 14:01:49 -0500 Subject: [PATCH 3/6] Fix _source accepting an array of fields in _search. (#430) Signed-off-by: dblock --- CHANGELOG.md | 1 + spec/schemas/_core.search.yaml | 3 + tests/_core/search/_source.yaml | 147 ++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 tests/_core/search/_source.yaml diff --git a/CHANGELOG.md b/CHANGELOG.md index ef6e64159..d520d3f8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -86,6 +86,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Fixed query DSL `match` that supports a field name and value ([#405](https://github.com/opensearch-project/opensearch-api-specification/pull/405)) - Fixed `/_mapping` with `index` in query ([#385](https://github.com/opensearch-project/opensearch-api-specification/pull/385)) - Fixed duplicate `/_nodes/{node_id}` path ([#416](https://github.com/opensearch-project/opensearch-api-specification/pull/416)) +- Fixed `_source` accepting an array of fields in `/_search` ([#430](https://github.com/opensearch-project/opensearch-api-specification/pull/430)) ### Security diff --git a/spec/schemas/_core.search.yaml b/spec/schemas/_core.search.yaml index 8e7350d06..c6e65d005 100644 --- a/spec/schemas/_core.search.yaml +++ b/spec/schemas/_core.search.yaml @@ -789,6 +789,9 @@ components: description: Defines how to fetch a source. Fetching can be disabled entirely, or the source can be filtered. oneOf: - type: boolean + - type: array + items: + $ref: '_common.yaml#/components/schemas/Field' - $ref: '#/components/schemas/SourceFilter' SourceFilter: type: object diff --git a/tests/_core/search/_source.yaml b/tests/_core/search/_source.yaml new file mode 100644 index 000000000..973eb3585 --- /dev/null +++ b/tests/_core/search/_source.yaml @@ -0,0 +1,147 @@ +$schema: ../../../json_schemas/test_story.schema.yaml + +description: Test search endpoint (_source). +prologues: + - path: /movies/_doc + method: POST + parameters: + refresh: true + request_body: + payload: + director: Bennett Miller + title: Moneyball + year: 2011 + status: [201] +epilogues: + - path: /movies + method: DELETE + status: [200, 404] +chapters: + - synopsis: Search (_source=true). + path: /{index}/_search + parameters: + index: movies + method: POST + request_body: + payload: + _source: true + query: + match_all: {} + response: + status: 200 + payload: + timed_out: false + hits: + total: + value: 1 + relation: eq + max_score: 1 + hits: + - _index: movies + _score: 1 + _source: + director: Bennett Miller + title: Moneyball + year: 2011 + - synopsis: Search (_source=false). + path: /{index}/_search + parameters: + index: movies + method: POST + request_body: + payload: + _source: false + query: + match_all: {} + response: + status: 200 + payload: + timed_out: false + hits: + total: + value: 1 + relation: eq + max_score: 1 + hits: + - _index: movies + _score: 1 + - synopsis: Search (_source=[fields]). + path: /{index}/_search + parameters: + index: movies + method: POST + request_body: + payload: + _source: + - director + - year + query: + match_all: {} + response: + status: 200 + payload: + timed_out: false + hits: + total: + value: 1 + relation: eq + max_score: 1 + hits: + - _index: movies + _score: 1 + _source: + director: Bennett Miller + year: 2011 + - synopsis: Search (_source=filter). + path: /{index}/_search + parameters: + index: movies + method: POST + request_body: + payload: + _source: + includes: director + excludes: year + query: + match_all: {} + response: + status: 200 + payload: + timed_out: false + hits: + total: + value: 1 + relation: eq + max_score: 1 + hits: + - _index: movies + _score: 1 + _source: + director: Bennett Miller + - synopsis: Search (_source=filter with wildcards). + path: /{index}/_search + parameters: + index: movies + method: POST + request_body: + payload: + _source: + includes: '*' + excludes: year + query: + match_all: {} + response: + status: 200 + payload: + timed_out: false + hits: + total: + value: 1 + relation: eq + max_score: 1 + hits: + - _index: movies + _score: 1 + _source: + director: Bennett Miller + title: Moneyball From bf2772ad020f3bb3b891f0161ddb33aaff935180 Mon Sep 17 00:00:00 2001 From: Jakob Date: Fri, 19 Jul 2024 15:08:14 +0200 Subject: [PATCH 4/6] spec: replace nullable value with null type (#436) * spec: replace nullable value with null type Signed-off-by: Jakob Hahn * spec: please the linter Signed-off-by: Jakob Hahn * ajv set allowUnionTypes Signed-off-by: Jakob Hahn --------- Signed-off-by: Jakob Hahn --- CHANGELOG.md | 1 + spec/schemas/_common.aggregations.yaml | 161 +++++------------------- spec/schemas/_common.query_dsl.yaml | 16 +-- spec/schemas/_common.yaml | 20 ++- spec/schemas/_core.bulk.yaml | 5 +- spec/schemas/_core.rank_eval.yaml | 5 +- spec/schemas/_core.search.yaml | 10 +- spec/schemas/cat.allocation.yaml | 21 ++-- spec/schemas/cat.indices.yaml | 20 +-- spec/schemas/cat.shards.yaml | 20 +-- spec/schemas/cat.templates.yaml | 3 +- spec/schemas/cat.thread_pool.yaml | 20 +-- spec/schemas/indices.stats.yaml | 5 +- tools/src/_utils/JsonSchemaValidator.ts | 5 +- 14 files changed, 75 insertions(+), 237 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d520d3f8c..3d4e347b0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Replaced the deprecated fs.rmdirSync with fs.rmSync ([#359](https://github.com/opensearch-project/opensearch-api-specification/pull/359)) - Tester tool now provides better context for non-2XX responses when --verbose is used ([#359](https://github.com/opensearch-project/opensearch-api-specification/pull/359)) - Lock testing for next release of OpenSearch to a specific SHA ([#431](https://github.com/opensearch-project/opensearch-api-specification/pull/431)) +- Replace nullable with null type ([#436](https://github.com/opensearch-project/opensearch-api-specification/pull/436)) ### Deprecated diff --git a/spec/schemas/_common.aggregations.yaml b/spec/schemas/_common.aggregations.yaml index f2c25a65f..3313b096b 100644 --- a/spec/schemas/_common.aggregations.yaml +++ b/spec/schemas/_common.aggregations.yaml @@ -113,21 +113,14 @@ components: KeyedPercentiles: type: object additionalProperties: - oneOf: - - type: string - - type: number - - nullable: true - type: string + type: ['null', number, string] ArrayPercentilesItem: type: object properties: key: type: string value: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] value_as_string: type: string required: @@ -162,10 +155,7 @@ components: description: |- The metric value. A missing value generally means that there was no data to aggregate, unless specified otherwise. - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] value_as_string: type: string required: @@ -226,20 +216,11 @@ components: count: type: number min: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] max: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] avg: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] sum: type: number min_as_string: @@ -266,40 +247,19 @@ components: - type: object properties: sum_of_squares: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] variance: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] variance_population: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] variance_sampling: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] std_deviation: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] std_deviation_population: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] std_deviation_sampling: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] std_deviation_bounds: $ref: '#/components/schemas/StandardDeviationBounds' sum_of_squares_as_string: @@ -326,35 +286,17 @@ components: type: object properties: upper: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] lower: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] upper_population: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] lower_population: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] upper_sampling: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] lower_sampling: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] required: - lower - lower_population @@ -1426,32 +1368,20 @@ components: count: type: number min_length: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] max_length: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] avg_length: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] entropy: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] distribution: oneOf: + - type: 'null' - type: object additionalProperties: type: number - - nullable: true - type: string + - type: string min_length_as_string: type: string max_length_as_string: @@ -1522,17 +1452,11 @@ components: sort: type: array items: - oneOf: - - $ref: '_common.yaml#/components/schemas/FieldValue' - - nullable: true - type: string + $ref: '_common.yaml#/components/schemas/FieldValue' metrics: type: object additionalProperties: - oneOf: - - $ref: '_common.yaml#/components/schemas/FieldValue' - - nullable: true - type: string + $ref: '_common.yaml#/components/schemas/FieldValue' required: - metrics - sort @@ -1542,10 +1466,7 @@ components: - type: object properties: value: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] value_as_string: type: string required: @@ -2544,21 +2465,13 @@ components: properties: from: description: Start of the range (inclusive). - oneOf: - - type: number - - type: string - - nullable: true - type: string + type: ['null', number, string] key: description: Custom key to return the range with. type: string to: description: End of the range (exclusive). - oneOf: - - type: number - - type: string - - nullable: true - type: string + type: ['null', number, string] GeoHashGridAggregation: allOf: - $ref: '#/components/schemas/BucketAggregationBase' @@ -2726,19 +2639,13 @@ components: properties: from: description: Start of the range. - oneOf: - - type: string - - nullable: true - type: string + type: ['null', string] mask: description: IP range defined as a CIDR mask. type: string to: description: End of the range. - oneOf: - - type: string - - nullable: true - type: string + type: ['null', string] IpPrefixAggregation: allOf: - $ref: '#/components/schemas/BucketAggregationBase' @@ -3113,8 +3020,8 @@ components: - type: array items: type: number - - nullable: true - type: string + - type: 'null' + - type: string hdr: $ref: '#/components/schemas/HdrMethod' tdigest: diff --git a/spec/schemas/_common.query_dsl.yaml b/spec/schemas/_common.query_dsl.yaml index 3fab6cef8..df09be4fd 100644 --- a/spec/schemas/_common.query_dsl.yaml +++ b/spec/schemas/_common.query_dsl.yaml @@ -1417,13 +1417,11 @@ components: from: oneOf: - $ref: '_common.yaml#/components/schemas/DateMath' - - nullable: true - type: string + - type: 'null' to: oneOf: - $ref: '_common.yaml#/components/schemas/DateMath' - - nullable: true - type: string + - type: 'null' format: $ref: '_common.yaml#/components/schemas/DateFormat' time_zone: @@ -1459,15 +1457,9 @@ components: description: Less than or equal to. type: number from: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] to: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] RankFeatureQuery: allOf: - $ref: '#/components/schemas/QueryBase' diff --git a/spec/schemas/_common.yaml b/spec/schemas/_common.yaml index b080de313..365c8826d 100644 --- a/spec/schemas/_common.yaml +++ b/spec/schemas/_common.yaml @@ -146,14 +146,12 @@ components: type: string FieldValue: description: A field value. - oneOf: - - type: number - - type: number - - type: string - - type: boolean - - nullable: true - type: string - - type: object + type: + - boolean + - 'null' + - number + - object + - string Void: description: |- The absence of any type. This is commonly used in APIs that don't return a body. @@ -1282,8 +1280,7 @@ components: licensed: type: boolean custom_foldername: - nullable: true - type: string + type: ['null', string] opensearch_version: $ref: '#/components/schemas/VersionString' required: @@ -2014,8 +2011,7 @@ components: relocating_node: oneOf: - $ref: '#/components/schemas/NodeId' - - nullable: true - type: string + - type: 'null' relocation_failure_info: $ref: '#/components/schemas/RelocationFailureInfo' required: diff --git a/spec/schemas/_core.bulk.yaml b/spec/schemas/_core.bulk.yaml index a4e03fd19..9006cfe23 100644 --- a/spec/schemas/_core.bulk.yaml +++ b/spec/schemas/_core.bulk.yaml @@ -116,10 +116,7 @@ components: x-version-removed: '2.0' _id: description: The document ID associated with the operation. - anyOf: - - type: string - - nullable: true - type: string + type: ['null', string] _index: description: |- Name of the index associated with the operation. diff --git a/spec/schemas/_core.rank_eval.yaml b/spec/schemas/_core.rank_eval.yaml index 171f44789..4527f0c05 100644 --- a/spec/schemas/_core.rank_eval.yaml +++ b/spec/schemas/_core.rank_eval.yaml @@ -156,10 +156,7 @@ components: hit: $ref: '#/components/schemas/RankEvalHit' rating: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] required: - hit RankEvalHit: diff --git a/spec/schemas/_core.search.yaml b/spec/schemas/_core.search.yaml index c6e65d005..87a2e01ef 100644 --- a/spec/schemas/_core.search.yaml +++ b/spec/schemas/_core.search.yaml @@ -19,10 +19,7 @@ components: items: $ref: '#/components/schemas/Hit' max_score: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] required: - hits TotalHits: @@ -50,10 +47,7 @@ components: _id: $ref: '_common.yaml#/components/schemas/Id' _score: - oneOf: - - type: number - - nullable: true - type: string + type: ['null', number, string] _explanation: $ref: '_core.explain.yaml#/components/schemas/Explanation' fields: diff --git a/spec/schemas/cat.allocation.yaml b/spec/schemas/cat.allocation.yaml index cfb016e91..ba6c82026 100644 --- a/spec/schemas/cat.allocation.yaml +++ b/spec/schemas/cat.allocation.yaml @@ -18,8 +18,7 @@ components: IMPORTANT: This metric double-counts disk space for hard-linked files, such as those created when shrinking, splitting, or cloning an index. anyOf: - $ref: '_common.yaml#/components/schemas/ByteSize' - - nullable: true - type: string + - type: 'null' disk.used: description: |- Total disk space in use. @@ -28,8 +27,7 @@ components: Unlike `disk.indices`, this metric does not double-count disk space for hard-linked files. anyOf: - $ref: '_common.yaml#/components/schemas/ByteSize' - - nullable: true - type: string + - type: 'null' disk.avail: description: |- Free disk space available to OpenSearch. @@ -37,32 +35,27 @@ components: Disk-based shard allocation uses this metric to assign shards to nodes based on available disk space. anyOf: - $ref: '_common.yaml#/components/schemas/ByteSize' - - nullable: true - type: string + - type: 'null' disk.total: description: Total disk space for the node, including in-use and available space. anyOf: - $ref: '_common.yaml#/components/schemas/ByteSize' - - nullable: true - type: string + - type: 'null' disk.percent: description: Total percentage of disk space in use. Calculated as `disk.used / disk.total`. anyOf: - $ref: '_common.yaml#/components/schemas/Percentage' - - nullable: true - type: string + - type: 'null' host: description: Network host for the node. Set using the `network.host` setting. anyOf: - $ref: '_common.yaml#/components/schemas/Host' - - nullable: true - type: string + - type: 'null' ip: description: IP address and port for the node. anyOf: - $ref: '_common.yaml#/components/schemas/Ip' - - nullable: true - type: string + - type: 'null' node: description: Name for the node. Set using the `node.name` setting. type: string diff --git a/spec/schemas/cat.indices.yaml b/spec/schemas/cat.indices.yaml index 974f4cbfc..32e50795c 100644 --- a/spec/schemas/cat.indices.yaml +++ b/spec/schemas/cat.indices.yaml @@ -29,16 +29,10 @@ components: type: string docs.count: description: available docs - anyOf: - - type: string - - nullable: true - type: string + type: ['null', string] docs.deleted: description: deleted docs - anyOf: - - type: string - - nullable: true - type: string + type: ['null', string] creation.date: description: index creation date (millisecond value) type: string @@ -47,16 +41,10 @@ components: type: string store.size: description: store size of primaries & replicas - anyOf: - - type: string - - nullable: true - type: string + type: ['null', string] pri.store.size: description: store size of primaries - anyOf: - - type: string - - nullable: true - type: string + type: ['null', string] completion.size: description: size of completion type: string diff --git a/spec/schemas/cat.shards.yaml b/spec/schemas/cat.shards.yaml index 65c9e94d2..4bb492c13 100644 --- a/spec/schemas/cat.shards.yaml +++ b/spec/schemas/cat.shards.yaml @@ -29,31 +29,19 @@ components: type: string docs: description: The number of documents in the shard. - anyOf: - - type: string - - nullable: true - type: string + type: ['null', string] store: description: The disk space used by the shard. - anyOf: - - type: string - - nullable: true - type: string + type: ['null', string] ip: description: The IP address of the node. - anyOf: - - type: string - - nullable: true - type: string + type: ['null', string] id: description: The unique identifier for the node. type: string node: description: The name of node. - anyOf: - - type: string - - nullable: true - type: string + type: ['null', string] sync_id: description: The sync identifier. type: string diff --git a/spec/schemas/cat.templates.yaml b/spec/schemas/cat.templates.yaml index 81c048955..ebc269250 100644 --- a/spec/schemas/cat.templates.yaml +++ b/spec/schemas/cat.templates.yaml @@ -21,8 +21,7 @@ components: description: The template version. anyOf: - $ref: '_common.yaml#/components/schemas/VersionString' - - nullable: true - type: string + - type: 'null' composed_of: description: The component templates that comprise the index template. type: string diff --git a/spec/schemas/cat.thread_pool.yaml b/spec/schemas/cat.thread_pool.yaml index bc91a875e..3d14b730a 100644 --- a/spec/schemas/cat.thread_pool.yaml +++ b/spec/schemas/cat.thread_pool.yaml @@ -60,25 +60,13 @@ components: type: string core: description: The core number of active threads allowed in a scaling thread pool. - anyOf: - - type: string - - nullable: true - type: string + type: ['null', string] max: description: The maximum number of active threads allowed in a scaling thread pool. - anyOf: - - type: string - - nullable: true - type: string + type: ['null', string] size: description: The number of active threads allowed in a fixed thread pool. - anyOf: - - type: string - - nullable: true - type: string + type: ['null', string] keep_alive: description: The thread keep alive time. - anyOf: - - type: string - - nullable: true - type: string + type: ['null', string] diff --git a/spec/schemas/indices.stats.yaml b/spec/schemas/indices.stats.yaml index 45076740f..d3301fcd0 100644 --- a/spec/schemas/indices.stats.yaml +++ b/spec/schemas/indices.stats.yaml @@ -255,10 +255,7 @@ components: primary: type: boolean relocating_node: - oneOf: - - type: string - - nullable: true - type: string + type: ['null', string] state: $ref: '#/components/schemas/ShardRoutingState' required: diff --git a/tools/src/_utils/JsonSchemaValidator.ts b/tools/src/_utils/JsonSchemaValidator.ts index e72b5654b..ff33dbc1f 100644 --- a/tools/src/_utils/JsonSchemaValidator.ts +++ b/tools/src/_utils/JsonSchemaValidator.ts @@ -22,7 +22,8 @@ interface JsonSchemaValidatorOpts { const DEFAULT_AJV_OPTS = { strict: true, - allErrors: true + allErrors: true, + allowUnionTypes: true } // Wrapper for AJV @@ -58,4 +59,4 @@ export default class JsonSchemaValidator { const errors = is_schema ? this.ajv.errors : validate_func.errors return valid ? undefined : this.errors_parser.parse(errors) } -} \ No newline at end of file +} From d8f1e0212bfedab176eae3d4d69956863633e2ff Mon Sep 17 00:00:00 2001 From: Jakob Date: Mon, 22 Jul 2024 16:21:05 +0200 Subject: [PATCH 5/6] spec: add plugins to NodeInfoSettings (#442) * spec: add plugins to NodeInfoSettings Signed-off-by: Jakob Hahn * github/opensearch-cluster: add plugins.index_state_management.job_interval to env for /_nodes/settings validation Signed-off-by: Jakob Hahn --------- Signed-off-by: Jakob Hahn --- .github/opensearch-cluster/docker-compose.yml | 3 ++- CHANGELOG.md | 1 + spec/schemas/nodes.info.yaml | 8 +++++++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/opensearch-cluster/docker-compose.yml b/.github/opensearch-cluster/docker-compose.yml index 07533766d..bdd6f2be9 100644 --- a/.github/opensearch-cluster/docker-compose.yml +++ b/.github/opensearch-cluster/docker-compose.yml @@ -9,4 +9,5 @@ services: environment: - 'OPENSEARCH_INITIAL_ADMIN_PASSWORD=${OPENSEARCH_PASSWORD:-myStrongPassword123!}' - discovery.type=single-node - - path.repo=/tmp/opensearch/repo \ No newline at end of file + - path.repo=/tmp/opensearch/repo + - plugins.index_state_management.job_interval=1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d4e347b0..76bb3ea2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Added `is_hidden` to `/{index}/_alias/{name}` and `/{index}/_aliases/{name}` ([#429](https://github.com/opensearch-project/opensearch-api-specification/pull/429)) - Added `ignore_unmapped` to `GeoDistanceQuery` ([#427](https://github.com/opensearch-project/opensearch-api-specification/pull/427)) - Added missing variants of `indices.put_alias` ([#434](https://github.com/opensearch-project/opensearch-api-specification/pull/434)) +- Added `plugins` to NodeInfoSettings ([#442](https://github.com/opensearch-project/opensearch-api-specification/pull/442)) ### Changed diff --git a/spec/schemas/nodes.info.yaml b/spec/schemas/nodes.info.yaml index a44d68d05..7086c17ca 100644 --- a/spec/schemas/nodes.info.yaml +++ b/spec/schemas/nodes.info.yaml @@ -348,6 +348,8 @@ components: $ref: '#/components/schemas/NodeInfoSettingsIngest' index: $ref: '#/components/schemas/NodeInfoSettingsIndex' + plugins: + $ref: '#/components/schemas/NodeInfoSettingsPlugins' required: - client - cluster @@ -631,6 +633,10 @@ components: type: array items: type: string + NodeInfoSettingsPlugins: + type: object + additionalProperties: + $ref: '_common.yaml#/components/schemas/FieldValue' NodeThreadPoolInfo: type: object properties: @@ -704,4 +710,4 @@ components: $ref: '#/components/schemas/NodeInfoIngestProcessor' required: - request_processors - - response_processors \ No newline at end of file + - response_processors From 34ff292223a051432363dd0c5bb310c606e1d5b1 Mon Sep 17 00:00:00 2001 From: "Daniel (dB.) Doubrovkine" Date: Mon, 22 Jul 2024 11:32:50 -0500 Subject: [PATCH 6/6] Added rudimentary test coverage counting paths being tested. (#443) * Added test coverage. Signed-off-by: dblock --- .cspell | 1 + .../pr-test-coverage-analysis.template.md | 8 +++ .github/workflows/pr-comment.yml | 3 +- .github/workflows/test-spec.yml | 59 +++++++++++++++++- CHANGELOG.md | 1 + tools/src/tester/ChapterEvaluator.ts | 1 + tools/src/tester/MergedOpenApiSpec.ts | 13 +++- tools/src/tester/ResultLogger.ts | 8 +++ tools/src/tester/StoryEvaluator.ts | 10 +-- tools/src/tester/TestResults.ts | 48 +++++++++++++++ tools/src/tester/TestRunner.ts | 13 ++-- tools/src/tester/test.ts | 12 +++- tools/src/tester/types/eval.types.ts | 9 ++- tools/src/tester/types/test.types.ts | 14 +++++ tools/tests/tester/MergedOpenApiSpec.test.ts | 57 ++++++++++------- tools/tests/tester/ResultLogger.test.ts | 26 ++++++++ tools/tests/tester/TestResults.test.ts | 55 +++++++++++++++++ .../fixtures/evals/error/chapter_error.yaml | 1 + .../fixtures/evals/failed/invalid_data.yaml | 5 ++ .../fixtures/evals/failed/not_found.yaml | 5 +- tools/tests/tester/fixtures/evals/passed.yaml | 8 +++ .../specs/complete/namespaces/nodes.yaml | 61 +++++++++++++++++++ tools/tests/tester/integ/TestRunner.test.ts | 6 +- 23 files changed, 380 insertions(+), 44 deletions(-) create mode 100644 .github/pr-comment-templates/pr-test-coverage-analysis.template.md create mode 100644 tools/src/tester/TestResults.ts create mode 100644 tools/src/tester/types/test.types.ts create mode 100644 tools/tests/tester/TestResults.test.ts create mode 100644 tools/tests/tester/fixtures/specs/complete/namespaces/nodes.yaml diff --git a/.cspell b/.cspell index f292a14d7..37a004c69 100644 --- a/.cspell +++ b/.cspell @@ -47,6 +47,7 @@ aarch actiongroup actiongroups aggregatable +argjson asciifolding authc authinfo diff --git a/.github/pr-comment-templates/pr-test-coverage-analysis.template.md b/.github/pr-comment-templates/pr-test-coverage-analysis.template.md new file mode 100644 index 000000000..27f0fe7b5 --- /dev/null +++ b/.github/pr-comment-templates/pr-test-coverage-analysis.template.md @@ -0,0 +1,8 @@ +## Spec Test Coverage Analysis +{{with .test_coverage}} + +| Total | Tested | +|-------------------|----------------------------------------------------------| +| {{.paths_count}} | {{.evaluated_paths_count}} ({{.evaluated_paths_pct}} %) | + +{{end}} \ No newline at end of file diff --git a/.github/workflows/pr-comment.yml b/.github/workflows/pr-comment.yml index f66217f69..037cca862 100644 --- a/.github/workflows/pr-comment.yml +++ b/.github/workflows/pr-comment.yml @@ -4,6 +4,7 @@ on: workflow_run: workflows: - Analyze PR Changes + - Test Spec types: - completed @@ -71,4 +72,4 @@ jobs: comment-id: ${{ steps.fc.outputs.comment-id }} issue-number: ${{ env.PR_NUMBER }} body: ${{ steps.render.outputs.result }} - edit-mode: replace \ No newline at end of file + edit-mode: replace diff --git a/.github/workflows/test-spec.yml b/.github/workflows/test-spec.yml index 8e290cdf2..6395778a1 100644 --- a/.github/workflows/test-spec.yml +++ b/.github/workflows/test-spec.yml @@ -54,4 +54,61 @@ jobs: run: docker-compose up -d - name: Run Tests - run: npm run test:spec -- --opensearch-insecure \ No newline at end of file + run: | + npm run test:spec -- --opensearch-insecure --coverage coverage/test-spec-coverage-${{ matrix.entry.version }}.json + + - name: Upload Test Coverage Results + uses: actions/upload-artifact@v4 + with: + name: coverage-${{ matrix.entry.version }} + path: coverage/test-spec-coverage-${{ matrix.entry.version }}.json + + merge-coverage: + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' + needs: test-opensearch-spec + steps: + - uses: actions/checkout@v3 + + - name: Download Spec Coverage Data + uses: actions/download-artifact@v4 + with: + path: coverage + + - name: Combine Test Coverage Data + shell: bash -eo pipefail {0} + run: | + jq -sc ' + map(to_entries) | + flatten | + group_by(.key) | + map({key: .[0].key, value: map(.value) | max}) | + from_entries | + .' $(find ./coverage -name "test-spec-coverage-*.json") > ./coverage/coverage.json + + cat ./coverage/coverage.json + + - name: Construct Comment Data Payload + shell: bash -eo pipefail {0} + run: | + jq \ + --arg pr_number ${PR_NUMBER} \ + --slurpfile test_coverage ./coverage/coverage.json \ + --null-input ' + { + "pr_number": ($pr_number), + "comment_identifier": "# Test Coverage Analysis", + "template_name": "pr-test-coverage-analysis", + "template_data": { + "test_coverage": ($test_coverage[0]) + } + } + ' | tee pr-comment.json + env: + PR_NUMBER: ${{ github.event.pull_request.number }} + + - name: Upload PR Comment Payload + uses: actions/upload-artifact@v4 + with: + name: pr-comment + path: pr-comment.json \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 76bb3ea2a..7887cdd70 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Added `ignore_unmapped` to `GeoDistanceQuery` ([#427](https://github.com/opensearch-project/opensearch-api-specification/pull/427)) - Added missing variants of `indices.put_alias` ([#434](https://github.com/opensearch-project/opensearch-api-specification/pull/434)) - 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)) ### Changed diff --git a/tools/src/tester/ChapterEvaluator.ts b/tools/src/tester/ChapterEvaluator.ts index 445c3e1c0..a75b2094e 100644 --- a/tools/src/tester/ChapterEvaluator.ts +++ b/tools/src/tester/ChapterEvaluator.ts @@ -48,6 +48,7 @@ export default class ChapterEvaluator { const output_values = ChapterOutput.extract_output_values(response, chapter.output) return { title: chapter.synopsis, + path: `${chapter.method} ${chapter.path}`, overall: { result: overall_result(Object.values(params).concat([ request_body, status, payload_body_evaluation, payload_schema_evaluation ]).concat(output_values ? [output_values] : [])) }, diff --git a/tools/src/tester/MergedOpenApiSpec.ts b/tools/src/tester/MergedOpenApiSpec.ts index 93a1e25dc..56ee8b7a9 100644 --- a/tools/src/tester/MergedOpenApiSpec.ts +++ b/tools/src/tester/MergedOpenApiSpec.ts @@ -9,9 +9,10 @@ import { OpenAPIV3 } from 'openapi-types' import { Logger } from '../Logger' -import { determine_possible_schema_types, SpecificationContext } from '../_utils'; +import { determine_possible_schema_types, HTTP_METHODS, SpecificationContext } from '../_utils'; import { SchemaVisitor } from '../_utils/SpecificationVisitor'; import OpenApiMerger from '../merger/OpenApiMerger'; +import _ from 'lodash'; // An augmented spec with additionalProperties: false. export default class MergedOpenApiSpec { @@ -37,6 +38,16 @@ export default class MergedOpenApiSpec { return (this.spec().info as any)['x-api-version'] } + paths(): Record { + var obj: Record = {} + _.entries(this.spec().paths).forEach(([path, ops]) => { + obj[path] = _.entries(_.pick(ops, HTTP_METHODS)).map(([verb, _]) => { + return verb + }) + }) + return obj + } + private inject_additional_properties(ctx: SpecificationContext, spec: OpenAPIV3.Document): void { const visitor = new SchemaVisitor((ctx, schema) => { // If already has unevaluatedProperties then don't set diff --git a/tools/src/tester/ResultLogger.ts b/tools/src/tester/ResultLogger.ts index 1032fc087..aa1518499 100644 --- a/tools/src/tester/ResultLogger.ts +++ b/tools/src/tester/ResultLogger.ts @@ -10,13 +10,16 @@ import { type ChapterEvaluation, type Evaluation, Result, type StoryEvaluation } from './types/eval.types' import { overall_result } from './helpers' import * as ansi from './Ansi' +import TestResults from './TestResults' export interface ResultLogger { log: (evaluation: StoryEvaluation) => void + log_coverage: (_results: TestResults) => void } export class NoOpResultLogger implements ResultLogger { log (_: StoryEvaluation): void { } + log_coverage(_results: TestResults): void { } } export class ConsoleResultLogger implements ResultLogger { @@ -38,6 +41,11 @@ export class ConsoleResultLogger implements ResultLogger { if (with_padding) console.log() } + log_coverage(results: TestResults): void { + console.log() + console.log(`Tested ${results.evaluated_paths_count()}/${results.spec_paths_count()} paths.`) + } + #log_story ({ result, full_path, display_path, message }: StoryEvaluation): void { this.#log_evaluation({ result, message: message ?? full_path }, ansi.cyan(ansi.b(display_path))) } diff --git a/tools/src/tester/StoryEvaluator.ts b/tools/src/tester/StoryEvaluator.ts index db751e543..719437dc0 100644 --- a/tools/src/tester/StoryEvaluator.ts +++ b/tools/src/tester/StoryEvaluator.ts @@ -25,8 +25,8 @@ export default class StoryEvaluator { this._supplemental_chapter_evaluator = supplemental_chapter_evaluator } - async evaluate({ story, display_path, full_path }: StoryFile, version: string, dry_run: boolean = false): Promise { - if (story.version !== undefined && !semver.satisfies(version, story.version)) { + async evaluate({ story, display_path, full_path }: StoryFile, version?: string, dry_run: boolean = false): Promise { + if (version != undefined && story.version !== undefined && !semver.satisfies(version, story.version)) { return { result: Result.SKIPPED, display_path, @@ -42,7 +42,7 @@ export default class StoryEvaluator { } const story_outputs = new StoryOutputs() const { evaluations: prologues, has_errors: prologue_errors } = await this.#evaluate_supplemental_chapters(story.prologues ?? [], dry_run, story_outputs) - const chapters = await this.#evaluate_chapters(story.chapters, prologue_errors, version, dry_run, story_outputs) + const chapters = await this.#evaluate_chapters(story.chapters, prologue_errors, dry_run, story_outputs, version) const { evaluations: epilogues } = await this.#evaluate_supplemental_chapters(story.epilogues ?? [], dry_run, story_outputs) return { display_path, @@ -55,13 +55,13 @@ export default class StoryEvaluator { } } - async #evaluate_chapters(chapters: Chapter[], has_errors: boolean, version: string, dry_run: boolean, story_outputs: StoryOutputs): Promise { + async #evaluate_chapters(chapters: Chapter[], has_errors: boolean, dry_run: boolean, story_outputs: StoryOutputs, version?: string): Promise { const evaluations: ChapterEvaluation[] = [] for (const chapter of chapters) { if (dry_run) { const title = chapter.synopsis || `${chapter.method} ${chapter.path}` evaluations.push({ title, overall: { result: Result.SKIPPED, message: 'Dry Run', error: undefined } }) - } else if (chapter.version !== undefined && !semver.satisfies(version, chapter.version)) { + } else if (version != undefined && chapter.version !== undefined && !semver.satisfies(version, chapter.version)) { const title = chapter.synopsis || `${chapter.method} ${chapter.path}` evaluations.push({ title, overall: { result: Result.SKIPPED, message: `Skipped because version ${version} does not satisfy ${chapter.version}.`, error: undefined } }) } else { diff --git a/tools/src/tester/TestResults.ts b/tools/src/tester/TestResults.ts new file mode 100644 index 000000000..c4ae26b78 --- /dev/null +++ b/tools/src/tester/TestResults.ts @@ -0,0 +1,48 @@ +/* +* 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 _ from "lodash"; +import MergedOpenApiSpec from "./MergedOpenApiSpec"; +import { StoryEvaluations } from "./types/eval.types"; +import { SpecTestCoverage } from "./types/test.types"; +import { write_json } from "../helpers"; + +export default class TestResults { + protected _spec: MergedOpenApiSpec + protected _evaluations: StoryEvaluations + + constructor(spec: MergedOpenApiSpec, evaluations: StoryEvaluations) { + this._spec = spec + this._evaluations = evaluations + } + + evaluated_paths_count(): number { + return _.uniq(_.compact(_.flatten(_.map(this._evaluations.evaluations, (evaluation) => + _.map(evaluation.chapters, (chapter) => chapter.path) + )))).length + } + + spec_paths_count(): number { + return Object.values(this._spec.paths()).reduce((acc, methods) => acc + methods.length, 0); + } + + test_coverage(): SpecTestCoverage { + return { + evaluated_paths_count: this.evaluated_paths_count(), + paths_count: this.spec_paths_count(), + evaluated_paths_pct: this.spec_paths_count() > 0 ? Math.round( + this.evaluated_paths_count() / this.spec_paths_count() * 100 * 100 + ) / 100 : 0, + } + } + + write_coverage(file_path: string): void { + write_json(file_path, this.test_coverage()) + } +} diff --git a/tools/src/tester/TestRunner.ts b/tools/src/tester/TestRunner.ts index 72f38d4f4..8962931f4 100644 --- a/tools/src/tester/TestRunner.ts +++ b/tools/src/tester/TestRunner.ts @@ -8,11 +8,11 @@ */ import type StoryEvaluator from './StoryEvaluator' -import { type StoryFile } from './types/eval.types' +import { StoryEvaluations, type StoryFile } from './types/eval.types' import fs from 'fs' import { type Story } from './types/story.types' import { read_yaml } from '../helpers' -import { Result, type StoryEvaluation } from './types/eval.types' +import { Result } from './types/eval.types' import { type ResultLogger } from './ResultLogger' import { basename, resolve } from 'path' import type StoryValidator from "./StoryValidator"; @@ -32,10 +32,10 @@ export default class TestRunner { this._result_logger = result_logger } - async run (story_path: string, version: string = '2.15.0', dry_run: boolean = false): Promise<{ evaluations: StoryEvaluation[], failed: boolean }> { + async run (story_path: string, version?: string, dry_run: boolean = false): Promise<{ results: StoryEvaluations, failed: boolean }> { let failed = false const story_files = this.#sort_story_files(this.#collect_story_files(resolve(story_path), '', '')) - const evaluations: StoryEvaluation[] = [] + const results: StoryEvaluations = { evaluations: [] } if (!dry_run) { const info = await this._http_client.wait_until_available() @@ -45,11 +45,12 @@ export default class TestRunner { for (const story_file of story_files) { const evaluation = this._story_validator.validate(story_file) ?? await this._story_evaluator.evaluate(story_file, version, dry_run) - evaluations.push(evaluation) + results.evaluations.push(evaluation) this._result_logger.log(evaluation) if ([Result.ERROR, Result.FAILED].includes(evaluation.result)) failed = true } - return { evaluations, failed } + + return { results, failed } } #collect_story_files (folder: string, file: string, prefix: string): StoryFile[] { diff --git a/tools/src/tester/test.ts b/tools/src/tester/test.ts index 6fa7b5f68..5c55a5446 100644 --- a/tools/src/tester/test.ts +++ b/tools/src/tester/test.ts @@ -28,6 +28,7 @@ import * as process from 'node:process' import SupplementalChapterEvaluator from './SupplementalChapterEvaluator' import MergedOpenApiSpec from './MergedOpenApiSpec' import StoryValidator from "./StoryValidator"; +import TestResults from './TestResults' const command = new Command() .description('Run test stories against the OpenSearch spec.') @@ -44,6 +45,7 @@ const command = new Command() .addOption(OPENSEARCH_USERNAME_OPTION) .addOption(OPENSEARCH_PASSWORD_OPTION) .addOption(OPENSEARCH_INSECURE_OPTION) + .addOption(new Option('--coverage ', 'path to write test coverage results to')) .allowExcessArguments(false) .parse() @@ -62,7 +64,15 @@ const runner = new TestRunner(http_client, story_validator, story_evaluator, res runner.run(opts.testsPath, spec.api_version(), opts.dryRun) .then( - ({ failed }) => { + ({ results, failed }) => { + + const test_results = new TestResults(spec, results) + result_logger.log_coverage(test_results) + if (opts.coverage !== undefined) { + console.log(`Writing ${opts.coverage} ...`) + test_results.write_coverage(opts.coverage) + } + if (failed) process.exit(1) }, err => { throw err }) diff --git a/tools/src/tester/types/eval.types.ts b/tools/src/tester/types/eval.types.ts index f8fe386f9..0097361e3 100644 --- a/tools/src/tester/types/eval.types.ts +++ b/tools/src/tester/types/eval.types.ts @@ -28,9 +28,14 @@ export interface StoryEvaluation { prologues?: ChapterEvaluation[] } +export interface StoryEvaluations { + evaluations: StoryEvaluation[] +} + export interface ChapterEvaluation { - title: string - overall: Evaluation + title: string, + overall: Evaluation, + path?: string, request?: { parameters?: Record request_body?: Evaluation diff --git a/tools/src/tester/types/test.types.ts b/tools/src/tester/types/test.types.ts new file mode 100644 index 000000000..c0e14717a --- /dev/null +++ b/tools/src/tester/types/test.types.ts @@ -0,0 +1,14 @@ +/* +* 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. +*/ + +export interface SpecTestCoverage { + paths_count: number + evaluated_paths_count: number, + evaluated_paths_pct: number +} diff --git a/tools/tests/tester/MergedOpenApiSpec.test.ts b/tools/tests/tester/MergedOpenApiSpec.test.ts index 2acda940d..2c656082d 100644 --- a/tools/tests/tester/MergedOpenApiSpec.test.ts +++ b/tools/tests/tester/MergedOpenApiSpec.test.ts @@ -10,36 +10,47 @@ import { Logger } from 'Logger' import MergedOpenApiSpec from "tester/MergedOpenApiSpec" -describe('unevaluatedProperties', () => { +describe('merged API spec', () => { const spec = new MergedOpenApiSpec('tools/tests/tester/fixtures/specs/complete', new Logger()) - const responses: any = spec.spec().components?.responses test('has an api version', () => { expect(spec.api_version()).toEqual('1.2.3') }) - test('is added with required fields', () => { - const schema = responses['info@200'].content['application/json'].schema - expect(schema.unevaluatedProperties).toEqual({ not: true, errorMessage: 'property is not defined in the spec' }) + test('paths', () => { + expect(spec.paths()).toEqual({ + '/_nodes/{id}': ['get', 'post'], + '/index': ['get'], + '/nodes': ['get'] + }) }) - test('is added when no required fields', () => { - const schema = responses['info@500'].content['application/json'].schema - expect(schema.unevaluatedProperties).toEqual({ not: true, errorMessage: 'property is not defined in the spec' }) - }) - - test('is not added to empty object schema', () => { - const schema = responses['info@503'].content['application/json'].schema - expect(schema.unevaluatedProperties).toBeUndefined() - }) - - test('is not added when true', () => { - const schema = responses['info@201'].content['application/json'].schema - expect(schema.unevaluatedProperties).toEqual(true) - }) - - test('is not added when object', () => { - const schema = responses['info@404'].content['application/json'].schema - expect(schema.unevaluatedProperties).toEqual({ type: 'object' }) + describe('unevaluatedProperties', () => { + const responses: any = spec.spec().components?.responses + + test('is added with required fields', () => { + const schema = responses['info@200'].content['application/json'].schema + expect(schema.unevaluatedProperties).toEqual({ not: true, errorMessage: 'property is not defined in the spec' }) + }) + + test('is added when no required fields', () => { + const schema = responses['info@500'].content['application/json'].schema + expect(schema.unevaluatedProperties).toEqual({ not: true, errorMessage: 'property is not defined in the spec' }) + }) + + test('is not added to empty object schema', () => { + const schema = responses['info@503'].content['application/json'].schema + expect(schema.unevaluatedProperties).toBeUndefined() + }) + + test('is not added when true', () => { + const schema = responses['info@201'].content['application/json'].schema + expect(schema.unevaluatedProperties).toEqual(true) + }) + + test('is not added when object', () => { + const schema = responses['info@404'].content['application/json'].schema + expect(schema.unevaluatedProperties).toEqual({ type: 'object' }) + }) }) }) diff --git a/tools/tests/tester/ResultLogger.test.ts b/tools/tests/tester/ResultLogger.test.ts index 8c0470dae..2eea82b2d 100644 --- a/tools/tests/tester/ResultLogger.test.ts +++ b/tools/tests/tester/ResultLogger.test.ts @@ -10,6 +10,8 @@ import { ConsoleResultLogger } from "tester/ResultLogger" import { Result } from "tester/types/eval.types" import * as ansi from 'tester/Ansi' +import MergedOpenApiSpec from "tester/MergedOpenApiSpec" +import TestResults from "tester/TestResults" describe('ConsoleResultLogger', () => { let log: jest.Mock @@ -52,6 +54,30 @@ describe('ConsoleResultLogger', () => { [] ]) }) + + test('log_coverage', () => { + const spec = new MergedOpenApiSpec('tools/tests/tester/fixtures/specs/complete') + const test_results = new TestResults(spec, { evaluations: [{ + result: Result.PASSED, + display_path: 'path', + full_path: 'path', + description: 'description', + chapters: [ + { + title: 'title', + overall: { result: Result.PASSED }, + path: 'path' + } + ] + }] }) + + logger.log_coverage(test_results) + + expect(log.mock.calls).toEqual([ + [], + ['Tested 1/4 paths.'] + ]) + }) }) describe('verbose=false', () => { diff --git a/tools/tests/tester/TestResults.test.ts b/tools/tests/tester/TestResults.test.ts new file mode 100644 index 000000000..fb8b25853 --- /dev/null +++ b/tools/tests/tester/TestResults.test.ts @@ -0,0 +1,55 @@ +/* +* 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 MergedOpenApiSpec from "tester/MergedOpenApiSpec" +import TestResults from "tester/TestResults" +import { Result } from "tester/types/eval.types" +import fs from 'fs' + +describe('TestResults', () => { + const spec = new MergedOpenApiSpec('tools/tests/tester/fixtures/specs/complete') + + const evaluations = [{ + result: Result.PASSED, + display_path: 'path', + full_path: 'full_path', + description: 'description', + message: 'message', + chapters: [{ + title: 'title', + overall: { + result: Result.PASSED + }, + path: 'path' + }], + epilogues: [], + prologues: [] + }] + + const test_results = new TestResults(spec, { evaluations }) + + test('evaluated_paths_count', () => { + expect(test_results.evaluated_paths_count()).toEqual(1) + }) + + test('spec_paths_count', () => { + expect(test_results.spec_paths_count()).toEqual(4) + }) + + test('write_coverage', () => { + const filename = 'coverage.json' + test_results.write_coverage(filename) + expect(JSON.parse(fs.readFileSync(filename, 'utf8'))).toEqual({ + evaluated_paths_count: 1, + evaluated_paths_pct: 25, + paths_count: 4 + }) + fs.unlinkSync(filename) + }) +}) diff --git a/tools/tests/tester/fixtures/evals/error/chapter_error.yaml b/tools/tests/tester/fixtures/evals/error/chapter_error.yaml index 704c71ba4..37f1baba4 100644 --- a/tools/tests/tester/fixtures/evals/error/chapter_error.yaml +++ b/tools/tests/tester/fixtures/evals/error/chapter_error.yaml @@ -17,6 +17,7 @@ chapters: - title: This chapter show throw an error. overall: result: ERROR + path: DELETE /{index} request: parameters: {} request_body: diff --git a/tools/tests/tester/fixtures/evals/failed/invalid_data.yaml b/tools/tests/tester/fixtures/evals/failed/invalid_data.yaml index ec0c9043f..a05ae7aa7 100644 --- a/tools/tests/tester/fixtures/evals/failed/invalid_data.yaml +++ b/tools/tests/tester/fixtures/evals/failed/invalid_data.yaml @@ -10,6 +10,7 @@ chapters: - title: This chapter should fail because the parameter is invalid. overall: result: FAILED + path: PUT /{index} request: parameters: index: @@ -27,6 +28,7 @@ chapters: - title: This chapter should fail because the request body is invalid. overall: result: FAILED + path: PUT /{index} request: parameters: index: @@ -44,6 +46,7 @@ chapters: - title: This chapter should fail because the response content type does not match. overall: result: FAILED + path: GET /_cat/indices/{index} request: parameters: format: @@ -63,6 +66,7 @@ chapters: - title: This chapter should fail because the response data and schema are invalid. overall: result: FAILED + path: DELETE /{index} request: parameters: index: @@ -81,6 +85,7 @@ chapters: - title: This chapter should fail because the response status does not match. overall: result: ERROR + path: PUT /{index} request: parameters: index: diff --git a/tools/tests/tester/fixtures/evals/failed/not_found.yaml b/tools/tests/tester/fixtures/evals/failed/not_found.yaml index 766fb3b99..72bc6318b 100644 --- a/tools/tests/tester/fixtures/evals/failed/not_found.yaml +++ b/tools/tests/tester/fixtures/evals/failed/not_found.yaml @@ -14,6 +14,7 @@ chapters: - title: This chapter should fail because the parameter is not defined in the spec. overall: result: FAILED + path: PUT /{index} request: parameters: index: @@ -33,6 +34,7 @@ chapters: - title: This chapter should fail because the request body is not defined in the spec. overall: result: FAILED + path: HEAD /{index} request: parameters: index: @@ -50,6 +52,7 @@ chapters: - title: This chapter should fail because the response is not defined in the spec. overall: result: FAILED + path: DELETE /{index} request: parameters: index: @@ -68,4 +71,4 @@ chapters: epilogues: - title: DELETE /books overall: - result: PASSED \ No newline at end of file + result: PASSED diff --git a/tools/tests/tester/fixtures/evals/passed.yaml b/tools/tests/tester/fixtures/evals/passed.yaml index 6808a9da1..375b24f26 100644 --- a/tools/tests/tester/fixtures/evals/passed.yaml +++ b/tools/tests/tester/fixtures/evals/passed.yaml @@ -10,6 +10,7 @@ chapters: - title: This PUT /{index} chapter should pass. overall: result: PASSED + path: PUT /{index} request: parameters: index: @@ -26,6 +27,7 @@ chapters: - title: This GET /_cat chapter returns text/plain and should pass. overall: result: PASSED + path: GET /_cat request: parameters: {} request_body: @@ -40,6 +42,7 @@ chapters: - title: This GET /_cat/health chapter returns application/json and should pass. overall: result: PASSED + path: GET /_cat/health request: parameters: format: @@ -56,6 +59,7 @@ chapters: - title: This GET /_cat/health chapter returns application/yaml and should pass. overall: result: PASSED + path: GET /_cat/health request: parameters: format: @@ -72,6 +76,7 @@ chapters: - title: This GET /_cat/health chapter returns application/cbor and should pass. overall: result: PASSED + path: GET /_cat/health request: parameters: format: @@ -88,6 +93,7 @@ chapters: - title: This GET /_cat/health chapter returns application/smile and should pass. overall: result: PASSED + path: GET /_cat/health request: parameters: format: @@ -104,6 +110,7 @@ chapters: - title: This GET /_cat/health should run (default). overall: result: PASSED + path: GET /_cat/health request: parameters: format: @@ -120,6 +127,7 @@ chapters: - title: This GET /_cat/health should run (~> 2.x). overall: result: PASSED + path: GET /_cat/health request: parameters: format: diff --git a/tools/tests/tester/fixtures/specs/complete/namespaces/nodes.yaml b/tools/tests/tester/fixtures/specs/complete/namespaces/nodes.yaml new file mode 100644 index 000000000..87abb9dbe --- /dev/null +++ b/tools/tests/tester/fixtures/specs/complete/namespaces/nodes.yaml @@ -0,0 +1,61 @@ +openapi: 3.1.0 +info: + title: OpenSearch API + description: OpenSearch API + version: 1.0.0 +paths: + /nodes: + get: + operationId: nodes.0 + responses: + '200': + $ref: '#/components/responses/nodes.info@200' + /_nodes/{id}: + get: + operationId: nodes.info.1 + x-operation-group: nodes.info + x-version-added: '1.0' + description: Returns information about nodes in the cluster. + parameters: + - $ref: '#/components/parameters/nodes.info::path.id' + responses: + '200': + $ref: '#/components/responses/nodes.info@200' + post: + operationId: nodes.info.1 + x-operation-group: nodes.info + x-version-added: '1.0' + description: Returns information about nodes in the cluster. + parameters: + - $ref: '#/components/parameters/nodes.info::path.id' + requestBody: + $ref: '#/components/requestBodies/nodes.info' + responses: + '200': + $ref: '#/components/responses/nodes.info@200' +components: + requestBodies: + nodes.info: + content: + application/json: + schema: + type: object + properties: + _all: + type: boolean + description: Nodes options. + parameters: + nodes.info::path.id: + in: path + name: id + description: Node ID. + required: true + schema: + type: string + responses: + nodes.info@200: + description: All nodes. + content: + application/json: + schema: + type: object diff --git a/tools/tests/tester/integ/TestRunner.test.ts b/tools/tests/tester/integ/TestRunner.test.ts index 8a706b6b1..4e06a109c 100644 --- a/tools/tests/tester/integ/TestRunner.test.ts +++ b/tools/tests/tester/integ/TestRunner.test.ts @@ -16,13 +16,13 @@ test('stories folder', async () => { const info = await opensearch_http_client.wait_until_available() expect(info.version).toBeDefined() - const result = await test_runner.run('tools/tests/tester/fixtures/stories') + const run = await test_runner.run('tools/tests/tester/fixtures/stories') - expect(result.failed).toBeTruthy() + expect(run.failed).toBeTruthy() const actual_evaluations: Array> = [] - for (const evaluation of result.evaluations) { + for (const evaluation of run.results.evaluations) { const { full_path, ...rest } = flatten_errors(evaluation) expect(full_path.endsWith(rest.display_path)).toBeTruthy() actual_evaluations.push(rest)