diff --git a/.github/workflows/test-spec.yml b/.github/workflows/test-spec.yml index 06a098265..a4c354c89 100644 --- a/.github/workflows/test-spec.yml +++ b/.github/workflows/test-spec.yml @@ -38,6 +38,8 @@ jobs: tests: snapshot - version: 2.17.0 tests: plugins/streaming + - version: 2.17.0 + tests: plugins/notifications - version: 2.18.0 hub: opensearchstaging ref: '@sha256:4445e195c53992038891519dc3be0d273cdaad1b047943d68921168ed243e7e9' diff --git a/.lycheeignore b/.lycheeignore index c859dd4da..caa2546d0 100644 --- a/.lycheeignore +++ b/.lycheeignore @@ -1 +1,2 @@ https://localhost:* +http://webhook:8080 diff --git a/CHANGELOG.md b/CHANGELOG.md index f92d956a6..b53b5bb60 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -101,6 +101,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Added `persian_stem` filter ([#592](https://github.com/opensearch-project/opensearch-api-specification/pull/592)) - Added `404` response for `DELETE /{index}`, `GET /{index}/_doc/{id}`, `DELETE /{index}/_doc/{id}` ([#589](https://github.com/opensearch-project/opensearch-api-specification/pull/589)) - Added ability to pass `InlineScript` as a simple string ([#605](https://github.com/opensearch-project/opensearch-api-specification/pull/605)) +- Added `config_id` and `config_id_list` to `/_plugins/_notifications/configs` query parameters ([#594](https://github.com/opensearch-project/opensearch-api-specification/pull/594)) ### Changed @@ -172,8 +173,9 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Fixed create/delete/index operation in `_bulk` ([#582](https://github.com/opensearch-project/opensearch-api-specification/pull/582)) - Add `mode` and `compression` to k-NN index creation and search, and add `rescore` and `oversample_factor` to k-NN search ([#588](https://github.com/opensearch-project/opensearch-api-specification/pull/588)) - Fixed `/{index}/_search` with aggregations ([#576](https://github.com/opensearch-project/opensearch-api-specification/pull/576)) -- Fixed inaccurate numeric type ([#597](https://github.com/opensearch-project/opensearch-api-specification/pull/597))([#598](https://github.com/opensearch-project/opensearch-api-specification/pull/598))([#600](https://github.com/opensearch-project/opensearch-api-specification/pull/600)) - Fixed mapping and analysis types ([#600](https://github.com/opensearch-project/opensearch-api-specification/pull/600)) +- Fixed inaccurate numeric type ([#597](https://github.com/opensearch-project/opensearch-api-specification/pull/597))([#598](https://github.com/opensearch-project/opensearch-api-specification/pull/598))([#600](https://github.com/opensearch-project/opensearch-api-specification/pull/600)) +- Fixed `RestStatus` responses in `DELETE /_plugins/_notifications/configs/{config_id}` ([#594](https://github.com/opensearch-project/opensearch-api-specification/pull/594)) ### Security diff --git a/spec/namespaces/notifications.yaml b/spec/namespaces/notifications.yaml index 00faf3941..811a2f21b 100644 --- a/spec/namespaces/notifications.yaml +++ b/spec/namespaces/notifications.yaml @@ -26,6 +26,8 @@ paths: parameters: - $ref: '#/components/parameters/notifications.get_configs::query.chime.url' - $ref: '#/components/parameters/notifications.get_configs::query.chime.url.keyword' + - $ref: '#/components/parameters/notifications.get_configs::query.config_id' + - $ref: '#/components/parameters/notifications.get_configs::query.config_id_list' - $ref: '#/components/parameters/notifications.get_configs::query.config_type' - $ref: '#/components/parameters/notifications.get_configs::query.created_time_ms' - $ref: '#/components/parameters/notifications.get_configs::query.description' @@ -318,6 +320,20 @@ components: in: query schema: type: string + notifications.get_configs::query.config_id: + name: config_id + in: query + description: Notification configuration ID. + schema: + type: string + notifications.get_configs::query.config_id_list: + name: config_id_list + in: query + description: Notification configuration IDs. + schema: + type: array + items: + type: string notifications.get_configs::query.config_type: name: config_type in: query diff --git a/spec/schemas/notifications._common.yaml b/spec/schemas/notifications._common.yaml index 55d1a0040..667eb0847 100644 --- a/spec/schemas/notifications._common.yaml +++ b/spec/schemas/notifications._common.yaml @@ -34,23 +34,14 @@ components: RestStatus: type: string enum: - - accepted - - continue - - created - - found - - moved_permanently - - multi_status - - multiple_choices - - no_content - - non_authoritative_information - - not_modified - - ok - - partial_content - - reset_content - - see_other - - switching_protocols - - temporary_redirect - - use_proxy + - ACCEPTED + - CREATED + - MULTI_STATUS + - NON_AUTHORITATIVE_INFORMATION + - NO_CONTENT + - OK + - PARTIAL_CONTENT + - RESET_CONTENT NotificationConfigType: type: string description: Type of notification configuration. diff --git a/tests/default/notifications/channels.yaml b/tests/default/notifications/channels.yaml new file mode 100644 index 000000000..d45fea828 --- /dev/null +++ b/tests/default/notifications/channels.yaml @@ -0,0 +1,10 @@ +$schema: ../../../json_schemas/test_story.schema.yaml + +description: Test listing channels. +version: '>= 2.0' +chapters: + - synopsis: Retrieve a list of all notification channels. + path: /_plugins/_notifications/channels + method: GET + response: + status: 200 diff --git a/tests/default/notifications/configs.yaml b/tests/default/notifications/configs.yaml new file mode 100644 index 000000000..3a1523f1e --- /dev/null +++ b/tests/default/notifications/configs.yaml @@ -0,0 +1,97 @@ +$schema: ../../../json_schemas/test_story.schema.yaml + +description: Test listing notification configs. +version: '>= 2.0' +chapters: + - synopsis: Create a channel configuration. + path: /_plugins/_notifications/configs + method: POST + request: + payload: + config_id: webhook-configuration + config: + name: Notifications Channel + description: Default notifications channel. + config_type: webhook + is_enabled: true + webhook: + url: http://webhook:8080/ + response: + status: 200 + - synopsis: Update a channel configuration. + path: /_plugins/_notifications/configs/{config_id} + method: PUT + parameters: + config_id: webhook-configuration + request: + payload: + config: + name: Notifications Channel + config_type: webhook + is_enabled: true + webhook: + url: http://webhook:8080/ + response: + status: 200 + - synopsis: Retrieve a list of all notification configurations. + path: /_plugins/_notifications/configs + method: GET + retry: + count: 2 + response: + status: 200 + payload: + config_list: + - config_id: webhook-configuration + - synopsis: Retrieve a list of all notification configurations filtered by config ID. + path: /_plugins/_notifications/configs + method: GET + parameters: + config_type: webhook + response: + status: 200 + payload: + config_list: + - config_id: webhook-configuration + - synopsis: Retrieve a notification configuration by config ID (path). + path: /_plugins/_notifications/configs/{config_id} + method: GET + parameters: + config_id: webhook-configuration + response: + status: 200 + payload: + config_list: + - config_id: webhook-configuration + - synopsis: Retrieve a notification configuration by config ID (query). + path: /_plugins/_notifications/configs + method: GET + parameters: + config_id: webhook-configuration + response: + status: 200 + payload: + config_list: + - config_id: webhook-configuration + - synopsis: Retrieve a notification configuration by config ID list (query). + path: /_plugins/_notifications/configs + method: GET + parameters: + config_id_list: + - webhook-configuration + response: + status: 200 + payload: + config_list: + - config_id: webhook-configuration + - synopsis: Delete a channel configuration. + path: /_plugins/_notifications/configs/{config_id} + method: DELETE + parameters: + config_id: webhook-configuration + response: + status: 200 +epilogues: + - path: /_plugins/_notifications/configs/webhook-configuration + method: DELETE + status: [200,404] diff --git a/tests/default/notifications/features.yaml b/tests/default/notifications/features.yaml new file mode 100644 index 000000000..6c11b90b1 --- /dev/null +++ b/tests/default/notifications/features.yaml @@ -0,0 +1,10 @@ +$schema: ../../../json_schemas/test_story.schema.yaml + +description: Test listing supported channel configurations. +version: '>= 2.0' +chapters: + - synopsis: Retrieve a list of all supported notification configuration types. + path: /_plugins/_notifications/features + method: GET + response: + status: 200 diff --git a/tests/plugins/notifications/docker-compose.yml b/tests/plugins/notifications/docker-compose.yml new file mode 100644 index 000000000..937846f3c --- /dev/null +++ b/tests/plugins/notifications/docker-compose.yml @@ -0,0 +1,19 @@ +version: '3' + +services: + opensearch-cluster: + image: ${OPENSEARCH_DOCKER_HUB_PROJECT:-opensearchproject}/opensearch:${OPENSEARCH_VERSION:-latest}${OPENSEARCH_DOCKER_REF} + ports: + - 9200:9200 + - 9600:9600 + environment: + - OPENSEARCH_INITIAL_ADMIN_PASSWORD=${OPENSEARCH_PASSWORD:-myStrongPassword123!} + - OPENSEARCH_JAVA_OPTS=${OPENSEARCH_JAVA_OPTS} + - discovery.type=single-node + webhook: + image: python:latest + volumes: + - ./server.py:/server.py + ports: + - '8080:8080' + entrypoint: python server.py diff --git a/tests/plugins/notifications/notifications/feature/test.yaml b/tests/plugins/notifications/notifications/feature/test.yaml new file mode 100644 index 000000000..e889155e1 --- /dev/null +++ b/tests/plugins/notifications/notifications/feature/test.yaml @@ -0,0 +1,37 @@ +$schema: ../../../../../json_schemas/test_story.schema.yaml + +description: Test sending a notification. +version: '>= 2.0' +prologues: + - path: /_plugins/_notifications/configs + method: POST + request: + payload: + config_id: custom-webhook-configuration + config: + name: Notifications Channel + description: Default notifications channel. + config_type: webhook + is_enabled: true + webhook: + url: http://webhook:8080/ + status: [200] +chapters: + - synopsis: Test sending a notification. + path: /_plugins/_notifications/feature/test/{config_id} + method: GET + parameters: + config_id: custom-webhook-configuration + response: + status: 200 + payload: + status_list: + - config_id: custom-webhook-configuration + config_type: webhook + delivery_status: + status_code: '200' + status_text: '{"ok":"true"}' +epilogues: + - path: /_plugins/_notifications/configs/custom-webhook-configuration + method: DELETE + status: [200,404] diff --git a/tests/plugins/notifications/server.py b/tests/plugins/notifications/server.py new file mode 100644 index 000000000..20de61d94 --- /dev/null +++ b/tests/plugins/notifications/server.py @@ -0,0 +1,31 @@ +# +# 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. +# + +from http.server import BaseHTTPRequestHandler, HTTPServer + + +class SimpleHTTPRequestHandler(BaseHTTPRequestHandler): + def do_GET(self): + self.send_response(200) + self.send_header("Content-type", "application_json") + self.end_headers() + self.wfile.write(b'{"ok":"true"}') + + def do_POST(self): + self.send_response(200) + self.send_header("Content-type", "application_json") + self.end_headers() + self.wfile.write(b'{"ok":"true"}') + + +if __name__ == "__main__": + server_address = ("", 8080) + httpd = HTTPServer(server_address, SimpleHTTPRequestHandler) + print("Server started on http://localhost:8080") + httpd.serve_forever() diff --git a/tools/src/tester/TestRunner.ts b/tools/src/tester/TestRunner.ts index 7b36af3b9..6317ef392 100644 --- a/tools/src/tester/TestRunner.ts +++ b/tools/src/tester/TestRunner.ts @@ -70,7 +70,7 @@ export default class TestRunner { #collect_story_files (folder: string, file: string, prefix: string): StoryFile[] { const path = file === '' ? folder : `${folder}/${file}` const next_prefix = prefix === '' ? file : `${prefix}/${file}` - if (file.startsWith('.') || file == 'docker-compose.yml' || file == 'Dockerfile') { + if (file.startsWith('.') || file == 'docker-compose.yml' || file == 'Dockerfile' || file.endsWith('.py')) { return [] } else if (fs.statSync(path).isFile()) { const story: Story = read_yaml(path) diff --git a/tools/tests/tester/integ/TestRunner.test.ts b/tools/tests/tester/integ/TestRunner.test.ts index 75253cd7c..a747f1b64 100644 --- a/tools/tests/tester/integ/TestRunner.test.ts +++ b/tools/tests/tester/integ/TestRunner.test.ts @@ -53,4 +53,10 @@ describe('story_files', () => { story_file => story_file.display_path )).not.toContain('nodes/plugins/docker-compose.yml') }) + + test('does not contain a python script', () => { + expect(test_runner.story_files('tests/plugins/notifications').map( + story_file => story_file.display_path + )).not.toContain('nodes/plugins/server.py') + }) })