From 36c3ce58bc4ba655bb06cf24df86a627810434e4 Mon Sep 17 00:00:00 2001 From: AWSHurneyt Date: Wed, 15 Dec 2021 11:21:02 -0800 Subject: [PATCH 1/9] Implemented draft of Finding data model, and some basic unit tests for it. Signed-off-by: AWSHurneyt Signed-off-by: AWSHurneyt --- .../org/opensearch/alerting/model/Finding.kt | 202 ++++++++++++++++++ .../org/opensearch/alerting/TestHelpers.kt | 33 ++- .../opensearch/alerting/model/FindingTests.kt | 73 +++++++ 3 files changed, 307 insertions(+), 1 deletion(-) create mode 100644 alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt create mode 100644 alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt diff --git a/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt b/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt new file mode 100644 index 000000000..4a0d4e218 --- /dev/null +++ b/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt @@ -0,0 +1,202 @@ +/* + * 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. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package org.opensearch.alerting.model + +import org.opensearch.alerting.elasticapi.instant +import org.opensearch.common.io.stream.StreamInput +import org.opensearch.common.io.stream.StreamOutput +import org.opensearch.common.io.stream.Writeable +import org.opensearch.common.lucene.uid.Versions +import org.opensearch.common.xcontent.ToXContent +import org.opensearch.common.xcontent.XContentBuilder +import org.opensearch.common.xcontent.XContentParser +import org.opensearch.common.xcontent.XContentParserUtils.ensureExpectedToken +import org.opensearch.commons.authuser.User +import java.io.IOException +import java.time.Instant + +class Finding( + val id: String = NO_ID, + val logEventId: String = NO_ID, + val monitorId: String, + val monitorName: String, + val monitorUser: User?, + val monitorVersion: Long = NO_VERSION, + val ruleId: String = NO_ID, + val ruleTags: List, + val severity: String, + val timestamp: Instant, + val triggerId: String, + val triggerName: String +) : Writeable, ToXContent { + + @Throws(IOException::class) + constructor(sin: StreamInput) : this( + id = sin.readString(), + logEventId = sin.readString(), + monitorId = sin.readString(), + monitorName = sin.readString(), + monitorUser = if (sin.readBoolean()) User(sin) else null, + monitorVersion = sin.readLong(), + ruleId = sin.readString(), + ruleTags = sin.readStringList(), + severity = sin.readString(), + timestamp = sin.readInstant(), + triggerId = sin.readString(), + triggerName = sin.readString() + ) + + fun asTemplateArg(): Map { + return mapOf( + FINDING_ID_FIELD to id, + LOG_EVENT_ID_FIELD to logEventId, + MONITOR_ID_FIELD to monitorId, + MONITOR_NAME_FIELD to monitorName, + MONITOR_VERSION_FIELD to monitorVersion, + RULE_ID_FIELD to ruleId, + RULE_TAGS_FIELD to ruleTags, + SEVERITY_FIELD to severity, + TIMESTAMP_FIELD to timestamp.toEpochMilli(), + TRIGGER_ID_FIELD to triggerId, + TRIGGER_NAME_FIELD to triggerName + ) + } + + override fun toXContent(builder: XContentBuilder, params: ToXContent.Params): XContentBuilder { + builder.startObject() + .field(FINDING_ID_FIELD, id) + .field(LOG_EVENT_ID_FIELD, logEventId) + .field(MONITOR_ID_FIELD, monitorId) + .field(MONITOR_NAME_FIELD, monitorName) + .field(MONITOR_USER_FIELD, monitorUser) + .field(MONITOR_VERSION_FIELD, monitorVersion) + .field(RULE_ID_FIELD, ruleId) + .field(RULE_TAGS_FIELD, ruleTags.toTypedArray()) + .field(SEVERITY_FIELD, severity) + .field(TIMESTAMP_FIELD, timestamp) + .field(TRIGGER_ID_FIELD, triggerId) + .field(TRIGGER_NAME_FIELD, triggerName) + builder.endObject() + return builder + } + + @Throws(IOException::class) + override fun writeTo(out: StreamOutput) { + out.writeString(id) + out.writeString(logEventId) + out.writeString(monitorId) + out.writeString(monitorName) + monitorUser?.writeTo(out) + out.writeLong(monitorVersion) + out.writeString(ruleId) + out.writeStringCollection(ruleTags) + out.writeString(severity) + out.writeInstant(timestamp) + out.writeString(triggerId) + out.writeString(triggerName) + } + + companion object { + const val FINDING_ID_FIELD = "id" + const val LOG_EVENT_ID_FIELD = "log_event_id" + const val MONITOR_ID_FIELD = "monitor_id" + const val MONITOR_NAME_FIELD = "monitor_name" + const val MONITOR_USER_FIELD = "monitor_user" + const val MONITOR_VERSION_FIELD = "monitor_version" + const val RULE_ID_FIELD = "rule_id" + const val RULE_TAGS_FIELD = "rule_tags" + const val SEVERITY_FIELD = "severity" + const val TIMESTAMP_FIELD = "timestamp" + const val TRIGGER_ID_FIELD = "trigger_id" + const val TRIGGER_NAME_FIELD = "trigger_name" + const val NO_ID = "" + const val NO_VERSION = Versions.NOT_FOUND + + @JvmStatic @JvmOverloads + @Throws(IOException::class) + fun parse(xcp: XContentParser, id: String = NO_ID): Finding { + var logEventId: String = NO_ID + lateinit var monitorId: String + lateinit var monitorName: String + var monitorUser: User? = null + var monitorVersion: Long = NO_VERSION + var ruleId: String = NO_ID + val ruleTags: MutableList = mutableListOf() + lateinit var severity: String + lateinit var timestamp: Instant + lateinit var triggerId: String + lateinit var triggerName: String + + ensureExpectedToken(XContentParser.Token.START_OBJECT, xcp.currentToken(), xcp) + while (xcp.nextToken() != XContentParser.Token.END_OBJECT) { + val fieldName = xcp.currentName() + xcp.nextToken() + + when (fieldName) { + LOG_EVENT_ID_FIELD -> logEventId = xcp.text() + MONITOR_ID_FIELD -> monitorId = xcp.text() + MONITOR_NAME_FIELD -> monitorName = xcp.text() + MONITOR_USER_FIELD -> monitorUser = if (xcp.currentToken() == XContentParser.Token.VALUE_NULL) null else User.parse(xcp) + MONITOR_VERSION_FIELD -> monitorVersion = xcp.longValue() + RULE_ID_FIELD -> ruleId = xcp.text() + RULE_TAGS_FIELD -> { + ensureExpectedToken(XContentParser.Token.START_ARRAY, xcp.currentToken(), xcp) + // TODO dev code: investigate implementing error logging +// while (xcp.nextToken() != XContentParser.Token.END_ARRAY) { +// errorHistory.add(FindingError.parse(xcp)) +// } + } + SEVERITY_FIELD -> severity = xcp.text() + TIMESTAMP_FIELD -> timestamp = requireNotNull(xcp.instant()) + TRIGGER_ID_FIELD -> triggerId = xcp.text() + TRIGGER_NAME_FIELD -> triggerName = xcp.text() + } + } + + return Finding( + id = id, + logEventId = logEventId, + monitorId = monitorId, + monitorName = monitorName, + monitorUser = monitorUser, + monitorVersion = monitorVersion, + ruleId = ruleId, + ruleTags = ruleTags, + severity = severity, + timestamp = timestamp, + triggerId = triggerId, + triggerName = triggerName + ) + } + + @JvmStatic + @Throws(IOException::class) + fun readFrom(sin: StreamInput): Finding { + return Finding(sin) + } + } +} diff --git a/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt b/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt index 60d632dc9..caf26b003 100644 --- a/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt +++ b/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt @@ -10,7 +10,7 @@ */ /* - * Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. @@ -41,6 +41,7 @@ import org.opensearch.alerting.model.AggregationResultBucket import org.opensearch.alerting.model.Alert import org.opensearch.alerting.model.BucketLevelTrigger import org.opensearch.alerting.model.BucketLevelTriggerRunResult +import org.opensearch.alerting.model.Finding import org.opensearch.alerting.model.InputRunResults import org.opensearch.alerting.model.Monitor import org.opensearch.alerting.model.MonitorRunResult @@ -291,6 +292,36 @@ fun randomAlert(monitor: Monitor = randomQueryLevelMonitor()): Alert { ) } +fun randomFinding( + id: String = OpenSearchRestTestCase.randomAlphaOfLength(10), + logEventId: String = OpenSearchRestTestCase.randomAlphaOfLength(10), + monitorId: String = OpenSearchRestTestCase.randomAlphaOfLength(10), + monitorName: String = OpenSearchRestTestCase.randomAlphaOfLength(10), + monitorUser: User? = randomUser(), + monitorVersion: Long = OpenSearchRestTestCase.randomNonNegativeLong(), + ruleId: String = OpenSearchRestTestCase.randomAlphaOfLength(10), + ruleTags: MutableList = mutableListOf(), + severity: String = "${randomInt(5)}", + timestamp: Instant = Instant.now(), + triggerId: String = OpenSearchRestTestCase.randomAlphaOfLength(10), + triggerName: String = OpenSearchRestTestCase.randomAlphaOfLength(10) +): Finding { + return Finding( + id = id, + logEventId = logEventId, + monitorId = monitorId, + monitorName = monitorName, + monitorUser = monitorUser, + monitorVersion = monitorVersion, + ruleId = ruleId, + ruleTags = ruleTags, + severity = severity, + timestamp = timestamp, + triggerId = triggerId, + triggerName = triggerName + ) +} + fun randomAlertWithAggregationResultBucket(monitor: Monitor = randomBucketLevelMonitor()): Alert { val trigger = randomBucketLevelTrigger() val actionExecutionResults = mutableListOf(randomActionExecutionResult(), randomActionExecutionResult()) diff --git a/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt b/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt new file mode 100644 index 000000000..dc6437ba4 --- /dev/null +++ b/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt @@ -0,0 +1,73 @@ +/* + * 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. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package org.opensearch.alerting.model + +import org.opensearch.alerting.randomFinding +import org.opensearch.alerting.randomUser +import org.opensearch.test.OpenSearchTestCase + +class FindingTests : OpenSearchTestCase() { + fun `test can create finding with user`() { + // GIVEN + val user = randomUser() + + // WHEN + val finding = randomFinding(monitorUser = user) + + // THEN + assertEquals("Finding `monitorUser` field does not match:", user, finding.monitorUser) + } + + fun `test can create finding without user`() { + // GIVEN + WHEN + val finding = randomFinding(monitorUser = null) + + // THEN + assertNull("Finding `monitorUser` field should be null:", finding.monitorUser) + } + + fun `test finding asTemplateArgs`() { + // GIVEN + val finding = randomFinding() + + // WHEN + val templateArgs = finding.asTemplateArg() + + // THEN + assertEquals("Template args 'id' field does not match:", templateArgs[Finding.FINDING_ID_FIELD], finding.id) + assertEquals("Template args 'logEventId' field does not match:", templateArgs[Finding.LOG_EVENT_ID_FIELD], finding.logEventId) + assertEquals("Template args 'monitorId' field does not match:", templateArgs[Finding.MONITOR_ID_FIELD], finding.monitorId) + assertEquals("Template args 'monitorName' field does not match:", templateArgs[Finding.MONITOR_NAME_FIELD], finding.monitorName) + assertEquals("Template args 'monitorVersion' field does not match:", templateArgs[Finding.MONITOR_VERSION_FIELD], finding.monitorVersion) + assertEquals("Template args 'ruleId' field does not match:", templateArgs[Finding.RULE_ID_FIELD], finding.ruleId) + assertEquals("Template args 'ruleTags' field does not match:", templateArgs[Finding.RULE_TAGS_FIELD], finding.ruleTags) + assertEquals("Template args 'severity' field does not match:", templateArgs[Finding.SEVERITY_FIELD], finding.severity) + assertEquals("Template args 'timestamp' field does not match:", templateArgs[Finding.TIMESTAMP_FIELD], finding.timestamp.toEpochMilli()) + assertEquals("Template args 'triggerId' field does not match:", templateArgs[Finding.TRIGGER_ID_FIELD], finding.triggerId) + assertEquals("Template args 'triggerName' field does not match:", templateArgs[Finding.TRIGGER_NAME_FIELD], finding.triggerName) + } +} From 2bf3e9c6bfc742603ca99104575bd77cb9f29a43 Mon Sep 17 00:00:00 2001 From: AWSHurneyt Date: Wed, 15 Dec 2021 15:00:34 -0800 Subject: [PATCH 2/9] Refactored Finding.kt to no longer user monitorUser and monitorVersion attributes. Signed-off-by: AWSHurneyt --- .../org/opensearch/alerting/model/Finding.kt | 20 ------------------ .../org/opensearch/alerting/TestHelpers.kt | 4 ---- .../opensearch/alerting/model/FindingTests.kt | 21 ------------------- 3 files changed, 45 deletions(-) diff --git a/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt b/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt index 4a0d4e218..3a2a08d33 100644 --- a/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt +++ b/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt @@ -30,12 +30,10 @@ import org.opensearch.alerting.elasticapi.instant import org.opensearch.common.io.stream.StreamInput import org.opensearch.common.io.stream.StreamOutput import org.opensearch.common.io.stream.Writeable -import org.opensearch.common.lucene.uid.Versions import org.opensearch.common.xcontent.ToXContent import org.opensearch.common.xcontent.XContentBuilder import org.opensearch.common.xcontent.XContentParser import org.opensearch.common.xcontent.XContentParserUtils.ensureExpectedToken -import org.opensearch.commons.authuser.User import java.io.IOException import java.time.Instant @@ -44,8 +42,6 @@ class Finding( val logEventId: String = NO_ID, val monitorId: String, val monitorName: String, - val monitorUser: User?, - val monitorVersion: Long = NO_VERSION, val ruleId: String = NO_ID, val ruleTags: List, val severity: String, @@ -60,8 +56,6 @@ class Finding( logEventId = sin.readString(), monitorId = sin.readString(), monitorName = sin.readString(), - monitorUser = if (sin.readBoolean()) User(sin) else null, - monitorVersion = sin.readLong(), ruleId = sin.readString(), ruleTags = sin.readStringList(), severity = sin.readString(), @@ -76,7 +70,6 @@ class Finding( LOG_EVENT_ID_FIELD to logEventId, MONITOR_ID_FIELD to monitorId, MONITOR_NAME_FIELD to monitorName, - MONITOR_VERSION_FIELD to monitorVersion, RULE_ID_FIELD to ruleId, RULE_TAGS_FIELD to ruleTags, SEVERITY_FIELD to severity, @@ -92,8 +85,6 @@ class Finding( .field(LOG_EVENT_ID_FIELD, logEventId) .field(MONITOR_ID_FIELD, monitorId) .field(MONITOR_NAME_FIELD, monitorName) - .field(MONITOR_USER_FIELD, monitorUser) - .field(MONITOR_VERSION_FIELD, monitorVersion) .field(RULE_ID_FIELD, ruleId) .field(RULE_TAGS_FIELD, ruleTags.toTypedArray()) .field(SEVERITY_FIELD, severity) @@ -110,8 +101,6 @@ class Finding( out.writeString(logEventId) out.writeString(monitorId) out.writeString(monitorName) - monitorUser?.writeTo(out) - out.writeLong(monitorVersion) out.writeString(ruleId) out.writeStringCollection(ruleTags) out.writeString(severity) @@ -125,8 +114,6 @@ class Finding( const val LOG_EVENT_ID_FIELD = "log_event_id" const val MONITOR_ID_FIELD = "monitor_id" const val MONITOR_NAME_FIELD = "monitor_name" - const val MONITOR_USER_FIELD = "monitor_user" - const val MONITOR_VERSION_FIELD = "monitor_version" const val RULE_ID_FIELD = "rule_id" const val RULE_TAGS_FIELD = "rule_tags" const val SEVERITY_FIELD = "severity" @@ -134,7 +121,6 @@ class Finding( const val TRIGGER_ID_FIELD = "trigger_id" const val TRIGGER_NAME_FIELD = "trigger_name" const val NO_ID = "" - const val NO_VERSION = Versions.NOT_FOUND @JvmStatic @JvmOverloads @Throws(IOException::class) @@ -142,8 +128,6 @@ class Finding( var logEventId: String = NO_ID lateinit var monitorId: String lateinit var monitorName: String - var monitorUser: User? = null - var monitorVersion: Long = NO_VERSION var ruleId: String = NO_ID val ruleTags: MutableList = mutableListOf() lateinit var severity: String @@ -160,8 +144,6 @@ class Finding( LOG_EVENT_ID_FIELD -> logEventId = xcp.text() MONITOR_ID_FIELD -> monitorId = xcp.text() MONITOR_NAME_FIELD -> monitorName = xcp.text() - MONITOR_USER_FIELD -> monitorUser = if (xcp.currentToken() == XContentParser.Token.VALUE_NULL) null else User.parse(xcp) - MONITOR_VERSION_FIELD -> monitorVersion = xcp.longValue() RULE_ID_FIELD -> ruleId = xcp.text() RULE_TAGS_FIELD -> { ensureExpectedToken(XContentParser.Token.START_ARRAY, xcp.currentToken(), xcp) @@ -182,8 +164,6 @@ class Finding( logEventId = logEventId, monitorId = monitorId, monitorName = monitorName, - monitorUser = monitorUser, - monitorVersion = monitorVersion, ruleId = ruleId, ruleTags = ruleTags, severity = severity, diff --git a/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt b/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt index caf26b003..b5920420b 100644 --- a/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt +++ b/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt @@ -297,8 +297,6 @@ fun randomFinding( logEventId: String = OpenSearchRestTestCase.randomAlphaOfLength(10), monitorId: String = OpenSearchRestTestCase.randomAlphaOfLength(10), monitorName: String = OpenSearchRestTestCase.randomAlphaOfLength(10), - monitorUser: User? = randomUser(), - monitorVersion: Long = OpenSearchRestTestCase.randomNonNegativeLong(), ruleId: String = OpenSearchRestTestCase.randomAlphaOfLength(10), ruleTags: MutableList = mutableListOf(), severity: String = "${randomInt(5)}", @@ -311,8 +309,6 @@ fun randomFinding( logEventId = logEventId, monitorId = monitorId, monitorName = monitorName, - monitorUser = monitorUser, - monitorVersion = monitorVersion, ruleId = ruleId, ruleTags = ruleTags, severity = severity, diff --git a/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt b/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt index dc6437ba4..d19d12aa1 100644 --- a/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt +++ b/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt @@ -27,29 +27,9 @@ package org.opensearch.alerting.model import org.opensearch.alerting.randomFinding -import org.opensearch.alerting.randomUser import org.opensearch.test.OpenSearchTestCase class FindingTests : OpenSearchTestCase() { - fun `test can create finding with user`() { - // GIVEN - val user = randomUser() - - // WHEN - val finding = randomFinding(monitorUser = user) - - // THEN - assertEquals("Finding `monitorUser` field does not match:", user, finding.monitorUser) - } - - fun `test can create finding without user`() { - // GIVEN + WHEN - val finding = randomFinding(monitorUser = null) - - // THEN - assertNull("Finding `monitorUser` field should be null:", finding.monitorUser) - } - fun `test finding asTemplateArgs`() { // GIVEN val finding = randomFinding() @@ -62,7 +42,6 @@ class FindingTests : OpenSearchTestCase() { assertEquals("Template args 'logEventId' field does not match:", templateArgs[Finding.LOG_EVENT_ID_FIELD], finding.logEventId) assertEquals("Template args 'monitorId' field does not match:", templateArgs[Finding.MONITOR_ID_FIELD], finding.monitorId) assertEquals("Template args 'monitorName' field does not match:", templateArgs[Finding.MONITOR_NAME_FIELD], finding.monitorName) - assertEquals("Template args 'monitorVersion' field does not match:", templateArgs[Finding.MONITOR_VERSION_FIELD], finding.monitorVersion) assertEquals("Template args 'ruleId' field does not match:", templateArgs[Finding.RULE_ID_FIELD], finding.ruleId) assertEquals("Template args 'ruleTags' field does not match:", templateArgs[Finding.RULE_TAGS_FIELD], finding.ruleTags) assertEquals("Template args 'severity' field does not match:", templateArgs[Finding.SEVERITY_FIELD], finding.severity) From 640420f0f0320984a8e91a97d6c6afa86407317a Mon Sep 17 00:00:00 2001 From: AWSHurneyt Date: Wed, 15 Dec 2021 17:07:39 -0800 Subject: [PATCH 3/9] Fixed incorrect parsing logic in Finding. Signed-off-by: AWSHurneyt --- .../main/kotlin/org/opensearch/alerting/model/Finding.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt b/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt index 3a2a08d33..da41959bc 100644 --- a/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt +++ b/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt @@ -147,10 +147,9 @@ class Finding( RULE_ID_FIELD -> ruleId = xcp.text() RULE_TAGS_FIELD -> { ensureExpectedToken(XContentParser.Token.START_ARRAY, xcp.currentToken(), xcp) - // TODO dev code: investigate implementing error logging -// while (xcp.nextToken() != XContentParser.Token.END_ARRAY) { -// errorHistory.add(FindingError.parse(xcp)) -// } + while (xcp.nextToken() != XContentParser.Token.END_ARRAY) { + ruleTags.add(xcp.text()) + } } SEVERITY_FIELD -> severity = xcp.text() TIMESTAMP_FIELD -> timestamp = requireNotNull(xcp.instant()) From 8adc018ffa49ff47e6ba190ee82d31b388bd6800 Mon Sep 17 00:00:00 2001 From: AWSHurneyt Date: Fri, 17 Dec 2021 11:12:26 -0800 Subject: [PATCH 4/9] Refactored Finding to store the complete log event instead of the log event ID. Refactored feature assets to rename references to rules to queries. Signed-off-by: AWSHurneyt --- .../org/opensearch/alerting/model/Finding.kt | 64 +++++++++++-------- .../org/opensearch/alerting/TestHelpers.kt | 14 ++-- .../opensearch/alerting/model/FindingTests.kt | 6 +- 3 files changed, 47 insertions(+), 37 deletions(-) diff --git a/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt b/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt index da41959bc..f9bcd61a2 100644 --- a/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt +++ b/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt @@ -37,13 +37,16 @@ import org.opensearch.common.xcontent.XContentParserUtils.ensureExpectedToken import java.io.IOException import java.time.Instant +/** + * A wrapper of the log event that enriches the event by also including information about the monitor it triggered. + */ class Finding( val id: String = NO_ID, - val logEventId: String = NO_ID, + val logEvent: Map, val monitorId: String, val monitorName: String, - val ruleId: String = NO_ID, - val ruleTags: List, + val queryId: String = NO_ID, + val queryTags: List, val severity: String, val timestamp: Instant, val triggerId: String, @@ -53,11 +56,11 @@ class Finding( @Throws(IOException::class) constructor(sin: StreamInput) : this( id = sin.readString(), - logEventId = sin.readString(), + logEvent = suppressWarning(sin.readMap()), monitorId = sin.readString(), monitorName = sin.readString(), - ruleId = sin.readString(), - ruleTags = sin.readStringList(), + queryId = sin.readString(), + queryTags = sin.readStringList(), severity = sin.readString(), timestamp = sin.readInstant(), triggerId = sin.readString(), @@ -67,11 +70,11 @@ class Finding( fun asTemplateArg(): Map { return mapOf( FINDING_ID_FIELD to id, - LOG_EVENT_ID_FIELD to logEventId, + LOG_EVENT_FIELD to logEvent, MONITOR_ID_FIELD to monitorId, MONITOR_NAME_FIELD to monitorName, - RULE_ID_FIELD to ruleId, - RULE_TAGS_FIELD to ruleTags, + QUERY_ID_FIELD to queryId, + QUERY_TAGS_FIELD to queryTags, SEVERITY_FIELD to severity, TIMESTAMP_FIELD to timestamp.toEpochMilli(), TRIGGER_ID_FIELD to triggerId, @@ -82,11 +85,11 @@ class Finding( override fun toXContent(builder: XContentBuilder, params: ToXContent.Params): XContentBuilder { builder.startObject() .field(FINDING_ID_FIELD, id) - .field(LOG_EVENT_ID_FIELD, logEventId) + .field(LOG_EVENT_FIELD, logEvent) .field(MONITOR_ID_FIELD, monitorId) .field(MONITOR_NAME_FIELD, monitorName) - .field(RULE_ID_FIELD, ruleId) - .field(RULE_TAGS_FIELD, ruleTags.toTypedArray()) + .field(QUERY_ID_FIELD, queryId) + .field(QUERY_TAGS_FIELD, queryTags.toTypedArray()) .field(SEVERITY_FIELD, severity) .field(TIMESTAMP_FIELD, timestamp) .field(TRIGGER_ID_FIELD, triggerId) @@ -98,11 +101,11 @@ class Finding( @Throws(IOException::class) override fun writeTo(out: StreamOutput) { out.writeString(id) - out.writeString(logEventId) + out.writeMap(logEvent) out.writeString(monitorId) out.writeString(monitorName) - out.writeString(ruleId) - out.writeStringCollection(ruleTags) + out.writeString(queryId) + out.writeStringCollection(queryTags) out.writeString(severity) out.writeInstant(timestamp) out.writeString(triggerId) @@ -111,11 +114,11 @@ class Finding( companion object { const val FINDING_ID_FIELD = "id" - const val LOG_EVENT_ID_FIELD = "log_event_id" + const val LOG_EVENT_FIELD = "log_event" const val MONITOR_ID_FIELD = "monitor_id" const val MONITOR_NAME_FIELD = "monitor_name" - const val RULE_ID_FIELD = "rule_id" - const val RULE_TAGS_FIELD = "rule_tags" + const val QUERY_ID_FIELD = "query_id" + const val QUERY_TAGS_FIELD = "query_tags" const val SEVERITY_FIELD = "severity" const val TIMESTAMP_FIELD = "timestamp" const val TRIGGER_ID_FIELD = "trigger_id" @@ -125,11 +128,11 @@ class Finding( @JvmStatic @JvmOverloads @Throws(IOException::class) fun parse(xcp: XContentParser, id: String = NO_ID): Finding { - var logEventId: String = NO_ID + var logEvent: Map = mapOf() lateinit var monitorId: String lateinit var monitorName: String - var ruleId: String = NO_ID - val ruleTags: MutableList = mutableListOf() + var queryId: String = NO_ID + val queryTags: MutableList = mutableListOf() lateinit var severity: String lateinit var timestamp: Instant lateinit var triggerId: String @@ -141,14 +144,14 @@ class Finding( xcp.nextToken() when (fieldName) { - LOG_EVENT_ID_FIELD -> logEventId = xcp.text() + LOG_EVENT_FIELD -> logEvent = xcp.map() MONITOR_ID_FIELD -> monitorId = xcp.text() MONITOR_NAME_FIELD -> monitorName = xcp.text() - RULE_ID_FIELD -> ruleId = xcp.text() - RULE_TAGS_FIELD -> { + QUERY_ID_FIELD -> queryId = xcp.text() + QUERY_TAGS_FIELD -> { ensureExpectedToken(XContentParser.Token.START_ARRAY, xcp.currentToken(), xcp) while (xcp.nextToken() != XContentParser.Token.END_ARRAY) { - ruleTags.add(xcp.text()) + queryTags.add(xcp.text()) } } SEVERITY_FIELD -> severity = xcp.text() @@ -160,11 +163,11 @@ class Finding( return Finding( id = id, - logEventId = logEventId, + logEvent = logEvent, monitorId = monitorId, monitorName = monitorName, - ruleId = ruleId, - ruleTags = ruleTags, + queryId = queryId, + queryTags = queryTags, severity = severity, timestamp = timestamp, triggerId = triggerId, @@ -177,5 +180,10 @@ class Finding( fun readFrom(sin: StreamInput): Finding { return Finding(sin) } + + @Suppress("UNCHECKED_CAST") + fun suppressWarning(map: MutableMap?): MutableMap { + return map as MutableMap + } } } diff --git a/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt b/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt index b5920420b..98844ddaf 100644 --- a/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt +++ b/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt @@ -294,11 +294,13 @@ fun randomAlert(monitor: Monitor = randomQueryLevelMonitor()): Alert { fun randomFinding( id: String = OpenSearchRestTestCase.randomAlphaOfLength(10), - logEventId: String = OpenSearchRestTestCase.randomAlphaOfLength(10), + logEvent: Map = mapOf( + OpenSearchRestTestCase.randomAlphaOfLength(5) to OpenSearchRestTestCase.randomAlphaOfLength(5) + ), monitorId: String = OpenSearchRestTestCase.randomAlphaOfLength(10), monitorName: String = OpenSearchRestTestCase.randomAlphaOfLength(10), - ruleId: String = OpenSearchRestTestCase.randomAlphaOfLength(10), - ruleTags: MutableList = mutableListOf(), + queryId: String = OpenSearchRestTestCase.randomAlphaOfLength(10), + queryTags: MutableList = mutableListOf(), severity: String = "${randomInt(5)}", timestamp: Instant = Instant.now(), triggerId: String = OpenSearchRestTestCase.randomAlphaOfLength(10), @@ -306,11 +308,11 @@ fun randomFinding( ): Finding { return Finding( id = id, - logEventId = logEventId, + logEvent = logEvent, monitorId = monitorId, monitorName = monitorName, - ruleId = ruleId, - ruleTags = ruleTags, + queryId = queryId, + queryTags = queryTags, severity = severity, timestamp = timestamp, triggerId = triggerId, diff --git a/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt b/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt index d19d12aa1..7448c9ebd 100644 --- a/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt +++ b/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt @@ -39,11 +39,11 @@ class FindingTests : OpenSearchTestCase() { // THEN assertEquals("Template args 'id' field does not match:", templateArgs[Finding.FINDING_ID_FIELD], finding.id) - assertEquals("Template args 'logEventId' field does not match:", templateArgs[Finding.LOG_EVENT_ID_FIELD], finding.logEventId) + assertNull("Template args 'logEvent' field should be null:", finding.logEvent) assertEquals("Template args 'monitorId' field does not match:", templateArgs[Finding.MONITOR_ID_FIELD], finding.monitorId) assertEquals("Template args 'monitorName' field does not match:", templateArgs[Finding.MONITOR_NAME_FIELD], finding.monitorName) - assertEquals("Template args 'ruleId' field does not match:", templateArgs[Finding.RULE_ID_FIELD], finding.ruleId) - assertEquals("Template args 'ruleTags' field does not match:", templateArgs[Finding.RULE_TAGS_FIELD], finding.ruleTags) + assertEquals("Template args 'queryId' field does not match:", templateArgs[Finding.QUERY_ID_FIELD], finding.queryId) + assertEquals("Template args 'queryTags' field does not match:", templateArgs[Finding.QUERY_TAGS_FIELD], finding.queryTags) assertEquals("Template args 'severity' field does not match:", templateArgs[Finding.SEVERITY_FIELD], finding.severity) assertEquals("Template args 'timestamp' field does not match:", templateArgs[Finding.TIMESTAMP_FIELD], finding.timestamp.toEpochMilli()) assertEquals("Template args 'triggerId' field does not match:", templateArgs[Finding.TRIGGER_ID_FIELD], finding.triggerId) From 7bc4ae24a95d54071db71d1e6a4ea2bacc9c50b2 Mon Sep 17 00:00:00 2001 From: AWSHurneyt Date: Fri, 17 Dec 2021 14:31:45 -0800 Subject: [PATCH 5/9] Implemented a new Input type to use for doc level monitors, and some basic unit tests. Signed-off-by: AWSHurneyt --- .../docLevelInput/DocLevelMonitorInput.kt | 104 ++++++++++++++++ .../model/docLevelInput/DocLevelQuery.kt | 116 ++++++++++++++++++ .../org/opensearch/alerting/TestHelpers.kt | 20 +++ .../model/DocLevelMonitorInputTests.kt | 63 ++++++++++ 4 files changed, 303 insertions(+) create mode 100644 alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelMonitorInput.kt create mode 100644 alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelQuery.kt create mode 100644 alerting/src/test/kotlin/org/opensearch/alerting/model/DocLevelMonitorInputTests.kt diff --git a/alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelMonitorInput.kt b/alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelMonitorInput.kt new file mode 100644 index 000000000..351aeef15 --- /dev/null +++ b/alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelMonitorInput.kt @@ -0,0 +1,104 @@ +package org.opensearch.alerting.model.docLevelInput + +import org.opensearch.alerting.core.model.Input +import org.opensearch.common.CheckedFunction +import org.opensearch.common.ParseField +import org.opensearch.common.io.stream.StreamInput +import org.opensearch.common.io.stream.StreamOutput +import org.opensearch.common.xcontent.NamedXContentRegistry +import org.opensearch.common.xcontent.ToXContent +import org.opensearch.common.xcontent.XContentBuilder +import org.opensearch.common.xcontent.XContentParser +import org.opensearch.common.xcontent.XContentParserUtils.ensureExpectedToken +import java.io.IOException + +data class DocLevelMonitorInput( + val description: String = NO_DESCRIPTION, + val indices: List, + val queries: List +) : Input { + + @Throws(IOException::class) + constructor(sin: StreamInput) : this( + sin.readString(), // description + sin.readStringList(), // indices + sin.readList(::DocLevelQuery) // docLevelQueries + ) + + fun asTemplateArg(): Map { + return mapOf( + DESCRIPTION_FIELD to description, + INDICES_FIELD to indices, + QUERIES_FIELD to queries.map { it.asTemplateArg() } + ) + } + + override fun name(): String { + return DOC_LEVEL_INPUT_FIELD + } + + @Throws(IOException::class) + override fun writeTo(out: StreamOutput) { + out.writeString(description) + out.writeStringCollection(indices) + out.writeCollection(queries) + } + + override fun toXContent(builder: XContentBuilder, params: ToXContent.Params): XContentBuilder { + builder.startObject() + .startObject(DOC_LEVEL_INPUT_FIELD) + .field(DESCRIPTION_FIELD, description) + .field(INDICES_FIELD, indices.toTypedArray()) + .field(QUERIES_FIELD, queries.toTypedArray()) + .endObject() + .endObject() + return builder + } + + companion object { + const val DESCRIPTION_FIELD = "description" + const val INDICES_FIELD = "indices" + const val DOC_LEVEL_INPUT_FIELD = "doc_level_input" + const val QUERIES_FIELD = "queries" + + const val NO_DESCRIPTION = "" + + val XCONTENT_REGISTRY = NamedXContentRegistry.Entry(Input::class.java, ParseField(DOC_LEVEL_INPUT_FIELD), CheckedFunction { parse(it) }) + + @JvmStatic @Throws(IOException::class) + fun parse(xcp: XContentParser): DocLevelMonitorInput { + var description: String = NO_DESCRIPTION + val indices: MutableList = mutableListOf() + val docLevelQueries: MutableList = mutableListOf() + + ensureExpectedToken(XContentParser.Token.START_OBJECT, xcp.currentToken(), xcp) + while (xcp.nextToken() != XContentParser.Token.END_OBJECT) { + val fieldName = xcp.currentName() + xcp.nextToken() + + when (fieldName) { + DESCRIPTION_FIELD -> description = xcp.text() + INDICES_FIELD -> { + ensureExpectedToken(XContentParser.Token.START_ARRAY, xcp.currentToken(), xcp) + while (xcp.nextToken() != XContentParser.Token.END_ARRAY) { + indices.add(xcp.text()) + } + } + QUERIES_FIELD -> { + ensureExpectedToken(XContentParser.Token.START_ARRAY, xcp.currentToken(), xcp) + while (xcp.nextToken() != XContentParser.Token.END_ARRAY) { + docLevelQueries.add(DocLevelQuery.parse(xcp)) + } + } + } + } + + return DocLevelMonitorInput(description = description, indices = indices, queries = docLevelQueries) + } + + @JvmStatic @Throws(IOException::class) + fun readFrom(sin: StreamInput): DocLevelMonitorInput { + return DocLevelMonitorInput(sin) + } + } +} diff --git a/alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelQuery.kt b/alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelQuery.kt new file mode 100644 index 000000000..605c82e46 --- /dev/null +++ b/alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelQuery.kt @@ -0,0 +1,116 @@ +package org.opensearch.alerting.model.docLevelInput + +import org.opensearch.alerting.model.action.Action +import org.opensearch.common.io.stream.StreamInput +import org.opensearch.common.io.stream.StreamOutput +import org.opensearch.common.io.stream.Writeable +import org.opensearch.common.xcontent.ToXContent +import org.opensearch.common.xcontent.ToXContentObject +import org.opensearch.common.xcontent.XContentBuilder +import org.opensearch.common.xcontent.XContentParser +import org.opensearch.common.xcontent.XContentParserUtils.ensureExpectedToken +import java.io.IOException + +data class DocLevelQuery( + val id: String = NO_ID, + val query: String, + val severity: String, + val tags: List = mutableListOf(), + val actions: List = mutableListOf() +) : Writeable, ToXContentObject { + + @Throws(IOException::class) + constructor(sin: StreamInput) : this( + sin.readString(), // id + sin.readString(), // query + sin.readString(), // severity + sin.readStringList(), // tags + sin.readList(::Action) // actions + ) + + fun asTemplateArg(): Map { + return mapOf( + QUERY_ID_FIELD to id, + QUERY_FIELD to query, + SEVERITY_FIELD to severity, + TAGS_FIELD to tags, + ACTIONS_FIELD to actions.map { it.asTemplateArg() } + ) + } + + @Throws(IOException::class) + override fun writeTo(out: StreamOutput) { + out.writeString(id) + out.writeString(query) + out.writeString(severity) + out.writeStringCollection(tags) + out.writeCollection(actions) + } + + override fun toXContent(builder: XContentBuilder, params: ToXContent.Params): XContentBuilder { + builder.startObject() + .field(QUERY_ID_FIELD, id) + .field(QUERY_FIELD, query) + .field(SEVERITY_FIELD, severity) + .field(TAGS_FIELD, tags.toTypedArray()) + .field(ACTIONS_FIELD, actions.toTypedArray()) + .endObject() + return builder + } + + companion object { + const val QUERY_ID_FIELD = "id" + const val QUERY_FIELD = "query" + const val SEVERITY_FIELD = "severity" + const val TAGS_FIELD = "tags" + const val ACTIONS_FIELD = "actions" + + const val NO_ID = "" + + @JvmStatic @Throws(IOException::class) + fun parse(xcp: XContentParser): DocLevelQuery { + var id: String = NO_ID + lateinit var query: String + lateinit var severity: String + val tags: MutableList = mutableListOf() + val actions: MutableList = mutableListOf() + + ensureExpectedToken(XContentParser.Token.START_OBJECT, xcp.currentToken(), xcp) + while (xcp.nextToken() != XContentParser.Token.END_OBJECT) { + val fieldName = xcp.currentName() + xcp.nextToken() + + when (fieldName) { + QUERY_ID_FIELD -> id = xcp.text() + QUERY_FIELD -> query = xcp.text() + SEVERITY_FIELD -> severity = xcp.text() + TAGS_FIELD -> { + ensureExpectedToken(XContentParser.Token.START_ARRAY, xcp.currentToken(), xcp) + while (xcp.nextToken() != XContentParser.Token.END_ARRAY) { + tags.add(xcp.text()) + } + } + ACTIONS_FIELD -> { + ensureExpectedToken(XContentParser.Token.START_ARRAY, xcp.currentToken(), xcp) + while (xcp.nextToken() != XContentParser.Token.END_ARRAY) { + actions.add(Action.parse(xcp)) + } + } + } + } + + return DocLevelQuery( + id = id, + query = query, + severity = severity, + tags = tags, + actions = actions + ) + } + + @JvmStatic @Throws(IOException::class) + fun readFrom(sin: StreamInput): DocLevelMonitorInput { + return DocLevelMonitorInput(sin) + } + } +} diff --git a/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt b/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt index 98844ddaf..28c13059b 100644 --- a/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt +++ b/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt @@ -58,6 +58,8 @@ import org.opensearch.alerting.model.action.Throttle import org.opensearch.alerting.model.destination.email.EmailAccount import org.opensearch.alerting.model.destination.email.EmailEntry import org.opensearch.alerting.model.destination.email.EmailGroup +import org.opensearch.alerting.model.docLevelInput.DocLevelMonitorInput +import org.opensearch.alerting.model.docLevelInput.DocLevelQuery import org.opensearch.alerting.util.getBucketKeysHash import org.opensearch.client.Request import org.opensearch.client.RequestOptions @@ -292,6 +294,24 @@ fun randomAlert(monitor: Monitor = randomQueryLevelMonitor()): Alert { ) } +fun randomDocLevelQuery( + id: String = OpenSearchRestTestCase.randomAlphaOfLength(10), + query: String = OpenSearchRestTestCase.randomAlphaOfLength(10), + severity: String = "${randomInt(5)}", + tags: List = mutableListOf(0..randomInt(10)).map { OpenSearchRestTestCase.randomAlphaOfLength(10) }, + actions: List = mutableListOf(0..randomInt(10)).map { randomAction() } +): DocLevelQuery { + return DocLevelQuery(id = id, query = query, severity = severity, tags = tags, actions = actions) +} + +fun randomDocLevelMonitorInput( + description: String = OpenSearchRestTestCase.randomAlphaOfLength(randomInt(10)), + indices: List = listOf(1..randomInt(10)).map { OpenSearchRestTestCase.randomAlphaOfLength(10) }, + queries: List = listOf(1..randomInt(10)).map { randomDocLevelQuery() } +) : DocLevelMonitorInput { + return DocLevelMonitorInput(description = description, indices = indices, queries = queries) +} + fun randomFinding( id: String = OpenSearchRestTestCase.randomAlphaOfLength(10), logEvent: Map = mapOf( diff --git a/alerting/src/test/kotlin/org/opensearch/alerting/model/DocLevelMonitorInputTests.kt b/alerting/src/test/kotlin/org/opensearch/alerting/model/DocLevelMonitorInputTests.kt new file mode 100644 index 000000000..c3a2a8b79 --- /dev/null +++ b/alerting/src/test/kotlin/org/opensearch/alerting/model/DocLevelMonitorInputTests.kt @@ -0,0 +1,63 @@ +/* + * 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. + * + * Modifications Copyright OpenSearch Contributors. See + * GitHub history for details. + */ + +/* + * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +package org.opensearch.alerting.model + +import org.opensearch.alerting.model.docLevelInput.DocLevelMonitorInput +import org.opensearch.alerting.model.docLevelInput.DocLevelQuery +import org.opensearch.alerting.randomDocLevelMonitorInput +import org.opensearch.alerting.randomDocLevelQuery +import org.opensearch.test.OpenSearchTestCase + +class DocLevelMonitorInputTests : OpenSearchTestCase() { + fun `testing DocLevelQuery asTemplateArgs`() { + // GIVEN + val query = randomDocLevelQuery() + + // WHEN + val templateArgs = query.asTemplateArg() + + // THEN + assertEquals("Template args 'id' field does not match:", templateArgs[DocLevelQuery.QUERY_ID_FIELD], query.id) + assertEquals("Template args 'query' field does not match:", templateArgs[DocLevelQuery.QUERY_FIELD], query.query) + assertEquals("Template args 'severity' field does not match:", templateArgs[DocLevelQuery.SEVERITY_FIELD], query.severity) + assertEquals("Template args 'tags' field does not match:", templateArgs[DocLevelQuery.TAGS_FIELD], query.tags) + assertEquals("Template args 'actions' field does not match:", templateArgs[DocLevelQuery.ACTIONS_FIELD], query.actions) + } + + fun `testing DocLevelMonitorInput asTemplateArgs`() { + // GIVEN + val input = randomDocLevelMonitorInput() + + // WHEN + val templateArgs = input.asTemplateArg() + + // THEN + assertEquals("Template args 'description' field does not match:", templateArgs[DocLevelMonitorInput.DESCRIPTION_FIELD], input.description) + assertEquals("Template args 'indices' field does not match:", templateArgs[DocLevelMonitorInput.INDICES_FIELD], input.indices) + assertEquals("Template args 'queries' field does not match:", templateArgs[DocLevelMonitorInput.QUERIES_FIELD], input.queries) + } +} From fb04986b0abe01f5d60c816b6d4063f2b1c8e515 Mon Sep 17 00:00:00 2001 From: AWSHurneyt Date: Fri, 17 Dec 2021 14:43:03 -0800 Subject: [PATCH 6/9] Fixed ktlint errors. Signed-off-by: AWSHurneyt --- .../src/test/kotlin/org/opensearch/alerting/TestHelpers.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt b/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt index 28c13059b..9d13d9952 100644 --- a/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt +++ b/alerting/src/test/kotlin/org/opensearch/alerting/TestHelpers.kt @@ -301,14 +301,14 @@ fun randomDocLevelQuery( tags: List = mutableListOf(0..randomInt(10)).map { OpenSearchRestTestCase.randomAlphaOfLength(10) }, actions: List = mutableListOf(0..randomInt(10)).map { randomAction() } ): DocLevelQuery { - return DocLevelQuery(id = id, query = query, severity = severity, tags = tags, actions = actions) + return DocLevelQuery(id = id, query = query, severity = severity, tags = tags, actions = actions) } fun randomDocLevelMonitorInput( description: String = OpenSearchRestTestCase.randomAlphaOfLength(randomInt(10)), indices: List = listOf(1..randomInt(10)).map { OpenSearchRestTestCase.randomAlphaOfLength(10) }, queries: List = listOf(1..randomInt(10)).map { randomDocLevelQuery() } -) : DocLevelMonitorInput { +): DocLevelMonitorInput { return DocLevelMonitorInput(description = description, indices = indices, queries = queries) } From b184af14cdbe93755b4fdca7b5bc79ca475e499f Mon Sep 17 00:00:00 2001 From: AWSHurneyt Date: Mon, 20 Dec 2021 14:57:11 -0800 Subject: [PATCH 7/9] Fixed faulty unit test. Signed-off-by: AWSHurneyt --- .../alerting/model/DocLevelMonitorInputTests.kt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/alerting/src/test/kotlin/org/opensearch/alerting/model/DocLevelMonitorInputTests.kt b/alerting/src/test/kotlin/org/opensearch/alerting/model/DocLevelMonitorInputTests.kt index c3a2a8b79..2ba0f05c8 100644 --- a/alerting/src/test/kotlin/org/opensearch/alerting/model/DocLevelMonitorInputTests.kt +++ b/alerting/src/test/kotlin/org/opensearch/alerting/model/DocLevelMonitorInputTests.kt @@ -26,6 +26,7 @@ package org.opensearch.alerting.model +import org.opensearch.alerting.model.action.Action import org.opensearch.alerting.model.docLevelInput.DocLevelMonitorInput import org.opensearch.alerting.model.docLevelInput.DocLevelQuery import org.opensearch.alerting.randomDocLevelMonitorInput @@ -45,7 +46,9 @@ class DocLevelMonitorInputTests : OpenSearchTestCase() { assertEquals("Template args 'query' field does not match:", templateArgs[DocLevelQuery.QUERY_FIELD], query.query) assertEquals("Template args 'severity' field does not match:", templateArgs[DocLevelQuery.SEVERITY_FIELD], query.severity) assertEquals("Template args 'tags' field does not match:", templateArgs[DocLevelQuery.TAGS_FIELD], query.tags) - assertEquals("Template args 'actions' field does not match:", templateArgs[DocLevelQuery.ACTIONS_FIELD], query.actions) + + val expectedActions = query.actions.map { mapOf(Action.NAME_FIELD to it.name) } + assertEquals("Template args 'actions' field does not match:", templateArgs[DocLevelQuery.ACTIONS_FIELD], expectedActions) } fun `testing DocLevelMonitorInput asTemplateArgs`() { @@ -58,6 +61,9 @@ class DocLevelMonitorInputTests : OpenSearchTestCase() { // THEN assertEquals("Template args 'description' field does not match:", templateArgs[DocLevelMonitorInput.DESCRIPTION_FIELD], input.description) assertEquals("Template args 'indices' field does not match:", templateArgs[DocLevelMonitorInput.INDICES_FIELD], input.indices) - assertEquals("Template args 'queries' field does not match:", templateArgs[DocLevelMonitorInput.QUERIES_FIELD], input.queries) + assertEquals("Template args 'queries' field does not contain the expected number of queries:", input.queries.size, (templateArgs[DocLevelMonitorInput.QUERIES_FIELD] as List<*>).size) + input.queries.forEach { + assertTrue("Template args 'queries' field does not match:", (templateArgs[DocLevelMonitorInput.QUERIES_FIELD] as List<*>).contains(it.asTemplateArg())) + } } } From 8ea16d33da082bfd48656e3160a35c805022f979 Mon Sep 17 00:00:00 2001 From: AWSHurneyt Date: Mon, 20 Dec 2021 15:07:30 -0800 Subject: [PATCH 8/9] Fixed faulty unit test. Signed-off-by: AWSHurneyt --- .../test/kotlin/org/opensearch/alerting/model/FindingTests.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt b/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt index 7448c9ebd..394372dc9 100644 --- a/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt +++ b/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt @@ -39,7 +39,7 @@ class FindingTests : OpenSearchTestCase() { // THEN assertEquals("Template args 'id' field does not match:", templateArgs[Finding.FINDING_ID_FIELD], finding.id) - assertNull("Template args 'logEvent' field should be null:", finding.logEvent) + assertEquals("Template args 'logEvent' field does not match:", templateArgs[Finding.LOG_EVENT_FIELD], finding.logEvent) assertEquals("Template args 'monitorId' field does not match:", templateArgs[Finding.MONITOR_ID_FIELD], finding.monitorId) assertEquals("Template args 'monitorName' field does not match:", templateArgs[Finding.MONITOR_NAME_FIELD], finding.monitorName) assertEquals("Template args 'queryId' field does not match:", templateArgs[Finding.QUERY_ID_FIELD], finding.queryId) From 37f70be8df0e89e2411d51d60241e68ce85272dc Mon Sep 17 00:00:00 2001 From: AWSHurneyt Date: Tue, 21 Dec 2021 11:17:30 -0800 Subject: [PATCH 9/9] Updated license header. Signed-off-by: AWSHurneyt --- .../org/opensearch/alerting/model/Finding.kt | 23 +------------------ .../docLevelInput/DocLevelMonitorInput.kt | 5 ++++ .../model/docLevelInput/DocLevelQuery.kt | 5 ++++ .../model/DocLevelMonitorInputTests.kt | 23 +------------------ .../opensearch/alerting/model/FindingTests.kt | 23 +------------------ 5 files changed, 13 insertions(+), 66 deletions(-) diff --git a/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt b/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt index f9bcd61a2..e10b1a41c 100644 --- a/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt +++ b/alerting/src/main/kotlin/org/opensearch/alerting/model/Finding.kt @@ -1,27 +1,6 @@ /* + * 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. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -/* - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. */ package org.opensearch.alerting.model diff --git a/alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelMonitorInput.kt b/alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelMonitorInput.kt index 351aeef15..a1ac19a46 100644 --- a/alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelMonitorInput.kt +++ b/alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelMonitorInput.kt @@ -1,3 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + package org.opensearch.alerting.model.docLevelInput import org.opensearch.alerting.core.model.Input diff --git a/alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelQuery.kt b/alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelQuery.kt index 605c82e46..f1d0cf367 100644 --- a/alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelQuery.kt +++ b/alerting/src/main/kotlin/org/opensearch/alerting/model/docLevelInput/DocLevelQuery.kt @@ -1,3 +1,8 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + package org.opensearch.alerting.model.docLevelInput import org.opensearch.alerting.model.action.Action diff --git a/alerting/src/test/kotlin/org/opensearch/alerting/model/DocLevelMonitorInputTests.kt b/alerting/src/test/kotlin/org/opensearch/alerting/model/DocLevelMonitorInputTests.kt index 2ba0f05c8..7f85b1895 100644 --- a/alerting/src/test/kotlin/org/opensearch/alerting/model/DocLevelMonitorInputTests.kt +++ b/alerting/src/test/kotlin/org/opensearch/alerting/model/DocLevelMonitorInputTests.kt @@ -1,27 +1,6 @@ /* + * 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. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -/* - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. */ package org.opensearch.alerting.model diff --git a/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt b/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt index 394372dc9..4e0cde443 100644 --- a/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt +++ b/alerting/src/test/kotlin/org/opensearch/alerting/model/FindingTests.kt @@ -1,27 +1,6 @@ /* + * 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. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -/* - * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"). - * You may not use this file except in compliance with the License. - * A copy of the License is located at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * or in the "license" file accompanying this file. This file is distributed - * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either - * express or implied. See the License for the specific language governing - * permissions and limitations under the License. */ package org.opensearch.alerting.model