From ae9de53d89b0c8b312c79ceee56ca9af6ec85cd4 Mon Sep 17 00:00:00 2001 From: "opensearch-trigger-bot[bot]" <98922864+opensearch-trigger-bot[bot]@users.noreply.github.com> Date: Fri, 18 Aug 2023 11:16:24 -0700 Subject: [PATCH] common utils to support Microsoft teams in notifications (#428) (#512) * Added common utils for microsoft teams * Added configType ,eventstatus,configDataProperties and msTeams files * Added ConfigType,EventStatus,ConfigDataProperties and MicrosoftTeams * fix build * fix build, add more test * change strings import * fix after core --------- (cherry picked from commit bae1beeac2a7890bf1824f7bdfc9ffadf9fee813) Signed-off-by: danielkyalo599 Signed-off-by: dankyalo599 Signed-off-by: zhichao-aws Signed-off-by: github-actions[bot] Co-authored-by: github-actions[bot] Co-authored-by: danielkyalo599 Signed-off-by: AWSHurneyt --- .../commons/notifications/model/ConfigType.kt | 5 + .../notifications/model/EventStatus.kt | 1 + .../notifications/model/MicrosoftTeams.kt | 99 +++++++++++++++++++ .../model/config/ConfigDataProperties.kt | 5 +- .../CreateNotificationConfigRequestTests.kt | 60 +++++++++++ .../action/GetChannelListResponseTests.kt | 16 ++- .../GetNotificationConfigResponseTests.kt | 29 +++++- .../UpdateNotificationConfigRequestTests.kt | 29 +++++- .../notifications/model/ChannelListTests.kt | 31 +++++- .../notifications/model/EventStatusTests.kt | 11 +++ .../model/FilterConfigListTests.kt | 16 ++- .../model/MicrosoftTeamsTests.kt | 87 ++++++++++++++++ .../model/NotificationConfigTests.kt | 27 +++++ .../model/config/ConfigPropertiesTests.kt | 16 ++- 14 files changed, 417 insertions(+), 15 deletions(-) create mode 100644 src/main/kotlin/org/opensearch/commons/notifications/model/MicrosoftTeams.kt create mode 100644 src/test/kotlin/org/opensearch/commons/notifications/model/MicrosoftTeamsTests.kt diff --git a/src/main/kotlin/org/opensearch/commons/notifications/model/ConfigType.kt b/src/main/kotlin/org/opensearch/commons/notifications/model/ConfigType.kt index e9888e2b..50f1f3bc 100644 --- a/src/main/kotlin/org/opensearch/commons/notifications/model/ConfigType.kt +++ b/src/main/kotlin/org/opensearch/commons/notifications/model/ConfigType.kt @@ -54,6 +54,11 @@ enum class ConfigType(val tag: String) { override fun toString(): String { return tag } + }, + MICROSOFT_TEAMS("microsoft_teams") { + override fun toString(): String { + return tag + } }; companion object { diff --git a/src/main/kotlin/org/opensearch/commons/notifications/model/EventStatus.kt b/src/main/kotlin/org/opensearch/commons/notifications/model/EventStatus.kt index afb023ce..8d1b5a7c 100644 --- a/src/main/kotlin/org/opensearch/commons/notifications/model/EventStatus.kt +++ b/src/main/kotlin/org/opensearch/commons/notifications/model/EventStatus.kt @@ -43,6 +43,7 @@ data class EventStatus( ConfigType.SLACK -> requireNotNull(deliveryStatus) ConfigType.EMAIL -> require(emailRecipientStatus.isNotEmpty()) ConfigType.SNS -> requireNotNull(deliveryStatus) + ConfigType.MICROSOFT_TEAMS -> requireNotNull(deliveryStatus) ConfigType.NONE -> log.info("Some config field not recognized") else -> { log.info("non-allowed config type for Status") diff --git a/src/main/kotlin/org/opensearch/commons/notifications/model/MicrosoftTeams.kt b/src/main/kotlin/org/opensearch/commons/notifications/model/MicrosoftTeams.kt new file mode 100644 index 00000000..48e32f15 --- /dev/null +++ b/src/main/kotlin/org/opensearch/commons/notifications/model/MicrosoftTeams.kt @@ -0,0 +1,99 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.opensearch.commons.notifications.model + +import org.opensearch.commons.notifications.NotificationConstants.URL_TAG +import org.opensearch.commons.utils.logger +import org.opensearch.commons.utils.validateUrl +import org.opensearch.core.common.Strings +import org.opensearch.core.common.io.stream.StreamInput +import org.opensearch.core.common.io.stream.StreamOutput +import org.opensearch.core.common.io.stream.Writeable +import org.opensearch.core.xcontent.ToXContent +import org.opensearch.core.xcontent.XContentBuilder +import org.opensearch.core.xcontent.XContentParser +import org.opensearch.core.xcontent.XContentParserUtils +import java.io.IOException + +/** + * Data class representing MicrosoftTeams channel. + */ +data class MicrosoftTeams( + val url: String +) : BaseConfigData { + + init { + require(!Strings.isNullOrEmpty(url)) { "URL is null or empty" } + validateUrl(url) + } + + companion object { + private val log by logger(MicrosoftTeams::class.java) + + /** + * reader to create instance of class from writable. + */ + val reader = Writeable.Reader { MicrosoftTeams(it) } + + /** + * Parser to parse xContent + */ + val xParser = XParser { parse(it) } + + /** + * Creator used in REST communication. + * @param parser XContentParser to deserialize data from. + */ + @JvmStatic + @Throws(IOException::class) + fun parse(parser: XContentParser): MicrosoftTeams { + var url: String? = null + + XContentParserUtils.ensureExpectedToken( + XContentParser.Token.START_OBJECT, + parser.currentToken(), + parser + ) + while (parser.nextToken() != XContentParser.Token.END_OBJECT) { + val fieldName = parser.currentName() + parser.nextToken() + when (fieldName) { + URL_TAG -> url = parser.text() + else -> { + parser.skipChildren() + log.info("Unexpected field: $fieldName, while parsing MicrosoftTeams destination") + } + } + } + url ?: throw IllegalArgumentException("$URL_TAG field absent") + return MicrosoftTeams(url) + } + } + + /** + * Constructor used in transport action communication. + * @param input StreamInput stream to deserialize data from. + */ + constructor(input: StreamInput) : this( + url = input.readString() + ) + + /** + * {@inheritDoc} + */ + override fun writeTo(output: StreamOutput) { + output.writeString(url) + } + + /** + * {@inheritDoc} + */ + override fun toXContent(builder: XContentBuilder?, params: ToXContent.Params?): XContentBuilder { + builder!! + return builder.startObject() + .field(URL_TAG, url) + .endObject() + } +} diff --git a/src/main/kotlin/org/opensearch/commons/notifications/model/config/ConfigDataProperties.kt b/src/main/kotlin/org/opensearch/commons/notifications/model/config/ConfigDataProperties.kt index 4d70b18f..28063e30 100644 --- a/src/main/kotlin/org/opensearch/commons/notifications/model/config/ConfigDataProperties.kt +++ b/src/main/kotlin/org/opensearch/commons/notifications/model/config/ConfigDataProperties.kt @@ -9,6 +9,7 @@ import org.opensearch.commons.notifications.model.Chime import org.opensearch.commons.notifications.model.ConfigType import org.opensearch.commons.notifications.model.Email import org.opensearch.commons.notifications.model.EmailGroup +import org.opensearch.commons.notifications.model.MicrosoftTeams import org.opensearch.commons.notifications.model.SesAccount import org.opensearch.commons.notifications.model.Slack import org.opensearch.commons.notifications.model.SmtpAccount @@ -36,7 +37,8 @@ internal object ConfigDataProperties { Pair(ConfigType.SNS, ConfigProperty(Sns.reader, Sns.xParser)), Pair(ConfigType.SES_ACCOUNT, ConfigProperty(SesAccount.reader, SesAccount.xParser)), Pair(ConfigType.EMAIL_GROUP, ConfigProperty(EmailGroup.reader, EmailGroup.xParser)), - Pair(ConfigType.SMTP_ACCOUNT, ConfigProperty(SmtpAccount.reader, SmtpAccount.xParser)) + Pair(ConfigType.SMTP_ACCOUNT, ConfigProperty(SmtpAccount.reader, SmtpAccount.xParser)), + Pair(ConfigType.MICROSOFT_TEAMS, ConfigProperty(MicrosoftTeams.reader, MicrosoftTeams.xParser)) ) /** @@ -62,6 +64,7 @@ internal object ConfigDataProperties { ConfigType.CHIME -> configData is Chime ConfigType.SNS -> configData is Sns ConfigType.SES_ACCOUNT -> configData is SesAccount + ConfigType.MICROSOFT_TEAMS -> configData is MicrosoftTeams ConfigType.NONE -> true } } diff --git a/src/test/kotlin/org/opensearch/commons/notifications/action/CreateNotificationConfigRequestTests.kt b/src/test/kotlin/org/opensearch/commons/notifications/action/CreateNotificationConfigRequestTests.kt index 24f389e2..117375e7 100644 --- a/src/test/kotlin/org/opensearch/commons/notifications/action/CreateNotificationConfigRequestTests.kt +++ b/src/test/kotlin/org/opensearch/commons/notifications/action/CreateNotificationConfigRequestTests.kt @@ -15,6 +15,7 @@ import org.opensearch.commons.notifications.model.Email import org.opensearch.commons.notifications.model.EmailGroup import org.opensearch.commons.notifications.model.EmailRecipient import org.opensearch.commons.notifications.model.MethodType +import org.opensearch.commons.notifications.model.MicrosoftTeams import org.opensearch.commons.notifications.model.NotificationConfig import org.opensearch.commons.notifications.model.Slack import org.opensearch.commons.notifications.model.SmtpAccount @@ -57,6 +58,16 @@ internal class CreateNotificationConfigRequestTests { isEnabled = true ) } + private fun createMicrosoftTeamsContentConfigObject(): NotificationConfig { + val sampleMicrosoftTeams = MicrosoftTeams("https://domain.com/sample_microsoft_teams_url#1234567890") + return NotificationConfig( + "name", + "description", + ConfigType.MICROSOFT_TEAMS, + configData = sampleMicrosoftTeams, + isEnabled = true + ) + } private fun createEmailGroupContentConfigObject(): NotificationConfig { val sampleEmailGroup = EmailGroup(listOf(EmailRecipient("dummy@company.com"))) @@ -114,6 +125,20 @@ internal class CreateNotificationConfigRequestTests { assertNull(recreatedObject.validate()) assertEquals(configRequest.notificationConfig, recreatedObject.notificationConfig) } + @Test + fun `Create config serialize and deserialize transport object should be equal microsoft teams`() { + val configRequest = CreateNotificationConfigRequest( + createMicrosoftTeamsContentConfigObject() + ) + val recreatedObject = + recreateObject(configRequest) { + CreateNotificationConfigRequest( + it + ) + } + assertNull(recreatedObject.validate()) + assertEquals(configRequest.notificationConfig, recreatedObject.notificationConfig) + } @Test fun `Create config serialize and deserialize transport object should be equal slack`() { @@ -189,6 +214,15 @@ internal class CreateNotificationConfigRequestTests { assertNull(recreatedObject.validate()) assertEquals(configRequest.notificationConfig, recreatedObject.notificationConfig) } + @Test + fun `Create config serialize and deserialize using json object should be equal microsoft teams`() { + val configRequest = CreateNotificationConfigRequest( + createMicrosoftTeamsContentConfigObject() + ) + val jsonString = getJsonString(configRequest) + val recreatedObject = createObjectFromJsonString(jsonString) { CreateNotificationConfigRequest.parse(it) } + assertEquals(configRequest.notificationConfig, recreatedObject.notificationConfig) + } @Test fun `Create config serialize and deserialize using json object should be equal`() { @@ -275,6 +309,32 @@ internal class CreateNotificationConfigRequestTests { val recreatedObject = createObjectFromJsonString(jsonString) { CreateNotificationConfigRequest.parse(it) } assertEquals(config, recreatedObject.notificationConfig) } + @Test + fun `Create config should deserialize json object using parser microsoft teams`() { + val sampleMicrosoftTeams = MicrosoftTeams("https://domain.com/sample_microsoft_teams_url#1234567890") + val config = NotificationConfig( + "name", + "description", + ConfigType.MICROSOFT_TEAMS, + configData = sampleMicrosoftTeams, + isEnabled = true + ) + + val jsonString = """ + { + "config_id":"config_id1", + "config":{ + "name":"name", + "description":"description", + "config_type":"microsoft_teams", + "is_enabled":true, + "microsoft_teams":{"url":"https://domain.com/sample_microsoft_teams_url#1234567890"} + } + } + """.trimIndent() + val recreatedObject = createObjectFromJsonString(jsonString) { CreateNotificationConfigRequest.parse(it) } + assertEquals(config, recreatedObject.notificationConfig) + } @Test fun `Create config should deserialize json object using parser webhook`() { diff --git a/src/test/kotlin/org/opensearch/commons/notifications/action/GetChannelListResponseTests.kt b/src/test/kotlin/org/opensearch/commons/notifications/action/GetChannelListResponseTests.kt index eb4023dd..4f19ab4b 100644 --- a/src/test/kotlin/org/opensearch/commons/notifications/action/GetChannelListResponseTests.kt +++ b/src/test/kotlin/org/opensearch/commons/notifications/action/GetChannelListResponseTests.kt @@ -62,11 +62,17 @@ internal class GetChannelListResponseTests { "description3", ConfigType.WEBHOOK ) + val sampleConfig4 = Channel( + "config_id5", + "name4", + "description4", + ConfigType.MICROSOFT_TEAMS + ) val searchResult = ChannelList( 100, 1000, TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO, - listOf(sampleConfig1, sampleConfig2, sampleConfig3) + listOf(sampleConfig1, sampleConfig2, sampleConfig3, sampleConfig4) ) val getResponse = GetChannelListResponse(searchResult) val recreatedObject = recreateObject(getResponse) { GetChannelListResponse(it) } @@ -108,11 +114,17 @@ internal class GetChannelListResponseTests { "description3", ConfigType.WEBHOOK ) + val sampleConfig4 = Channel( + "config_id5", + "name4", + "description4", + ConfigType.MICROSOFT_TEAMS + ) val searchResult = ChannelList( 100, 1000, TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO, - listOf(sampleConfig1, sampleConfig2, sampleConfig3) + listOf(sampleConfig1, sampleConfig2, sampleConfig3, sampleConfig4) ) val getResponse = GetChannelListResponse(searchResult) val jsonString = getJsonString(getResponse) diff --git a/src/test/kotlin/org/opensearch/commons/notifications/action/GetNotificationConfigResponseTests.kt b/src/test/kotlin/org/opensearch/commons/notifications/action/GetNotificationConfigResponseTests.kt index 3cfccfcb..a0c025ac 100644 --- a/src/test/kotlin/org/opensearch/commons/notifications/action/GetNotificationConfigResponseTests.kt +++ b/src/test/kotlin/org/opensearch/commons/notifications/action/GetNotificationConfigResponseTests.kt @@ -10,6 +10,7 @@ import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test import org.opensearch.commons.notifications.model.Chime import org.opensearch.commons.notifications.model.ConfigType +import org.opensearch.commons.notifications.model.MicrosoftTeams import org.opensearch.commons.notifications.model.NotificationConfig import org.opensearch.commons.notifications.model.NotificationConfigInfo import org.opensearch.commons.notifications.model.NotificationConfigSearchResult @@ -79,11 +80,23 @@ internal class GetNotificationConfigResponseTests { Instant.now(), sampleConfig2 ) + val sampleConfig3 = NotificationConfig( + "name", + "description", + ConfigType.MICROSOFT_TEAMS, + configData = MicrosoftTeams("https://domain.com/sample_url#1234567890") + ) + val configInfo3 = NotificationConfigInfo( + "config_id3", + Instant.now(), + Instant.now(), + sampleConfig3 + ) val searchResult = NotificationConfigSearchResult( 100, 1000, TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO, - listOf(configInfo1, configInfo2) + listOf(configInfo1, configInfo2, configInfo3) ) val searchResponse = GetNotificationConfigResponse(searchResult) val recreatedObject = recreateObject(searchResponse) { GetNotificationConfigResponse(it) } @@ -142,11 +155,23 @@ internal class GetNotificationConfigResponseTests { createdTimeMs, sampleConfig2 ) + val sampleConfig3 = NotificationConfig( + "name", + "description", + ConfigType.MICROSOFT_TEAMS, + configData = MicrosoftTeams("https://domain.com/sample_url#1234567890") + ) + val configInfo3 = NotificationConfigInfo( + "config_id3", + lastUpdatedTimeMs, + createdTimeMs, + sampleConfig3 + ) val searchResult = NotificationConfigSearchResult( 100, 1000, TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO, - listOf(configInfo1, configInfo2) + listOf(configInfo1, configInfo2, configInfo3) ) val searchResponse = GetNotificationConfigResponse(searchResult) val jsonString = getJsonString(searchResponse) diff --git a/src/test/kotlin/org/opensearch/commons/notifications/action/UpdateNotificationConfigRequestTests.kt b/src/test/kotlin/org/opensearch/commons/notifications/action/UpdateNotificationConfigRequestTests.kt index a6e0077a..e07d7747 100644 --- a/src/test/kotlin/org/opensearch/commons/notifications/action/UpdateNotificationConfigRequestTests.kt +++ b/src/test/kotlin/org/opensearch/commons/notifications/action/UpdateNotificationConfigRequestTests.kt @@ -15,6 +15,7 @@ import org.opensearch.commons.notifications.model.Email import org.opensearch.commons.notifications.model.EmailGroup import org.opensearch.commons.notifications.model.EmailRecipient import org.opensearch.commons.notifications.model.MethodType +import org.opensearch.commons.notifications.model.MicrosoftTeams import org.opensearch.commons.notifications.model.NotificationConfig import org.opensearch.commons.notifications.model.Slack import org.opensearch.commons.notifications.model.SmtpAccount @@ -35,7 +36,16 @@ internal class UpdateNotificationConfigRequestTests { isEnabled = true ) } - + private fun createMicrosoftTeamsContentConfigObject(): NotificationConfig { + val sampleMicrosoftTeams = MicrosoftTeams("https://domain.com/sample_microsoft_teams_url#1234567890") + return NotificationConfig( + "name", + "description", + ConfigType.MICROSOFT_TEAMS, + configData = sampleMicrosoftTeams, + isEnabled = true + ) + } private fun createSlackContentConfigObject(): NotificationConfig { val sampleSlack = Slack("https://domain.com/sample_slack_url#1234567890") return NotificationConfig( @@ -109,6 +119,15 @@ internal class UpdateNotificationConfigRequestTests { assertEquals(configRequest.notificationConfig, recreatedObject.notificationConfig) assertEquals("config_id", recreatedObject.configId) } + @Test + fun `Update config serialize and deserialize transport object should be equal Microsoft Teams`() { + val configRequest = UpdateNotificationConfigRequest("config_id", createMicrosoftTeamsContentConfigObject()) + val recreatedObject = + recreateObject(configRequest) { UpdateNotificationConfigRequest(it) } + assertNull(recreatedObject.validate()) + assertEquals(configRequest.notificationConfig, recreatedObject.notificationConfig) + assertEquals("config_id", recreatedObject.configId) + } @Test fun `Update config serialize and deserialize transport object should be equal Slack`() { @@ -168,6 +187,14 @@ internal class UpdateNotificationConfigRequestTests { assertEquals(configRequest.notificationConfig, recreatedObject.notificationConfig) assertEquals("config_id", recreatedObject.configId) } + @Test + fun `Update config serialize and deserialize using json object should be equal microsoft Teams`() { + val configRequest = UpdateNotificationConfigRequest("config_id", createMicrosoftTeamsContentConfigObject()) + val jsonString = getJsonString(configRequest) + val recreatedObject = createObjectFromJsonString(jsonString) { UpdateNotificationConfigRequest.parse(it) } + assertEquals(configRequest.notificationConfig, recreatedObject.notificationConfig) + assertEquals("config_id", recreatedObject.configId) + } @Test fun `Update config serialize and deserialize using json object should be equal slack`() { diff --git a/src/test/kotlin/org/opensearch/commons/notifications/model/ChannelListTests.kt b/src/test/kotlin/org/opensearch/commons/notifications/model/ChannelListTests.kt index 06387d37..cad52261 100644 --- a/src/test/kotlin/org/opensearch/commons/notifications/model/ChannelListTests.kt +++ b/src/test/kotlin/org/opensearch/commons/notifications/model/ChannelListTests.kt @@ -55,12 +55,19 @@ internal class ChannelListTests { ConfigType.CHIME, true ) - val channelList = ChannelList(listOf(channel1, channel2)) + val channel3 = Channel( + "configId3", + "name3", + "description3", + ConfigType.MICROSOFT_TEAMS, + true + ) + val channelList = ChannelList(listOf(channel1, channel2, channel3)) val expectedResult = ChannelList( 0, - 2, + 3, TotalHits.Relation.EQUAL_TO, - listOf(channel1, channel2) + listOf(channel1, channel2, channel3) ) val recreatedObject = recreateObject(channelList) { ChannelList(it) } assertSearchResultEquals(expectedResult, recreatedObject) @@ -82,11 +89,18 @@ internal class ChannelListTests { ConfigType.CHIME, true ) + val channel3 = Channel( + "configId3", + "name3", + "description3", + ConfigType.MICROSOFT_TEAMS, + true + ) val channelList = ChannelList( 100, 1000, TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO, - listOf(channel1, channel2) + listOf(channel1, channel2, channel3) ) val recreatedObject = recreateObject(channelList) { ChannelList(it) } assertSearchResultEquals(channelList, recreatedObject) @@ -123,11 +137,18 @@ internal class ChannelListTests { ConfigType.CHIME, true ) + val channel3 = Channel( + "configId3", + "name3", + "description3", + ConfigType.MICROSOFT_TEAMS, + true + ) val channelList = ChannelList( 100, 1000, TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO, - listOf(channel1, channel2) + listOf(channel1, channel2, channel3) ) val jsonString = getJsonString(channelList) val recreatedObject = createObjectFromJsonString(jsonString) { ChannelList(it) } diff --git a/src/test/kotlin/org/opensearch/commons/notifications/model/EventStatusTests.kt b/src/test/kotlin/org/opensearch/commons/notifications/model/EventStatusTests.kt index 65173cfe..94b48e64 100644 --- a/src/test/kotlin/org/opensearch/commons/notifications/model/EventStatusTests.kt +++ b/src/test/kotlin/org/opensearch/commons/notifications/model/EventStatusTests.kt @@ -118,6 +118,17 @@ internal class EventStatusTests { } } + @Test + fun `Event throw exception if deliveryStatus is empty for config type MicrosoftTeams`() { + Assertions.assertThrows(IllegalArgumentException::class.java) { + EventStatus( + "config_id", + "name", + ConfigType.MICROSOFT_TEAMS + ) + } + } + @Test fun `Event throw exception if deliveryStatus is empty for config type Webhook`() { Assertions.assertThrows(IllegalArgumentException::class.java) { diff --git a/src/test/kotlin/org/opensearch/commons/notifications/model/FilterConfigListTests.kt b/src/test/kotlin/org/opensearch/commons/notifications/model/FilterConfigListTests.kt index de648bcd..11488e38 100644 --- a/src/test/kotlin/org/opensearch/commons/notifications/model/FilterConfigListTests.kt +++ b/src/test/kotlin/org/opensearch/commons/notifications/model/FilterConfigListTests.kt @@ -58,11 +58,17 @@ internal class FilterConfigListTests { "description3", ConfigType.WEBHOOK ) + val sampleConfig4 = Channel( + "config_id4", + "name4", + "description4", + ConfigType.MICROSOFT_TEAMS + ) val searchResult = ChannelList( 100, 1000, TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO, - listOf(sampleConfig1, sampleConfig2, sampleConfig3) + listOf(sampleConfig1, sampleConfig2, sampleConfig3, sampleConfig4) ) val recreatedObject = recreateObject(searchResult) { ChannelList(it) } assertSearchResultEquals(searchResult, recreatedObject) @@ -102,11 +108,17 @@ internal class FilterConfigListTests { "description3", ConfigType.WEBHOOK ) + val sampleConfig4 = Channel( + "config_id4", + "name4", + "description4", + ConfigType.MICROSOFT_TEAMS + ) val searchResult = ChannelList( 100, 1000, TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO, - listOf(sampleConfig1, sampleConfig2, sampleConfig3) + listOf(sampleConfig1, sampleConfig2, sampleConfig3, sampleConfig4) ) val jsonString = getJsonString(searchResult) val recreatedObject = createObjectFromJsonString(jsonString) { ChannelList(it) } diff --git a/src/test/kotlin/org/opensearch/commons/notifications/model/MicrosoftTeamsTests.kt b/src/test/kotlin/org/opensearch/commons/notifications/model/MicrosoftTeamsTests.kt new file mode 100644 index 00000000..4543c06b --- /dev/null +++ b/src/test/kotlin/org/opensearch/commons/notifications/model/MicrosoftTeamsTests.kt @@ -0,0 +1,87 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ +package org.opensearch.commons.notifications.model + +import com.fasterxml.jackson.core.JsonParseException +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.opensearch.commons.utils.createObjectFromJsonString +import org.opensearch.commons.utils.getJsonString +import org.opensearch.commons.utils.recreateObject +import java.net.MalformedURLException + +internal class MicrosoftTeamsTests { + + @Test + fun `Microsoft Teams serialize and deserialize transport object should be equal`() { + val sampleMicrosoftTeams = MicrosoftTeams("https://domain.com/sample_url#1234567890") + val recreatedObject = recreateObject(sampleMicrosoftTeams) { MicrosoftTeams(it) } + assertEquals(sampleMicrosoftTeams, recreatedObject) + } + + @Test + fun `Microsoft Teams serialize and deserialize using json object should be equal`() { + val sampleMicrosoftTeams = MicrosoftTeams("https://domain.com/sample_url#1234567890") + val jsonString = getJsonString(sampleMicrosoftTeams) + val recreatedObject = createObjectFromJsonString(jsonString) { MicrosoftTeams.parse(it) } + assertEquals(sampleMicrosoftTeams, recreatedObject) + } + + @Test + fun `Microsoft Teams should deserialize json object using parser`() { + val sampleMicrosoftTeams = MicrosoftTeams("https://domain.com/sample_url#1234567890") + val jsonString = "{\"url\":\"${sampleMicrosoftTeams.url}\"}" + val recreatedObject = createObjectFromJsonString(jsonString) { MicrosoftTeams.parse(it) } + assertEquals(sampleMicrosoftTeams, recreatedObject) + } + + @Test + fun `Microsoft Teams should throw exception when invalid json object is passed`() { + val jsonString = "sample message" + assertThrows { + createObjectFromJsonString(jsonString) { MicrosoftTeams.parse(it) } + } + } + + @Test + fun `Microsoft Teams should throw exception when url is replace with url2 in json object`() { + val sampleMicrosoftTeams = MicrosoftTeams("https://domain.com/sample_url#1234567890") + val jsonString = "{\"url2\":\"${sampleMicrosoftTeams.url}\"}" + assertThrows { + createObjectFromJsonString(jsonString) { MicrosoftTeams.parse(it) } + } + } + + @Test + fun `Microsoft Teams should throw exception when url is not proper`() { + assertThrows { + MicrosoftTeams("domain.com/sample_url#1234567890") + } + val jsonString = "{\"url\":\"domain.com/sample_url\"}" + assertThrows { + createObjectFromJsonString(jsonString) { MicrosoftTeams.parse(it) } + } + } + + @Test + fun `Microsoft Teams should throw exception when url protocol is not https or http`() { + assertThrows { + MicrosoftTeams("ftp://domain.com/sample_url#1234567890") + } + val jsonString = "{\"url\":\"ftp://domain.com/sample_url\"}" + assertThrows { + createObjectFromJsonString(jsonString) { MicrosoftTeams.parse(it) } + } + } + + @Test + fun `Microsoft Teams should safely ignore extra field in json object`() { + val sampleMicrosoftTeams = MicrosoftTeams("https://domain.com/sample_url#1234567890") + val jsonString = "{\"url\":\"${sampleMicrosoftTeams.url}\", \"another\":\"field\"}" + val recreatedObject = createObjectFromJsonString(jsonString) { MicrosoftTeams.parse(it) } + assertEquals(sampleMicrosoftTeams, recreatedObject) + } +} diff --git a/src/test/kotlin/org/opensearch/commons/notifications/model/NotificationConfigTests.kt b/src/test/kotlin/org/opensearch/commons/notifications/model/NotificationConfigTests.kt index f8aa9e9d..31791120 100644 --- a/src/test/kotlin/org/opensearch/commons/notifications/model/NotificationConfigTests.kt +++ b/src/test/kotlin/org/opensearch/commons/notifications/model/NotificationConfigTests.kt @@ -66,6 +66,33 @@ internal class NotificationConfigTests { assertEquals(sampleConfig, recreatedObject) } + @Test + fun `Config serialize and deserialize with microsoft teams object should be equal`() { + val sampleMicrosoftTeams = MicrosoftTeams("https://domain.com/sample_url#1234567890") + val sampleConfig = NotificationConfig( + "name", + "description", + ConfigType.MICROSOFT_TEAMS, + configData = sampleMicrosoftTeams + ) + val recreatedObject = recreateObject(sampleConfig) { NotificationConfig(it) } + assertEquals(sampleConfig, recreatedObject) + } + + @Test + fun `Config serialize and deserialize with json microsoft teams object should be equal`() { + val sampleMicrosoftTeams = MicrosoftTeams("https://domain.com/sample_url#1234567890") + val sampleConfig = NotificationConfig( + "name", + "description", + ConfigType.MICROSOFT_TEAMS, + configData = sampleMicrosoftTeams + ) + val jsonString = getJsonString(sampleConfig) + val recreatedObject = createObjectFromJsonString(jsonString) { NotificationConfig.parse(it) } + assertEquals(sampleConfig, recreatedObject) + } + @Test fun `Config serialize and deserialize with webhook object should be equal`() { val sampleWebhook = Webhook("https://domain.com/sample_url#1234567890") diff --git a/src/test/kotlin/org/opensearch/commons/notifications/model/config/ConfigPropertiesTests.kt b/src/test/kotlin/org/opensearch/commons/notifications/model/config/ConfigPropertiesTests.kt index 80a20b88..881cf9d4 100644 --- a/src/test/kotlin/org/opensearch/commons/notifications/model/config/ConfigPropertiesTests.kt +++ b/src/test/kotlin/org/opensearch/commons/notifications/model/config/ConfigPropertiesTests.kt @@ -7,6 +7,7 @@ import org.opensearch.commons.notifications.model.Email import org.opensearch.commons.notifications.model.EmailGroup import org.opensearch.commons.notifications.model.EmailRecipient import org.opensearch.commons.notifications.model.MethodType +import org.opensearch.commons.notifications.model.MicrosoftTeams import org.opensearch.commons.notifications.model.Slack import org.opensearch.commons.notifications.model.SmtpAccount import org.opensearch.commons.notifications.model.Webhook @@ -22,6 +23,11 @@ internal class ConfigPropertiesTests { assertEquals(getReaderForConfigType(ConfigType.SLACK), Slack.reader) } + @Test + fun `Validate config property reader Microsoft Teams`() { + assertEquals(getReaderForConfigType(ConfigType.MICROSOFT_TEAMS), MicrosoftTeams.reader) + } + @Test fun `Validate config property reader chime`() { assertEquals(getReaderForConfigType(ConfigType.CHIME), Chime.reader) @@ -48,7 +54,7 @@ internal class ConfigPropertiesTests { } @Test - fun `Validate config data parse slack`() { + fun `Validate config data parse slack`() { val sampleSlack = Slack("https://domain.com/sample_url#1234567890") val jsonString = getJsonString(sampleSlack) val recreatedObject = createObjectFromJsonString(jsonString) { createConfigData(ConfigType.SLACK, it) } @@ -70,7 +76,13 @@ internal class ConfigPropertiesTests { val recreatedObject = createObjectFromJsonString(jsonString) { createConfigData(ConfigType.WEBHOOK, it) } assertEquals(sampleWebhook, recreatedObject) } - + @Test + fun `Validate config data parse Microsoft Teams`() { + val sampleMicrosoftTeams = MicrosoftTeams("https://domain.com/sample_url#1234567890") + val jsonString = getJsonString(sampleMicrosoftTeams) + val recreatedObject = createObjectFromJsonString(jsonString) { createConfigData(ConfigType.MICROSOFT_TEAMS, it) } + assertEquals(sampleMicrosoftTeams, recreatedObject) + } @Test fun `Validate config data parse EmailGroup`() { val sampleEmailGroup = EmailGroup(listOf(EmailRecipient("email1@email.com"), EmailRecipient("email2@email.com")))