|  | 
|  | 1 | +/* | 
|  | 2 | + * SPDX-License-Identifier: Apache-2.0 | 
|  | 3 | + * | 
|  | 4 | + * The OpenSearch Contributors require contributions made to | 
|  | 5 | + * this file be licensed under the Apache-2.0 license or a | 
|  | 6 | + * compatible open source license. | 
|  | 7 | + * | 
|  | 8 | + * Modifications Copyright OpenSearch Contributors. See | 
|  | 9 | + * GitHub history for details. | 
|  | 10 | + */ | 
|  | 11 | +package org.opensearch.commons.notifications | 
|  | 12 | + | 
|  | 13 | +import com.nhaarman.mockitokotlin2.whenever | 
|  | 14 | +import org.junit.jupiter.api.Test | 
|  | 15 | +import org.junit.jupiter.api.extension.ExtendWith | 
|  | 16 | +import org.mockito.Answers | 
|  | 17 | +import org.mockito.ArgumentMatchers.eq | 
|  | 18 | +import org.mockito.Mock | 
|  | 19 | +import org.mockito.Mockito.any | 
|  | 20 | +import org.mockito.Mockito.doAnswer | 
|  | 21 | +import org.mockito.Mockito.mock | 
|  | 22 | +import org.mockito.Mockito.times | 
|  | 23 | +import org.mockito.Mockito.verify | 
|  | 24 | +import org.mockito.junit.jupiter.MockitoExtension | 
|  | 25 | +import org.opensearch.action.ActionListener | 
|  | 26 | +import org.opensearch.action.ActionType | 
|  | 27 | +import org.opensearch.client.node.NodeClient | 
|  | 28 | +import org.opensearch.commons.notifications.action.CreateNotificationConfigRequest | 
|  | 29 | +import org.opensearch.commons.notifications.action.CreateNotificationConfigResponse | 
|  | 30 | +import org.opensearch.commons.notifications.action.DeleteNotificationConfigRequest | 
|  | 31 | +import org.opensearch.commons.notifications.action.DeleteNotificationConfigResponse | 
|  | 32 | +import org.opensearch.commons.notifications.action.GetFeatureChannelListRequest | 
|  | 33 | +import org.opensearch.commons.notifications.action.GetFeatureChannelListResponse | 
|  | 34 | +import org.opensearch.commons.notifications.action.GetNotificationConfigRequest | 
|  | 35 | +import org.opensearch.commons.notifications.action.GetNotificationConfigResponse | 
|  | 36 | +import org.opensearch.commons.notifications.action.GetNotificationEventRequest | 
|  | 37 | +import org.opensearch.commons.notifications.action.GetNotificationEventResponse | 
|  | 38 | +import org.opensearch.commons.notifications.action.GetPluginFeaturesRequest | 
|  | 39 | +import org.opensearch.commons.notifications.action.GetPluginFeaturesResponse | 
|  | 40 | +import org.opensearch.commons.notifications.action.SendNotificationResponse | 
|  | 41 | +import org.opensearch.commons.notifications.action.UpdateNotificationConfigRequest | 
|  | 42 | +import org.opensearch.commons.notifications.action.UpdateNotificationConfigResponse | 
|  | 43 | +import org.opensearch.commons.notifications.model.ChannelMessage | 
|  | 44 | +import org.opensearch.commons.notifications.model.ConfigType | 
|  | 45 | +import org.opensearch.commons.notifications.model.DeliveryStatus | 
|  | 46 | +import org.opensearch.commons.notifications.model.EventSource | 
|  | 47 | +import org.opensearch.commons.notifications.model.EventStatus | 
|  | 48 | +import org.opensearch.commons.notifications.model.Feature | 
|  | 49 | +import org.opensearch.commons.notifications.model.FeatureChannel | 
|  | 50 | +import org.opensearch.commons.notifications.model.FeatureChannelList | 
|  | 51 | +import org.opensearch.commons.notifications.model.NotificationConfig | 
|  | 52 | +import org.opensearch.commons.notifications.model.NotificationConfigInfo | 
|  | 53 | +import org.opensearch.commons.notifications.model.NotificationConfigSearchResult | 
|  | 54 | +import org.opensearch.commons.notifications.model.NotificationEvent | 
|  | 55 | +import org.opensearch.commons.notifications.model.NotificationEventInfo | 
|  | 56 | +import org.opensearch.commons.notifications.model.NotificationEventSearchResult | 
|  | 57 | +import org.opensearch.commons.notifications.model.SeverityType | 
|  | 58 | +import org.opensearch.commons.notifications.model.Slack | 
|  | 59 | +import org.opensearch.rest.RestStatus | 
|  | 60 | +import java.time.Instant | 
|  | 61 | +import java.util.EnumSet | 
|  | 62 | + | 
|  | 63 | +@Suppress("UNCHECKED_CAST") | 
|  | 64 | +@ExtendWith(MockitoExtension::class) | 
|  | 65 | +internal class NotificationsPluginInterfaceTests { | 
|  | 66 | + | 
|  | 67 | +    @Mock(answer = Answers.RETURNS_DEEP_STUBS) | 
|  | 68 | +    private lateinit var client: NodeClient | 
|  | 69 | + | 
|  | 70 | +    @Test | 
|  | 71 | +    fun createNotificationConfig() { | 
|  | 72 | +        val request = mock(CreateNotificationConfigRequest::class.java) | 
|  | 73 | +        val response = CreateNotificationConfigResponse("configId") | 
|  | 74 | +        val listener: ActionListener<CreateNotificationConfigResponse> = | 
|  | 75 | +            mock(ActionListener::class.java) as ActionListener<CreateNotificationConfigResponse> | 
|  | 76 | + | 
|  | 77 | +        doAnswer { | 
|  | 78 | +            (it.getArgument(2) as ActionListener<CreateNotificationConfigResponse>) | 
|  | 79 | +                .onResponse(response) | 
|  | 80 | +        }.whenever(client).execute(any(ActionType::class.java), any(), any()) | 
|  | 81 | + | 
|  | 82 | +        NotificationsPluginInterface.createNotificationConfig(client, request, listener) | 
|  | 83 | +        verify(listener, times(1)).onResponse(eq(response)) | 
|  | 84 | +    } | 
|  | 85 | + | 
|  | 86 | +    @Test | 
|  | 87 | +    fun updateNotificationConfig() { | 
|  | 88 | +        val request = mock(UpdateNotificationConfigRequest::class.java) | 
|  | 89 | +        val response = UpdateNotificationConfigResponse("configId") | 
|  | 90 | +        val listener: ActionListener<UpdateNotificationConfigResponse> = | 
|  | 91 | +            mock(ActionListener::class.java) as ActionListener<UpdateNotificationConfigResponse> | 
|  | 92 | + | 
|  | 93 | +        doAnswer { | 
|  | 94 | +            (it.getArgument(2) as ActionListener<UpdateNotificationConfigResponse>) | 
|  | 95 | +                .onResponse(response) | 
|  | 96 | +        }.whenever(client).execute(any(ActionType::class.java), any(), any()) | 
|  | 97 | + | 
|  | 98 | +        NotificationsPluginInterface.updateNotificationConfig(client, request, listener) | 
|  | 99 | +        verify(listener, times(1)).onResponse(eq(response)) | 
|  | 100 | +    } | 
|  | 101 | + | 
|  | 102 | +    @Test | 
|  | 103 | +    fun deleteNotificationConfig() { | 
|  | 104 | +        val request = mock(DeleteNotificationConfigRequest::class.java) | 
|  | 105 | +        val response = DeleteNotificationConfigResponse(mapOf(Pair("sample_config_id", RestStatus.OK))) | 
|  | 106 | +        val listener: ActionListener<DeleteNotificationConfigResponse> = | 
|  | 107 | +            mock(ActionListener::class.java) as ActionListener<DeleteNotificationConfigResponse> | 
|  | 108 | + | 
|  | 109 | +        doAnswer { | 
|  | 110 | +            (it.getArgument(2) as ActionListener<DeleteNotificationConfigResponse>) | 
|  | 111 | +                .onResponse(response) | 
|  | 112 | +        }.whenever(client).execute(any(ActionType::class.java), any(), any()) | 
|  | 113 | + | 
|  | 114 | +        NotificationsPluginInterface.deleteNotificationConfig(client, request, listener) | 
|  | 115 | +        verify(listener, times(1)).onResponse(eq(response)) | 
|  | 116 | +    } | 
|  | 117 | + | 
|  | 118 | +    @Test | 
|  | 119 | +    fun getNotificationConfig() { | 
|  | 120 | +        val request = mock(GetNotificationConfigRequest::class.java) | 
|  | 121 | +        val response = mockGetNotificationConfigResponse() | 
|  | 122 | +        val listener: ActionListener<GetNotificationConfigResponse> = | 
|  | 123 | +            mock(ActionListener::class.java) as ActionListener<GetNotificationConfigResponse> | 
|  | 124 | + | 
|  | 125 | +        doAnswer { | 
|  | 126 | +            (it.getArgument(2) as ActionListener<GetNotificationConfigResponse>) | 
|  | 127 | +                .onResponse(response) | 
|  | 128 | +        }.whenever(client).execute(any(ActionType::class.java), any(), any()) | 
|  | 129 | + | 
|  | 130 | +        NotificationsPluginInterface.getNotificationConfig(client, request, listener) | 
|  | 131 | +        verify(listener, times(1)).onResponse(eq(response)) | 
|  | 132 | +    } | 
|  | 133 | + | 
|  | 134 | +    @Test | 
|  | 135 | +    fun getNotificationEvent() { | 
|  | 136 | +        val request = mock(GetNotificationEventRequest::class.java) | 
|  | 137 | +        val response = mockGetNotificationEventResponse() | 
|  | 138 | +        val listener: ActionListener<GetNotificationEventResponse> = | 
|  | 139 | +            mock(ActionListener::class.java) as ActionListener<GetNotificationEventResponse> | 
|  | 140 | + | 
|  | 141 | +        doAnswer { | 
|  | 142 | +            (it.getArgument(2) as ActionListener<GetNotificationEventResponse>) | 
|  | 143 | +                .onResponse(response) | 
|  | 144 | +        }.whenever(client).execute(any(ActionType::class.java), any(), any()) | 
|  | 145 | + | 
|  | 146 | +        NotificationsPluginInterface.getNotificationEvent(client, request, listener) | 
|  | 147 | +        verify(listener, times(1)).onResponse(eq(response)) | 
|  | 148 | +    } | 
|  | 149 | + | 
|  | 150 | +    @Test | 
|  | 151 | +    fun getPluginFeatures() { | 
|  | 152 | +        val request = mock(GetPluginFeaturesRequest::class.java) | 
|  | 153 | +        val response = GetPluginFeaturesResponse( | 
|  | 154 | +            listOf("config_type_1", "config_type_2", "config_type_3"), | 
|  | 155 | +            mapOf( | 
|  | 156 | +                Pair("FeatureKey1", "FeatureValue1"), | 
|  | 157 | +                Pair("FeatureKey2", "FeatureValue2"), | 
|  | 158 | +                Pair("FeatureKey3", "FeatureValue3") | 
|  | 159 | +            ) | 
|  | 160 | +        ) | 
|  | 161 | +        val listener: ActionListener<GetPluginFeaturesResponse> = | 
|  | 162 | +            mock(ActionListener::class.java) as ActionListener<GetPluginFeaturesResponse> | 
|  | 163 | + | 
|  | 164 | +        doAnswer { | 
|  | 165 | +            (it.getArgument(2) as ActionListener<GetPluginFeaturesResponse>) | 
|  | 166 | +                .onResponse(response) | 
|  | 167 | +        }.whenever(client).execute(any(ActionType::class.java), any(), any()) | 
|  | 168 | + | 
|  | 169 | +        NotificationsPluginInterface.getPluginFeatures(client, request, listener) | 
|  | 170 | +        verify(listener, times(1)).onResponse(eq(response)) | 
|  | 171 | +    } | 
|  | 172 | + | 
|  | 173 | +    @Test | 
|  | 174 | +    fun getFeatureChannelList() { | 
|  | 175 | +        val sampleConfig = FeatureChannel( | 
|  | 176 | +            "config_id", | 
|  | 177 | +            "name", | 
|  | 178 | +            "description", | 
|  | 179 | +            ConfigType.SLACK | 
|  | 180 | +        ) | 
|  | 181 | + | 
|  | 182 | +        val request = mock(GetFeatureChannelListRequest::class.java) | 
|  | 183 | +        val response = GetFeatureChannelListResponse(FeatureChannelList(sampleConfig)) | 
|  | 184 | +        val listener: ActionListener<GetFeatureChannelListResponse> = | 
|  | 185 | +            mock(ActionListener::class.java) as ActionListener<GetFeatureChannelListResponse> | 
|  | 186 | + | 
|  | 187 | +        doAnswer { | 
|  | 188 | +            (it.getArgument(2) as ActionListener<GetFeatureChannelListResponse>) | 
|  | 189 | +                .onResponse(response) | 
|  | 190 | +        }.whenever(client).execute(any(ActionType::class.java), any(), any()) | 
|  | 191 | + | 
|  | 192 | +        NotificationsPluginInterface.getFeatureChannelList(client, request, listener) | 
|  | 193 | +        verify(listener, times(1)).onResponse(eq(response)) | 
|  | 194 | +    } | 
|  | 195 | + | 
|  | 196 | +    @Test | 
|  | 197 | +    fun sendNotification() { | 
|  | 198 | +        val notificationInfo = EventSource( | 
|  | 199 | +            "title", | 
|  | 200 | +            "reference_id", | 
|  | 201 | +            Feature.REPORTS, | 
|  | 202 | +            SeverityType.HIGH, | 
|  | 203 | +            listOf("tag1", "tag2") | 
|  | 204 | +        ) | 
|  | 205 | +        val channelMessage = ChannelMessage( | 
|  | 206 | +            "text_description", | 
|  | 207 | +            "<b>htmlDescription</b>", | 
|  | 208 | +            null | 
|  | 209 | +        ) | 
|  | 210 | + | 
|  | 211 | +        val response = SendNotificationResponse("configId") | 
|  | 212 | +        val listener: ActionListener<SendNotificationResponse> = | 
|  | 213 | +            mock(ActionListener::class.java) as ActionListener<SendNotificationResponse> | 
|  | 214 | + | 
|  | 215 | +        doAnswer { | 
|  | 216 | +            (it.getArgument(2) as ActionListener<SendNotificationResponse>) | 
|  | 217 | +                .onResponse(response) | 
|  | 218 | +        }.whenever(client).execute(any(ActionType::class.java), any(), any()) | 
|  | 219 | + | 
|  | 220 | +        NotificationsPluginInterface.sendNotification( | 
|  | 221 | +            client, notificationInfo, channelMessage, listOf("channelId1", "channelId2"), listener | 
|  | 222 | +        ) | 
|  | 223 | +        verify(listener, times(1)).onResponse(eq(response)) | 
|  | 224 | +    } | 
|  | 225 | + | 
|  | 226 | +    private fun mockGetNotificationConfigResponse(): GetNotificationConfigResponse { | 
|  | 227 | +        val sampleSlack = Slack("https://domain.com/sample_url#1234567890") | 
|  | 228 | +        val sampleConfig = NotificationConfig( | 
|  | 229 | +            "name", | 
|  | 230 | +            "description", | 
|  | 231 | +            ConfigType.SLACK, | 
|  | 232 | +            EnumSet.of(Feature.REPORTS), | 
|  | 233 | +            configData = sampleSlack | 
|  | 234 | +        ) | 
|  | 235 | +        val configInfo = NotificationConfigInfo( | 
|  | 236 | +            "config_id", | 
|  | 237 | +            Instant.now(), | 
|  | 238 | +            Instant.now(), | 
|  | 239 | +            "tenant", | 
|  | 240 | +            sampleConfig | 
|  | 241 | +        ) | 
|  | 242 | +        return GetNotificationConfigResponse(NotificationConfigSearchResult(configInfo)) | 
|  | 243 | +    } | 
|  | 244 | + | 
|  | 245 | +    private fun mockGetNotificationEventResponse(): GetNotificationEventResponse { | 
|  | 246 | +        val sampleEventSource = EventSource( | 
|  | 247 | +            "title", | 
|  | 248 | +            "reference_id", | 
|  | 249 | +            Feature.ALERTING, | 
|  | 250 | +            severity = SeverityType.INFO | 
|  | 251 | +        ) | 
|  | 252 | +        val sampleStatus = EventStatus( | 
|  | 253 | +            "config_id", | 
|  | 254 | +            "name", | 
|  | 255 | +            ConfigType.SLACK, | 
|  | 256 | +            deliveryStatus = DeliveryStatus("404", "invalid recipient") | 
|  | 257 | +        ) | 
|  | 258 | +        val sampleEvent = NotificationEvent(sampleEventSource, listOf(sampleStatus)) | 
|  | 259 | +        val eventInfo = NotificationEventInfo( | 
|  | 260 | +            "event_id", | 
|  | 261 | +            Instant.now(), | 
|  | 262 | +            Instant.now(), | 
|  | 263 | +            "tenant", | 
|  | 264 | +            sampleEvent | 
|  | 265 | +        ) | 
|  | 266 | +        return GetNotificationEventResponse(NotificationEventSearchResult(eventInfo)) | 
|  | 267 | +    } | 
|  | 268 | +} | 
0 commit comments