1
+ /*
2
+ * Copyright OpenSearch Contributors
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ package org .opensearch .securityanalytics .alerts ;
7
+
8
+ import java .time .Instant ;
9
+ import java .time .ZoneId ;
10
+ import java .util .Collections ;
11
+ import java .util .List ;
12
+ import java .util .Map ;
13
+ import org .opensearch .core .action .ActionListener ;
14
+ import org .opensearch .client .Client ;
15
+ import org .opensearch .commons .alerting .model .Alert ;
16
+ import org .opensearch .commons .alerting .model .CronSchedule ;
17
+ import org .opensearch .commons .alerting .model .DataSources ;
18
+ import org .opensearch .commons .alerting .model .DocumentLevelTrigger ;
19
+ import org .opensearch .commons .alerting .model .Monitor ;
20
+ import org .opensearch .commons .alerting .model .Table ;
21
+ import org .opensearch .core .rest .RestStatus ;
22
+ import org .opensearch .script .Script ;
23
+ import org .opensearch .securityanalytics .action .AlertDto ;
24
+ import org .opensearch .securityanalytics .action .GetAlertsResponse ;
25
+ import org .opensearch .securityanalytics .action .GetDetectorAction ;
26
+ import org .opensearch .securityanalytics .action .GetDetectorRequest ;
27
+ import org .opensearch .securityanalytics .action .GetDetectorResponse ;
28
+ import org .opensearch .securityanalytics .config .monitors .DetectorMonitorConfig ;
29
+ import org .opensearch .securityanalytics .model .Detector ;
30
+ import org .opensearch .securityanalytics .transport .TransportIndexDetectorAction ;
31
+ import org .opensearch .test .OpenSearchTestCase ;
32
+
33
+
34
+ import static org .mockito .ArgumentMatchers .any ;
35
+ import static org .mockito .ArgumentMatchers .anyString ;
36
+ import static org .mockito .ArgumentMatchers .eq ;
37
+ import static org .mockito .Mockito .doAnswer ;
38
+ import static org .mockito .Mockito .mock ;
39
+ import static org .mockito .Mockito .spy ;
40
+
41
+ public class AlertingServiceTests extends OpenSearchTestCase {
42
+
43
+ public void testGetAlerts_success () {
44
+ AlertsService alertssService = spy (AlertsService .class );
45
+ Client client = mock (Client .class );
46
+ alertssService .setIndicesAdminClient (client );
47
+ // Create fake GetDetectorResponse
48
+ Detector detector = new Detector (
49
+ "detector_id123" ,
50
+ 0L ,
51
+ "test-monitor" ,
52
+ true ,
53
+ new CronSchedule ("31 * * * *" , ZoneId .of ("Asia/Kolkata" ), Instant .ofEpochSecond (1538164858L )),
54
+ Instant .now (),
55
+ Instant .now (),
56
+ "others_application" ,
57
+ null ,
58
+ List .of (),
59
+ List .of (),
60
+ List .of ("monitor_id1" , "monitor_id2" ),
61
+ DetectorMonitorConfig .getRuleIndex ("others_application" ),
62
+ null ,
63
+ DetectorMonitorConfig .getAlertsIndex ("others_application" ),
64
+ null ,
65
+ null ,
66
+ DetectorMonitorConfig .getFindingsIndex ("others_application" ),
67
+ Collections .emptyMap (),
68
+ Collections .emptyList (),
69
+ false
70
+ );
71
+ GetDetectorResponse getDetectorResponse = new GetDetectorResponse ("detector_id123" , 1L , RestStatus .OK , detector );
72
+
73
+ // Setup getDetector interceptor and return fake GetDetectorResponse by calling listener.onResponse
74
+ doAnswer (invocation -> {
75
+ ActionListener l = invocation .getArgument (2 );
76
+ l .onResponse (getDetectorResponse );
77
+ return null ;
78
+ }).when (client ).execute (eq (GetDetectorAction .INSTANCE ), any (GetDetectorRequest .class ), any (ActionListener .class ));
79
+
80
+ // Alerting GetAlertsResponse mock #1
81
+ Alert alert1 = new Alert (
82
+ "alert_id_1" ,
83
+ new Monitor (
84
+ "monitor_id_1" ,
85
+ -3 ,
86
+ "monitor_name" ,
87
+ true ,
88
+ new CronSchedule ("31 * * * *" , ZoneId .of ("Asia/Kolkata" ), Instant .ofEpochSecond (1538164858L )),
89
+ Instant .now (),
90
+ Instant .now (),
91
+ Monitor .MonitorType .DOC_LEVEL_MONITOR ,
92
+ null ,
93
+ 1 ,
94
+ List .of (),
95
+ List .of (),
96
+ Map .of (),
97
+ new DataSources (),
98
+ TransportIndexDetectorAction .PLUGIN_OWNER_FIELD
99
+ ),
100
+ new DocumentLevelTrigger ("trigger_id_1" , "my_trigger" , "severity_low" , List .of (), new Script ("" )),
101
+ List .of ("finding_id_1" ),
102
+ List .of ("docId1" ),
103
+ Instant .now (),
104
+ Instant .now (),
105
+ Alert .State .COMPLETED ,
106
+ null ,
107
+ List .of (),
108
+ List .of (),
109
+ 3 ,
110
+ null ,
111
+ null ,
112
+ null
113
+ );
114
+
115
+ Alert alert2 = new Alert (
116
+ "alert_id_1" ,
117
+ new Monitor (
118
+ "monitor_id_1" ,
119
+ -3 ,
120
+ "monitor_name" ,
121
+ true ,
122
+ new CronSchedule ("31 * * * *" , ZoneId .of ("Asia/Kolkata" ), Instant .ofEpochSecond (1538164858L )),
123
+ Instant .now (),
124
+ Instant .now (),
125
+ Monitor .MonitorType .DOC_LEVEL_MONITOR ,
126
+ null ,
127
+ 1 ,
128
+ List .of (),
129
+ List .of (),
130
+ Map .of (),
131
+ new DataSources (),
132
+ TransportIndexDetectorAction .PLUGIN_OWNER_FIELD
133
+ ),
134
+ new DocumentLevelTrigger ("trigger_id_1" , "my_trigger" , "severity_low" , List .of (), new Script ("" )),
135
+ List .of ("finding_id_1" ),
136
+ List .of ("docId1" ),
137
+ Instant .now (),
138
+ Instant .now (),
139
+ Alert .State .COMPLETED ,
140
+ null ,
141
+ List .of (),
142
+ List .of (),
143
+ 3 ,
144
+ null ,
145
+ null ,
146
+ null
147
+ );
148
+
149
+ GetAlertsResponse getAlertsResponse = new GetAlertsResponse (
150
+ List .of (new AlertDto (
151
+ detector .getId (),
152
+ alert1 .getId (),
153
+ alert1 .getVersion (),
154
+ alert1 .getSchemaVersion (),
155
+ alert1 .getTriggerId (),
156
+ alert1 .getTriggerName (),
157
+ alert1 .getFindingIds (),
158
+ alert1 .getRelatedDocIds (),
159
+ alert1 .getState (),
160
+ alert1 .getStartTime (),
161
+ alert1 .getEndTime (),
162
+ alert1 .getLastNotificationTime (),
163
+ alert1 .getAcknowledgedTime (),
164
+ alert1 .getErrorMessage (),
165
+ alert1 .getErrorHistory (),
166
+ alert1 .getSeverity (),
167
+ alert1 .getActionExecutionResults (),
168
+ alert1 .getAggregationResultBucket ()
169
+ ),
170
+ new AlertDto (
171
+ detector .getId (),
172
+ alert2 .getId (),
173
+ alert2 .getVersion (),
174
+ alert2 .getSchemaVersion (),
175
+ alert2 .getTriggerId (),
176
+ alert2 .getTriggerName (),
177
+ alert2 .getFindingIds (),
178
+ alert2 .getRelatedDocIds (),
179
+ alert2 .getState (),
180
+ alert2 .getStartTime (),
181
+ alert2 .getEndTime (),
182
+ alert2 .getLastNotificationTime (),
183
+ alert2 .getAcknowledgedTime (),
184
+ alert2 .getErrorMessage (),
185
+ alert2 .getErrorHistory (),
186
+ alert2 .getSeverity (),
187
+ alert2 .getActionExecutionResults (),
188
+ alert2 .getAggregationResultBucket ()
189
+ )
190
+ ), 2
191
+ );
192
+
193
+ doAnswer (invocation -> {
194
+ ActionListener l = invocation .getArgument (6 );
195
+ l .onResponse (getAlertsResponse );
196
+ return null ;
197
+ }).when (alertssService ).getAlertsByMonitorIds (any (), any (), anyString (), any (Table .class ), anyString (), anyString (), any (ActionListener .class ));
198
+
199
+ // Call getFindingsByDetectorId
200
+ Table table = new Table (
201
+ "asc" ,
202
+ "id" ,
203
+ null ,
204
+ 100 ,
205
+ 0 ,
206
+ null
207
+ );
208
+ alertssService .getAlertsByDetectorId ("detector_id123" , table , "severity_low" , Alert .State .COMPLETED .toString (), new ActionListener <>() {
209
+ @ Override
210
+ public void onResponse (GetAlertsResponse getAlertsResponse ) {
211
+ assertEquals (2 , (int )getAlertsResponse .getTotalAlerts ());
212
+ assertEquals (2 , getAlertsResponse .getAlerts ().size ());
213
+ }
214
+
215
+ @ Override
216
+ public void onFailure (Exception e ) {
217
+
218
+ }
219
+ });
220
+ }
221
+
222
+ public void testGetFindings_getFindingsByMonitorIdFailures () {
223
+
224
+ AlertsService alertssService = spy (AlertsService .class );
225
+ Client client = mock (Client .class );
226
+ alertssService .setIndicesAdminClient (client );
227
+ // Create fake GetDetectorResponse
228
+ Detector detector = new Detector (
229
+ "detector_id123" ,
230
+ 0L ,
231
+ "test-monitor" ,
232
+ true ,
233
+ new CronSchedule ("31 * * * *" , ZoneId .of ("Asia/Kolkata" ), Instant .ofEpochSecond (1538164858L )),
234
+ Instant .now (),
235
+ Instant .now (),
236
+ "others_application" ,
237
+ null ,
238
+ List .of (),
239
+ List .of (),
240
+ List .of ("monitor_id1" , "monitor_id2" ),
241
+ DetectorMonitorConfig .getRuleIndex ("others_application" ),
242
+ null ,
243
+ DetectorMonitorConfig .getAlertsIndex ("others_application" ),
244
+ null ,
245
+ null ,
246
+ DetectorMonitorConfig .getFindingsIndex ("others_application" ),
247
+ Collections .emptyMap (),
248
+ Collections .emptyList (),
249
+ false
250
+ );
251
+ GetDetectorResponse getDetectorResponse = new GetDetectorResponse ("detector_id123" , 1L , RestStatus .OK , detector );
252
+
253
+ // Setup getDetector interceptor and return fake GetDetectorResponse by calling listener.onResponse
254
+ doAnswer (invocation -> {
255
+ ActionListener l = invocation .getArgument (2 );
256
+ l .onResponse (getDetectorResponse );
257
+ return null ;
258
+ }).when (client ).execute (eq (GetDetectorAction .INSTANCE ), any (GetDetectorRequest .class ), any (ActionListener .class ));
259
+
260
+ doAnswer (invocation -> {
261
+ ActionListener l = invocation .getArgument (6 );
262
+ l .onFailure (new IllegalArgumentException ("Error getting findings" ));
263
+ return null ;
264
+ }).when (alertssService ).getAlertsByMonitorIds (any (), any (), anyString (), any (Table .class ), anyString (), anyString (), any (ActionListener .class ));
265
+
266
+ // Call getFindingsByDetectorId
267
+ Table table = new Table (
268
+ "asc" ,
269
+ "id" ,
270
+ null ,
271
+ 100 ,
272
+ 0 ,
273
+ null
274
+ );
275
+ alertssService .getAlertsByDetectorId ("detector_id123" , table , "severity_low" , Alert .State .COMPLETED .toString (), new ActionListener <>() {
276
+ @ Override
277
+ public void onResponse (GetAlertsResponse getAlertsResponse ) {
278
+ fail ("this test should've failed" );
279
+ }
280
+
281
+ @ Override
282
+ public void onFailure (Exception e ) {
283
+ assertTrue (e .getMessage ().contains ("Error getting findings" ));
284
+ }
285
+ });
286
+ }
287
+
288
+ public void testGetFindings_getDetectorFailure () {
289
+
290
+ AlertsService alertssService = spy (AlertsService .class );
291
+ Client client = mock (Client .class );
292
+ alertssService .setIndicesAdminClient (client );
293
+
294
+ // Setup getDetector interceptor and return fake expcetion by calling onFailure
295
+ doAnswer (invocation -> {
296
+ ActionListener l = invocation .getArgument (2 );
297
+ l .onFailure (new IllegalArgumentException ("GetDetector failed" ));
298
+ return null ;
299
+ }).when (client ).execute (eq (GetDetectorAction .INSTANCE ), any (GetDetectorRequest .class ), any (ActionListener .class ));
300
+
301
+ // Call getFindingsByDetectorId
302
+ Table table = new Table (
303
+ "asc" ,
304
+ "id" ,
305
+ null ,
306
+ 100 ,
307
+ 0 ,
308
+ null
309
+ );
310
+ alertssService .getAlertsByDetectorId ("detector_id123" , table , "severity_low" , Alert .State .COMPLETED .toString (), new ActionListener <>() {
311
+ @ Override
312
+ public void onResponse (GetAlertsResponse getAlertsResponse ) {
313
+ fail ("this test should've failed" );
314
+ }
315
+
316
+ @ Override
317
+ public void onFailure (Exception e ) {
318
+ assertTrue (e .getMessage ().contains ("GetDetector failed" ));
319
+ }
320
+ });
321
+ }
322
+ }
0 commit comments