diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/alert_type.ts b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/alert_type.ts index 6015881270405..e3d379f2869b9 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/alert_type.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/alert_type.ts @@ -120,6 +120,7 @@ export interface GeoContainmentParams extends AlertTypeParams { export interface GeoContainmentState extends AlertTypeState { shapesFilters: Record; shapesIdsNamesMap: Record; + prevLocationMap: Record; } export interface GeoContainmentInstanceState extends AlertInstanceState { location: number[]; diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts index 15a6564395c16..754af920b009e 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/geo_containment.ts @@ -16,6 +16,7 @@ import { GeoContainmentInstanceState, GeoContainmentAlertType, GeoContainmentInstanceContext, + GeoContainmentState, } from './alert_type'; export type LatestEntityLocation = GeoContainmentInstanceState; @@ -141,7 +142,7 @@ export const getGeoContainmentExecutor = (log: Logger): GeoContainmentAlertType[ params, alertId, state, - }) { + }): Promise { const { shapesFilters, shapesIdsNamesMap } = state.shapesFilters ? state : await getShapesFilters( @@ -176,8 +177,7 @@ export const getGeoContainmentExecutor = (log: Logger): GeoContainmentAlertType[ } const currLocationMap: Map = transformResults( - // @ts-expect-error body doesn't exist on currentIntervalResults - currentIntervalResults?.body, + currentIntervalResults, params.dateField, params.geoField ); diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/es_sample_response.json b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/es_sample_response.json index 70edbd09aa5a1..b5751e527df4d 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/es_sample_response.json +++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/es_sample_response.json @@ -1,167 +1,246 @@ { - "took" : 2760, - "timed_out" : false, - "_shards" : { - "total" : 1, - "successful" : 1, - "skipped" : 0, - "failed" : 0 - }, - "hits" : { - "total" : { - "value" : 10000, - "relation" : "gte" + "body": { + "took":194, + "timed_out":false, + "_shards":{ + "total":1, + "successful":1, + "skipped":0, + "failed":0 }, - "max_score" : 0.0, - "hits" : [] - }, - "aggregations" : { - "shapes" : { - "meta" : { }, - "buckets" : { - "0DrJu3QB6yyY-xQxv6Ip" : { - "doc_count" : 1047, - "entitySplit" : { - "doc_count_error_upper_bound" : 0, - "sum_other_doc_count" : 957, - "buckets" : [ - { - "key" : "936", - "doc_count" : 9, - "entityHits" : { - "hits" : { - "total" : { - "value" : 9, - "relation" : "eq" - }, - "max_score" : null, - "hits" : [ - { - "_index" : "flight_tracks", - "_id" : "N-ng1XQB6yyY-xQxnGSM", - "_score" : null, - "fields" : { - "@timestamp" : [ - "2020-09-28T18:01:41.190Z" - ], - "location" : [ - "40.62806099653244, -82.8814151789993" - ], - "entity_id" : [ - "936" + "hits":{ + "total":{ + "value":18, + "relation":"eq" + }, + "max_score":null, + "hits":[ + + ] + }, + "aggregations":{ + "shapes":{ + "meta":{ + + }, + "buckets":{ + "k1ATGXkBsFLYN2Tj6AAk":{ + "doc_count":0, + "entitySplit":{ + "doc_count_error_upper_bound":0, + "sum_other_doc_count":0, + "buckets":[ + + ] + } + }, + "kFATGXkBsFLYN2Tj6AAk":{ + "doc_count":2, + "entitySplit":{ + "doc_count_error_upper_bound":0, + "sum_other_doc_count":0, + "buckets":[ + { + "key":"0", + "doc_count":1, + "entityHits":{ + "hits":{ + "total":{ + "value":1, + "relation":"eq" + }, + "max_score":null, + "hits":[ + { + "_index":"tracks", + "_id":"ZVBoGXkBsFLYN2Tj1wmV", + "_score":null, + "fields":{ + "@timestamp":[ + "2021-04-28T16:56:11.923Z" + ], + "location":[ + "40.751759740523994, -73.99018926545978" + ], + "entity_id":[ + "0" + ] + }, + "sort":[ + 1619628971923 ] - }, - "sort" : [ - 1601316101190 - ] - } - ] + } + ] + } } - } - }, - { - "key" : "AAL2019", - "doc_count" : 9, - "entityHits" : { - "hits" : { - "total" : { - "value" : 9, - "relation" : "eq" - }, - "max_score" : null, - "hits" : [ - { - "_index" : "flight_tracks", - "_id" : "iOng1XQB6yyY-xQxnGSM", - "_score" : null, - "fields" : { - "@timestamp" : [ - "2020-09-28T18:01:41.191Z" - ], - "location" : [ - "39.006176185794175, -82.22068064846098" - ], - "entity_id" : [ - "AAL2019" + }, + { + "key":"1", + "doc_count":1, + "entityHits":{ + "hits":{ + "total":{ + "value":1, + "relation":"eq" + }, + "max_score":null, + "hits":[ + { + "_index":"tracks", + "_id":"ZlBoGXkBsFLYN2Tj1wmV", + "_score":null, + "fields":{ + "@timestamp":[ + "2021-04-28T16:56:11.923Z" + ], + "location":[ + "40.75449890457094, -73.99561604484916" + ], + "entity_id":[ + "1" + ] + }, + "sort":[ + 1619628971923 ] - }, - "sort" : [ - 1601316101191 - ] - } - ] + } + ] + } } } - }, - { - "key" : "AAL2323", - "doc_count" : 9, - "entityHits" : { - "hits" : { - "total" : { - "value" : 9, - "relation" : "eq" - }, - "max_score" : null, - "hits" : [ - { - "_index" : "flight_tracks", - "_id" : "n-ng1XQB6yyY-xQxnGSM", - "_score" : null, - "fields" : { - "@timestamp" : [ - "2020-09-28T18:01:41.191Z" - ], - "location" : [ - "41.6677269525826, -84.71324851736426" - ], - "entity_id" : [ - "AAL2323" + ] + } + }, + "kVATGXkBsFLYN2Tj6AAk":{ + "doc_count":0, + "entitySplit":{ + "doc_count_error_upper_bound":0, + "sum_other_doc_count":0, + "buckets":[ + + ] + } + }, + "lVATGXkBsFLYN2Tj6AAk":{ + "doc_count":0, + "entitySplit":{ + "doc_count_error_upper_bound":0, + "sum_other_doc_count":0, + "buckets":[ + + ] + } + }, + "other":{ + "doc_count":15, + "entitySplit":{ + "doc_count_error_upper_bound":0, + "sum_other_doc_count":0, + "buckets":[ + { + "key":"2", + "doc_count":6, + "entityHits":{ + "hits":{ + "total":{ + "value":6, + "relation":"eq" + }, + "max_score":null, + "hits":[ + { + "_index":"tracks", + "_id":"Z1BoGXkBsFLYN2Tj1wmV", + "_score":null, + "fields":{ + "@timestamp":[ + "2021-04-28T16:56:11.923Z" + ], + "location":[ + "40.7667087810114, -73.98662586696446" + ], + "entity_id":[ + "2" + ] + }, + "sort":[ + 1619628971923 ] - }, - "sort" : [ - 1601316101191 - ] - } - ] + } + ] + } } - } - }, - { - "key" : "ABD5250", - "doc_count" : 9, - "entityHits" : { - "hits" : { - "total" : { - "value" : 9, - "relation" : "eq" - }, - "max_score" : null, - "hits" : [ - { - "_index" : "flight_tracks", - "_id" : "GOng1XQB6yyY-xQxnGWM", - "_score" : null, - "fields" : { - "@timestamp" : [ - "2020-09-28T18:01:41.192Z" - ], - "location" : [ - "39.07997465226799, 6.073727197945118" - ], - "entity_id" : [ - "ABD5250" + }, + { + "key":"1", + "doc_count":5, + "entityHits":{ + "hits":{ + "total":{ + "value":5, + "relation":"eq" + }, + "max_score":null, + "hits":[ + { + "_index":"tracks", + "_id":"Y1BoGXkBsFLYN2TjsAlp", + "_score":null, + "fields":{ + "@timestamp":[ + "2021-04-28T16:56:01.896Z" + ], + "location":[ + "40.755913141183555, -73.99459345266223" + ], + "entity_id":[ + "1" + ] + }, + "sort":[ + 1619628961896 + ] + } + ] + } + } + }, + { + "key":"0", + "doc_count":4, + "entityHits":{ + "hits":{ + "total":{ + "value":4, + "relation":"eq" + }, + "max_score":null, + "hits":[ + { + "_index":"tracks", + "_id":"YlBoGXkBsFLYN2TjsAlp", + "_score":null, + "fields":{ + "@timestamp":[ + "2021-04-28T16:56:01.896Z" + ], + "location":[ + "40.7506317878142, -73.98968475870788" + ], + "entity_id":[ + "0" + ] + }, + "sort":[ + 1619628961896 ] - }, - "sort" : [ - 1601316101192 - ] - } - ] + } + ] + } } } - } - ] + ] + } } } } diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/es_sample_response_shapes.json b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/es_sample_response_shapes.json new file mode 100644 index 0000000000000..dfe5a8b7f6ec1 --- /dev/null +++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/es_sample_response_shapes.json @@ -0,0 +1,428 @@ +{ + "body": { + "took":1, + "timed_out":false, + "_shards":{ + "total":1, + "successful":1, + "skipped":0, + "failed":0 + }, + "hits":{ + "total":{ + "value":11, + "relation":"eq" + }, + "max_score":1, + "hits":[ + { + "_index":"manhattan_boundaries", + "_id":"waFXH3kBi9P-_6qn8c8A", + "_score":1, + "_source":{ + "coordinates":{ + "type":"Polygon", + "coordinates":[ + [ + [ + -73.96772861480713, + 40.76060200607076 + ], + [ + -73.96805047988892, + 40.7601631739201 + ], + [ + -73.96732091903687, + 40.7598706175435 + ], + [ + -73.96693468093872, + 40.760471982031845 + ], + [ + -73.96759986877441, + 40.76078078870895 + ], + [ + -73.96772861480713, + 40.76060200607076 + ] + ] + ] + } + } + }, + { + "_index":"manhattan_boundaries", + "_id":"wqFXH3kBi9P-_6qn8c8A", + "_score":1, + "_source":{ + "coordinates":{ + "type":"Polygon", + "coordinates":[ + [ + [ + -73.97641897201538, + 40.75618104606283 + ], + [ + -73.97865056991577, + 40.75371038152863 + ], + [ + -73.97770643234252, + 40.75323899431278 + ], + [ + -73.9788007736206, + 40.75187357799962 + ], + [ + -73.97671937942503, + 40.751060816881505 + ], + [ + -73.97500276565552, + 40.75377540019266 + ], + [ + -73.97639751434325, + 40.75460438258571 + ], + [ + -73.9755392074585, + 40.755985996937774 + ], + [ + -73.97641897201538, + 40.75618104606283 + ] + ] + ] + } + } + }, + { + "_index":"manhattan_boundaries", + "_id":"w6FXH3kBi9P-_6qn8c8A", + "_score":1, + "_source":{ + "coordinates":{ + "type":"Polygon", + "coordinates":[ + [ + [ + -73.98592472076415, + 40.75957805987928 + ], + [ + -73.98695468902588, + 40.75566091379097 + ], + [ + -73.98573160171509, + 40.75553088008716 + ], + [ + -73.98465871810913, + 40.75946428710659 + ], + [ + -73.98592472076415, + 40.75957805987928 + ] + ] + ] + } + } + }, + { + "_index":"manhattan_boundaries", + "_id":"xKFXH3kBi9P-_6qn8c8A", + "_score":1, + "_source":{ + "coordinates":{ + "type":"Polygon", + "coordinates":[ + [ + [ + -73.9894437789917, + 40.75161349552273 + ], + [ + -73.98914337158203, + 40.75206863918968 + ], + [ + -73.99575233459473, + 40.75486445336327 + ], + [ + -73.99819850921631, + 40.75148345390278 + ], + [ + -73.9914608001709, + 40.74881754464601 + ], + [ + -73.9894437789917, + 40.75161349552273 + ] + ] + ] + } + } + }, + { + "_index":"manhattan_boundaries", + "_id":"xaFXH3kBi9P-_6qn8c8A", + "_score":1, + "_source":{ + "coordinates":{ + "type":"Polygon", + "coordinates":[ + [ + [ + -73.96914482116699, + 40.75874913950493 + ], + [ + -73.96946668624878, + 40.758229027325804 + ], + [ + -73.96856546401978, + 40.75793646243674 + ], + [ + -73.96824359893799, + 40.75845657690492 + ], + [ + -73.96914482116699, + 40.75874913950493 + ] + ] + ] + } + } + }, + { + "_index":"manhattan_boundaries", + "_id":"xqFXH3kBi9P-_6qn8c8A", + "_score":1, + "_source":{ + "coordinates":{ + "type":"Polygon", + "coordinates":[ + [ + [ + -73.96953105926514, + 40.7581640130173 + ], + [ + -73.9699387550354, + 40.75749761268889 + ], + [ + -73.96923065185547, + 40.75728631362887 + ], + [ + -73.96862983703613, + 40.757920208794026 + ], + [ + -73.96953105926514, + 40.7581640130173 + ] + ] + ] + } + } + }, + { + "_index":"manhattan_boundaries", + "_id":"x6FXH3kBi9P-_6qn8c8A", + "_score":1, + "_source":{ + "coordinates":{ + "type":"Polygon", + "coordinates":[ + [ + [ + -73.97045373916626, + 40.75679869785023 + ], + [ + -73.97079706192015, + 40.75629482445485 + ], + [ + -73.96998167037964, + 40.756051013376364 + ], + [ + -73.96961688995361, + 40.756554888619675 + ], + [ + -73.97045373916626, + 40.75679869785023 + ] + ] + ] + } + } + }, + { + "_index":"manhattan_boundaries", + "_id":"yKFXH3kBi9P-_6qn8c8A", + "_score":1, + "_source":{ + "coordinates":{ + "type":"Polygon", + "coordinates":[ + [ + [ + -73.98412227630615, + 40.75479943576424 + ], + [ + -73.98498058319092, + 40.75351532515499 + ], + [ + -73.98191213607788, + 40.75219867966512 + ], + [ + -73.9808177947998, + 40.75340154200611 + ], + [ + -73.98412227630615, + 40.75479943576424 + ] + ] + ] + } + } + }, + { + "_index":"manhattan_boundaries", + "_id":"yaFXH3kBi9P-_6qn8c8A", + "_score":1, + "_source":{ + "coordinates":{ + "type":"Polygon", + "coordinates":[ + [ + [ + -73.99725437164307, + 40.74498104863726 + ], + [ + -74.00386333465576, + 40.736136757139285 + ], + [ + -73.99703979492188, + 40.73334015558748 + ], + [ + -73.9897871017456, + 40.74153451605774 + ], + [ + -73.99725437164307, + 40.74498104863726 + ] + ] + ] + } + } + }, + { + "_index":"manhattan_boundaries", + "_id":"yqFXH3kBi9P-_6qn8c8A", + "_score":1, + "_source":{ + "coordinates":{ + "type":"Polygon", + "coordinates":[ + [ + [ + -73.98830652236938, + 40.75075196505171 + ], + [ + -73.9885640144348, + 40.74759834321152 + ], + [ + -73.98761987686157, + 40.747582087041366 + ], + [ + -73.98751258850098, + 40.74816730666263 + ], + [ + -73.98807048797607, + 40.74826484276548 + ], + [ + -73.9875340461731, + 40.75075196505171 + ], + [ + -73.98830652236938, + 40.75075196505171 + ] + ] + ] + } + } + }, + { + "_index":"manhattan_boundaries", + "_id":"y6FXH3kBi9P-_6qn8c8A", + "_score":1, + "_source":{ + "coordinates":{ + "type":"Polygon", + "coordinates":[ + [ + [ + -73.9824914932251, + 40.7467692734681 + ], + [ + -73.98356437683105, + 40.7452411570555 + ], + [ + -73.9813756942749, + 40.74446082874893 + ], + [ + -73.98030281066895, + 40.745696344339564 + ], + [ + -73.9824914932251, + 40.7467692734681 + ] + ] + ] + } + } + } + ] + } + } +} + diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/es_sample_response_with_nesting.json b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/es_sample_response_with_nesting.json index a4b7b6872b341..9baf58465c38e 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/es_sample_response_with_nesting.json +++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/es_sample_response_with_nesting.json @@ -1,167 +1,169 @@ { - "took" : 2760, - "timed_out" : false, - "_shards" : { - "total" : 1, - "successful" : 1, - "skipped" : 0, - "failed" : 0 - }, - "hits" : { - "total" : { - "value" : 10000, - "relation" : "gte" + "body": { + "took" : 2760, + "timed_out" : false, + "_shards" : { + "total" : 1, + "successful" : 1, + "skipped" : 0, + "failed" : 0 }, - "max_score" : 0.0, - "hits" : [] - }, - "aggregations" : { - "shapes" : { - "meta" : { }, - "buckets" : { - "0DrJu3QB6yyY-xQxv6Ip" : { - "doc_count" : 1047, - "entitySplit" : { - "doc_count_error_upper_bound" : 0, - "sum_other_doc_count" : 957, - "buckets" : [ - { - "key" : "936", - "doc_count" : 9, - "entityHits" : { - "hits" : { - "total" : { - "value" : 9, - "relation" : "eq" - }, - "max_score" : null, - "hits" : [ - { - "_index" : "flight_tracks", - "_id" : "N-ng1XQB6yyY-xQxnGSM", - "_score" : null, - "fields" : { - "time_data.@timestamp" : [ - "2020-09-28T18:01:41.190Z" - ], - "geo.coords.location" : [ - "40.62806099653244, -82.8814151789993" - ], - "entity_id" : [ - "936" + "hits" : { + "total" : { + "value" : 10000, + "relation" : "gte" + }, + "max_score" : 0.0, + "hits" : [] + }, + "aggregations" : { + "shapes" : { + "meta" : { }, + "buckets" : { + "0DrJu3QB6yyY-xQxv6Ip" : { + "doc_count" : 1047, + "entitySplit" : { + "doc_count_error_upper_bound" : 0, + "sum_other_doc_count" : 957, + "buckets" : [ + { + "key" : "936", + "doc_count" : 9, + "entityHits" : { + "hits" : { + "total" : { + "value" : 9, + "relation" : "eq" + }, + "max_score" : null, + "hits" : [ + { + "_index" : "flight_tracks", + "_id" : "N-ng1XQB6yyY-xQxnGSM", + "_score" : null, + "fields" : { + "time_data.@timestamp" : [ + "2020-09-28T18:01:41.190Z" + ], + "geo.coords.location" : [ + "40.62806099653244, -82.8814151789993" + ], + "entity_id" : [ + "936" + ] + }, + "sort" : [ + 1601316101190 ] - }, - "sort" : [ - 1601316101190 - ] - } - ] + } + ] + } } - } - }, - { - "key" : "AAL2019", - "doc_count" : 9, - "entityHits" : { - "hits" : { - "total" : { - "value" : 9, - "relation" : "eq" - }, - "max_score" : null, - "hits" : [ - { - "_index" : "flight_tracks", - "_id" : "iOng1XQB6yyY-xQxnGSM", - "_score" : null, - "fields" : { - "time_data.@timestamp" : [ - "2020-09-28T18:01:41.191Z" - ], - "geo.coords.location" : [ - "39.006176185794175, -82.22068064846098" - ], - "entity_id" : [ - "AAL2019" + }, + { + "key" : "AAL2019", + "doc_count" : 9, + "entityHits" : { + "hits" : { + "total" : { + "value" : 9, + "relation" : "eq" + }, + "max_score" : null, + "hits" : [ + { + "_index" : "flight_tracks", + "_id" : "iOng1XQB6yyY-xQxnGSM", + "_score" : null, + "fields" : { + "time_data.@timestamp" : [ + "2020-09-28T18:01:41.191Z" + ], + "geo.coords.location" : [ + "39.006176185794175, -82.22068064846098" + ], + "entity_id" : [ + "AAL2019" + ] + }, + "sort" : [ + 1601316101191 ] - }, - "sort" : [ - 1601316101191 - ] - } - ] + } + ] + } } - } - }, - { - "key" : "AAL2323", - "doc_count" : 9, - "entityHits" : { - "hits" : { - "total" : { - "value" : 9, - "relation" : "eq" - }, - "max_score" : null, - "hits" : [ - { - "_index" : "flight_tracks", - "_id" : "n-ng1XQB6yyY-xQxnGSM", - "_score" : null, - "fields" : { - "time_data.@timestamp" : [ - "2020-09-28T18:01:41.191Z" - ], - "geo.coords.location" : [ - "41.6677269525826, -84.71324851736426" - ], - "entity_id" : [ - "AAL2323" + }, + { + "key" : "AAL2323", + "doc_count" : 9, + "entityHits" : { + "hits" : { + "total" : { + "value" : 9, + "relation" : "eq" + }, + "max_score" : null, + "hits" : [ + { + "_index" : "flight_tracks", + "_id" : "n-ng1XQB6yyY-xQxnGSM", + "_score" : null, + "fields" : { + "time_data.@timestamp" : [ + "2020-09-28T18:01:41.191Z" + ], + "geo.coords.location" : [ + "41.6677269525826, -84.71324851736426" + ], + "entity_id" : [ + "AAL2323" + ] + }, + "sort" : [ + 1601316101191 ] - }, - "sort" : [ - 1601316101191 - ] - } - ] + } + ] + } } - } - }, - { - "key" : "ABD5250", - "doc_count" : 9, - "entityHits" : { - "hits" : { - "total" : { - "value" : 9, - "relation" : "eq" - }, - "max_score" : null, - "hits" : [ - { - "_index" : "flight_tracks", - "_id" : "GOng1XQB6yyY-xQxnGWM", - "_score" : null, - "fields" : { - "time_data.@timestamp" : [ - "2020-09-28T18:01:41.192Z" - ], - "geo.coords.location" : [ - "39.07997465226799, 6.073727197945118" - ], - "entity_id" : [ - "ABD5250" + }, + { + "key" : "ABD5250", + "doc_count" : 9, + "entityHits" : { + "hits" : { + "total" : { + "value" : 9, + "relation" : "eq" + }, + "max_score" : null, + "hits" : [ + { + "_index" : "flight_tracks", + "_id" : "GOng1XQB6yyY-xQxnGWM", + "_score" : null, + "fields" : { + "time_data.@timestamp" : [ + "2020-09-28T18:01:41.192Z" + ], + "geo.coords.location" : [ + "39.07997465226799, 6.073727197945118" + ], + "entity_id" : [ + "ABD5250" + ] + }, + "sort" : [ + 1601316101192 ] - }, - "sort" : [ - 1601316101192 - ] - } - ] + } + ] + } } } - } - ] + ] + } } } } diff --git a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/geo_containment.test.ts b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/geo_containment.test.ts index 429331916ea7d..df2e9df4ba189 100644 --- a/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/geo_containment.test.ts +++ b/x-pack/plugins/stack_alerts/server/alert_types/geo_containment/tests/geo_containment.test.ts @@ -6,67 +6,101 @@ */ import _ from 'lodash'; -import sampleJsonResponse from './es_sample_response.json'; -import sampleJsonResponseWithNesting from './es_sample_response_with_nesting.json'; -import { getActiveEntriesAndGenerateAlerts, transformResults } from '../geo_containment'; +import { loggingSystemMock } from 'src/core/server/mocks'; +import { AlertServicesMock, alertsMock } from '../../../../../alerting/server/mocks'; +import sampleAggsJsonResponse from './es_sample_response.json'; +import sampleShapesJsonResponse from './es_sample_response_shapes.json'; +import sampleAggsJsonResponseWithNesting from './es_sample_response_with_nesting.json'; +import { + getActiveEntriesAndGenerateAlerts, + transformResults, + getGeoContainmentExecutor, +} from '../geo_containment'; import { OTHER_CATEGORY } from '../es_query_builder'; -import { alertsMock } from '../../../../../alerting/server/mocks'; -import { GeoContainmentInstanceContext, GeoContainmentInstanceState } from '../alert_type'; +import { + GeoContainmentInstanceContext, + GeoContainmentInstanceState, + GeoContainmentParams, +} from '../alert_type'; import { SearchResponse } from 'elasticsearch'; +const alertInstanceFactory = (contextKeys: unknown[], testAlertActionArr: unknown[]) => ( + instanceId: string +) => { + const alertInstance = alertsMock.createAlertInstanceFactory< + GeoContainmentInstanceState, + GeoContainmentInstanceContext + >(); + alertInstance.scheduleActions.mockImplementation( + (actionGroupId: string, context?: GeoContainmentInstanceContext) => { + // Check subset of alert for comparison to expected results + // @ts-ignore + const contextSubset = _.pickBy(context, (v, k) => contextKeys.includes(k)); + testAlertActionArr.push({ + actionGroupId, + instanceId, + context: contextSubset, + }); + } + ); + return alertInstance; +}; + describe('geo_containment', () => { describe('transformResults', () => { const dateField = '@timestamp'; const geoField = 'location'; it('should correctly transform expected results', async () => { const transformedResults = transformResults( - (sampleJsonResponse as unknown) as SearchResponse, + // @ts-ignore + (sampleAggsJsonResponse.body as unknown) as SearchResponse, dateField, geoField ); expect(transformedResults).toEqual( new Map([ [ - '936', + '0', [ { - dateInShape: '2020-09-28T18:01:41.190Z', - docId: 'N-ng1XQB6yyY-xQxnGSM', - location: [-82.8814151789993, 40.62806099653244], - shapeLocationId: '0DrJu3QB6yyY-xQxv6Ip', + dateInShape: '2021-04-28T16:56:11.923Z', + docId: 'ZVBoGXkBsFLYN2Tj1wmV', + location: [-73.99018926545978, 40.751759740523994], + shapeLocationId: 'kFATGXkBsFLYN2Tj6AAk', }, - ], - ], - [ - 'AAL2019', - [ { - dateInShape: '2020-09-28T18:01:41.191Z', - docId: 'iOng1XQB6yyY-xQxnGSM', - location: [-82.22068064846098, 39.006176185794175], - shapeLocationId: '0DrJu3QB6yyY-xQxv6Ip', + dateInShape: '2021-04-28T16:56:01.896Z', + docId: 'YlBoGXkBsFLYN2TjsAlp', + location: [-73.98968475870788, 40.7506317878142], + shapeLocationId: 'other', }, ], ], [ - 'AAL2323', + '1', [ { - dateInShape: '2020-09-28T18:01:41.191Z', - docId: 'n-ng1XQB6yyY-xQxnGSM', - location: [-84.71324851736426, 41.6677269525826], - shapeLocationId: '0DrJu3QB6yyY-xQxv6Ip', + dateInShape: '2021-04-28T16:56:11.923Z', + docId: 'ZlBoGXkBsFLYN2Tj1wmV', + location: [-73.99561604484916, 40.75449890457094], + shapeLocationId: 'kFATGXkBsFLYN2Tj6AAk', + }, + { + dateInShape: '2021-04-28T16:56:01.896Z', + docId: 'Y1BoGXkBsFLYN2TjsAlp', + location: [-73.99459345266223, 40.755913141183555], + shapeLocationId: 'other', }, ], ], [ - 'ABD5250', + '2', [ { - dateInShape: '2020-09-28T18:01:41.192Z', - docId: 'GOng1XQB6yyY-xQxnGWM', - location: [6.073727197945118, 39.07997465226799], - shapeLocationId: '0DrJu3QB6yyY-xQxv6Ip', + dateInShape: '2021-04-28T16:56:11.923Z', + docId: 'Z1BoGXkBsFLYN2Tj1wmV', + location: [-73.98662586696446, 40.7667087810114], + shapeLocationId: 'other', }, ], ], @@ -78,7 +112,8 @@ describe('geo_containment', () => { const nestedGeoField = 'geo.coords.location'; it('should correctly transform expected results if fields are nested', async () => { const transformedResults = transformResults( - (sampleJsonResponseWithNesting as unknown) as SearchResponse, + // @ts-ignore + (sampleAggsJsonResponseWithNesting.body as unknown) as SearchResponse, nestedDateField, nestedGeoField ); @@ -181,7 +216,7 @@ describe('geo_containment', () => { ], ]); - const expectedContext = [ + const expectedAlertResults = [ { actionGroupId: 'Tracked entity contained', context: { @@ -213,28 +248,9 @@ describe('geo_containment', () => { instanceId: 'c-789', }, ]; + const contextKeys = Object.keys(expectedAlertResults[0].context); const emptyShapesIdsNamesMap = {}; - const alertInstanceFactory = (instanceId: string) => { - const alertInstance = alertsMock.createAlertInstanceFactory< - GeoContainmentInstanceState, - GeoContainmentInstanceContext - >(); - alertInstance.scheduleActions.mockImplementation( - (actionGroupId: string, context?: GeoContainmentInstanceContext) => { - const contextKeys = Object.keys(expectedContext[0].context); - const contextSubset = _.pickBy(context, (v, k) => contextKeys.includes(k)); - testAlertActionArr.push({ - actionGroupId, - instanceId, - context: contextSubset, - }); - return alertInstance; - } - ); - return alertInstance; - }; - const currentDateTime = new Date(); it('should use currently active entities if no older entity entries', () => { @@ -242,13 +258,14 @@ describe('geo_containment', () => { const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts( emptyPrevLocationMap, currLocationMap, - alertInstanceFactory, + alertInstanceFactory(contextKeys, testAlertActionArr), emptyShapesIdsNamesMap, currentDateTime ); expect(allActiveEntriesMap).toEqual(currLocationMap); - expect(testAlertActionArr).toMatchObject(expectedContext); + expect(testAlertActionArr).toMatchObject(expectedAlertResults); }); + it('should overwrite older identical entity entries', () => { const prevLocationMapWithIdenticalEntityEntry = new Map([ [ @@ -266,13 +283,14 @@ describe('geo_containment', () => { const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts( prevLocationMapWithIdenticalEntityEntry, currLocationMap, - alertInstanceFactory, + alertInstanceFactory(contextKeys, testAlertActionArr), emptyShapesIdsNamesMap, currentDateTime ); expect(allActiveEntriesMap).toEqual(currLocationMap); - expect(testAlertActionArr).toMatchObject(expectedContext); + expect(testAlertActionArr).toMatchObject(expectedAlertResults); }); + it('should preserve older non-identical entity entries', () => { const prevLocationMapWithNonIdenticalEntityEntry = new Map([ [ @@ -287,7 +305,7 @@ describe('geo_containment', () => { ], ], ]); - const expectedContextPlusD = [ + const expectedAlertResultsPlusD = [ { actionGroupId: 'Tracked entity contained', context: { @@ -298,19 +316,19 @@ describe('geo_containment', () => { }, instanceId: 'd-999', }, - ...expectedContext, + ...expectedAlertResults, ]; const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts( prevLocationMapWithNonIdenticalEntityEntry, currLocationMap, - alertInstanceFactory, + alertInstanceFactory(contextKeys, testAlertActionArr), emptyShapesIdsNamesMap, currentDateTime ); expect(allActiveEntriesMap).not.toEqual(currLocationMap); expect(allActiveEntriesMap.has('d')).toBeTruthy(); - expect(testAlertActionArr).toMatchObject(expectedContextPlusD); + expect(testAlertActionArr).toMatchObject(expectedAlertResultsPlusD); }); it('should remove "other" entries and schedule the expected number of actions', () => { @@ -327,12 +345,12 @@ describe('geo_containment', () => { const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts( emptyPrevLocationMap, currLocationMapWithOther, - alertInstanceFactory, + alertInstanceFactory(contextKeys, testAlertActionArr), emptyShapesIdsNamesMap, currentDateTime ); expect(allActiveEntriesMap).toEqual(currLocationMap); - expect(testAlertActionArr).toMatchObject(expectedContext); + expect(testAlertActionArr).toMatchObject(expectedAlertResults); }); it('should generate multiple alerts per entity if found in multiple shapes in interval', () => { @@ -360,7 +378,7 @@ describe('geo_containment', () => { getActiveEntriesAndGenerateAlerts( emptyPrevLocationMap, currLocationMapWithThreeMore, - alertInstanceFactory, + alertInstanceFactory(contextKeys, testAlertActionArr), emptyShapesIdsNamesMap, currentDateTime ); @@ -397,7 +415,7 @@ describe('geo_containment', () => { const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts( emptyPrevLocationMap, currLocationMapWithOther, - alertInstanceFactory, + alertInstanceFactory(contextKeys, testAlertActionArr), emptyShapesIdsNamesMap, currentDateTime ); @@ -429,7 +447,7 @@ describe('geo_containment', () => { const allActiveEntriesMap = getActiveEntriesAndGenerateAlerts( emptyPrevLocationMap, currLocationMapWithOther, - alertInstanceFactory, + alertInstanceFactory(contextKeys, testAlertActionArr), emptyShapesIdsNamesMap, currentDateTime ); @@ -445,4 +463,171 @@ describe('geo_containment', () => { ); }); }); + + describe('getGeoContainmentExecutor', () => { + // Params needed for all tests + const expectedAlertResults = [ + { + actionGroupId: 'Tracked entity contained', + context: { + containingBoundaryId: 'kFATGXkBsFLYN2Tj6AAk', + entityDocumentId: 'ZVBoGXkBsFLYN2Tj1wmV', + entityId: '0', + entityLocation: 'POINT (-73.99018926545978 40.751759740523994)', + }, + instanceId: '0-kFATGXkBsFLYN2Tj6AAk', + }, + { + actionGroupId: 'Tracked entity contained', + context: { + containingBoundaryId: 'kFATGXkBsFLYN2Tj6AAk', + entityDocumentId: 'ZlBoGXkBsFLYN2Tj1wmV', + entityId: '1', + entityLocation: 'POINT (-73.99561604484916 40.75449890457094)', + }, + instanceId: '1-kFATGXkBsFLYN2Tj6AAk', + }, + ]; + const testAlertActionArr: unknown[] = []; + const mockLogger = loggingSystemMock.createLogger(); + const previousStartedAt = new Date('2021-04-27T16:56:11.923Z'); + const startedAt = new Date('2021-04-29T16:56:11.923Z'); + const geoContainmentParams: GeoContainmentParams = { + index: 'testIndex', + indexId: 'testIndexId', + geoField: 'location', + entity: 'testEntity', + dateField: '@timestamp', + boundaryType: 'testBoundaryType', + boundaryIndexTitle: 'testBoundaryIndexTitle', + boundaryIndexId: 'testBoundaryIndexId', + boundaryGeoField: 'testBoundaryGeoField', + }; + const alertId = 'testAlertId'; + const geoContainmentState = { + shapesFilters: { + testShape: 'thisIsAShape', + }, + shapesIdsNamesMap: {}, + prevLocationMap: {}, + }; + + // Boundary test mocks + const boundaryCall = jest.fn(); + const esAggCall = jest.fn(); + const contextKeys = Object.keys(expectedAlertResults[0].context); + const alertServicesWithSearchMock: AlertServicesMock = { + ...alertsMock.createAlertServices(), + // @ts-ignore + alertInstanceFactory: alertInstanceFactory(contextKeys, testAlertActionArr), + scopedClusterClient: { + asCurrentUser: { + // @ts-ignore + search: jest.fn(({ index }: { index: string }) => { + if (index === geoContainmentParams.boundaryIndexTitle) { + boundaryCall(); + return sampleShapesJsonResponse; + } else { + esAggCall(); + return sampleAggsJsonResponse; + } + }), + }, + }, + }; + + beforeEach(() => { + jest.clearAllMocks(); + testAlertActionArr.length = 0; + }); + + it('should query for shapes if state does not contain shapes', async () => { + const executor = await getGeoContainmentExecutor(mockLogger); + const executionResult = await executor({ + previousStartedAt, + startedAt, + // @ts-ignore + services: alertServicesWithSearchMock, + params: geoContainmentParams, + alertId, + // @ts-ignore + state: {}, + }); + if (executionResult && executionResult.shapesFilters) { + expect(boundaryCall.mock.calls.length).toBe(1); + expect(esAggCall.mock.calls.length).toBe(1); + } + expect(testAlertActionArr).toMatchObject(expectedAlertResults); + }); + + it('should not query for shapes if state contains shapes', async () => { + const executor = await getGeoContainmentExecutor(mockLogger); + const executionResult = await executor({ + previousStartedAt, + startedAt, + // @ts-ignore + services: alertServicesWithSearchMock, + params: geoContainmentParams, + alertId, + state: geoContainmentState, + }); + if (executionResult && executionResult.shapesFilters) { + expect(boundaryCall.mock.calls.length).toBe(0); + expect(esAggCall.mock.calls.length).toBe(1); + } + expect(testAlertActionArr).toMatchObject(expectedAlertResults); + }); + + it('should carry through shapes filters in state to next call unmodified', async () => { + const executor = await getGeoContainmentExecutor(mockLogger); + const executionResult = await executor({ + previousStartedAt, + startedAt, + // @ts-ignore + services: alertServicesWithSearchMock, + params: geoContainmentParams, + alertId, + state: geoContainmentState, + }); + if (executionResult && executionResult.shapesFilters) { + expect(executionResult.shapesFilters).toEqual(geoContainmentState.shapesFilters); + } + expect(testAlertActionArr).toMatchObject(expectedAlertResults); + }); + + it('should return previous locations map', async () => { + const expectedPrevLocationMap = { + '0': [ + { + dateInShape: '2021-04-28T16:56:11.923Z', + docId: 'ZVBoGXkBsFLYN2Tj1wmV', + location: [-73.99018926545978, 40.751759740523994], + shapeLocationId: 'kFATGXkBsFLYN2Tj6AAk', + }, + ], + '1': [ + { + dateInShape: '2021-04-28T16:56:11.923Z', + docId: 'ZlBoGXkBsFLYN2Tj1wmV', + location: [-73.99561604484916, 40.75449890457094], + shapeLocationId: 'kFATGXkBsFLYN2Tj6AAk', + }, + ], + }; + const executor = await getGeoContainmentExecutor(mockLogger); + const executionResult = await executor({ + previousStartedAt, + startedAt, + // @ts-ignore + services: alertServicesWithSearchMock, + params: geoContainmentParams, + alertId, + state: geoContainmentState, + }); + if (executionResult && executionResult.prevLocationMap) { + expect(executionResult.prevLocationMap).toEqual(expectedPrevLocationMap); + } + expect(testAlertActionArr).toMatchObject(expectedAlertResults); + }); + }); });