package org.opensearch.commons.alerting
import com.carrotsearch.randomizedtesting.generators.RandomNumbers
import com.carrotsearch.randomizedtesting.generators.RandomStrings
import junit.framework.TestCase.assertNull
import org.apache.hc.core5.http.Header
import org.apache.hc.core5.http.HttpEntity
import org.opensearch.client.Request
import org.opensearch.client.RequestOptions
import org.opensearch.client.Response
import org.opensearch.client.RestClient
import org.opensearch.client.WarningsHandler
import org.opensearch.common.UUIDs
import org.opensearch.common.settings.Settings
import org.opensearch.common.xcontent.LoggingDeprecationHandler
import org.opensearch.common.xcontent.XContentFactory
import org.opensearch.common.xcontent.XContentType
import org.opensearch.commons.alerting.aggregation.bucketselectorext.BucketSelectorExtAggregationBuilder
import org.opensearch.commons.alerting.aggregation.bucketselectorext.BucketSelectorExtFilter
import org.opensearch.commons.alerting.model.ActionExecutionResult
import org.opensearch.commons.alerting.model.AggregationResultBucket
import org.opensearch.commons.alerting.model.Alert
import org.opensearch.commons.alerting.model.BucketLevelTrigger
import org.opensearch.commons.alerting.model.ChainedAlertTrigger
import org.opensearch.commons.alerting.model.ChainedMonitorFindings
import org.opensearch.commons.alerting.model.ClusterMetricsInput
import org.opensearch.commons.alerting.model.CompositeInput
import org.opensearch.commons.alerting.model.Delegate
import org.opensearch.commons.alerting.model.DocLevelMonitorInput
import org.opensearch.commons.alerting.model.DocLevelQuery
import org.opensearch.commons.alerting.model.DocumentLevelTrigger
import org.opensearch.commons.alerting.model.Finding
import org.opensearch.commons.alerting.model.Input
import org.opensearch.commons.alerting.model.IntervalSchedule
import org.opensearch.commons.alerting.model.Monitor
import org.opensearch.commons.alerting.model.NoOpTrigger
import org.opensearch.commons.alerting.model.QueryLevelTrigger
import org.opensearch.commons.alerting.model.Schedule
import org.opensearch.commons.alerting.model.SearchInput
import org.opensearch.commons.alerting.model.Sequence
import org.opensearch.commons.alerting.model.Trigger
import org.opensearch.commons.alerting.model.Workflow
import org.opensearch.commons.alerting.model.WorkflowInput
import org.opensearch.commons.alerting.model.action.Action
import org.opensearch.commons.alerting.model.action.ActionExecutionPolicy
import org.opensearch.commons.alerting.model.action.ActionExecutionScope
import org.opensearch.commons.alerting.model.action.AlertCategory
import org.opensearch.commons.alerting.model.action.PerAlertActionScope
import org.opensearch.commons.alerting.model.action.PerExecutionActionScope
import org.opensearch.commons.alerting.model.action.Throttle
import org.opensearch.commons.alerting.util.string
import org.opensearch.commons.authuser.User
import org.opensearch.core.xcontent.NamedXContentRegistry
import org.opensearch.core.xcontent.ToXContent
import org.opensearch.core.xcontent.XContentBuilder
import org.opensearch.core.xcontent.XContentParser
import org.opensearch.index.query.QueryBuilders
import org.opensearch.script.Script
import org.opensearch.script.ScriptType
import org.opensearch.search.SearchModule
import org.opensearch.search.aggregations.bucket.terms.IncludeExclude
import org.opensearch.search.aggregations.bucket.terms.TermsAggregationBuilder
import org.opensearch.search.builder.SearchSourceBuilder
import java.time.Instant
import java.time.temporal.ChronoUnit
import java.util.Random
import java.util.UUID
const val ALL_ACCESS_ROLE = "all_access"
fun randomQueryLevelMonitor(
name: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
user: User = randomUser(),
inputs: List = listOf(SearchInput(emptyList(), SearchSourceBuilder().query(QueryBuilders.matchAllQuery()))),
schedule: Schedule = IntervalSchedule(interval = 5, unit = ChronoUnit.MINUTES),
enabled: Boolean = Random().nextBoolean(),
triggers: List = (1..RandomNumbers.randomIntBetween(Random(), 0, 10)).map { randomQueryLevelTrigger() },
enabledTime: Instant? = if (enabled) Instant.now().truncatedTo(ChronoUnit.MILLIS) else null,
lastUpdateTime: Instant = Instant.now().truncatedTo(ChronoUnit.MILLIS),
withMetadata: Boolean = false
): Monitor {
return Monitor(
name = name, monitorType = Monitor.MonitorType.QUERY_LEVEL_MONITOR, enabled = enabled, inputs = inputs,
schedule = schedule, triggers = triggers, enabledTime = enabledTime, lastUpdateTime = lastUpdateTime, user = user,
uiMetadata = if (withMetadata) mapOf("foo" to "bar") else mapOf()
)
}
// Monitor of older versions without security.
fun randomQueryLevelMonitorWithoutUser(
name: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
inputs: List = listOf(SearchInput(emptyList(), SearchSourceBuilder().query(QueryBuilders.matchAllQuery()))),
schedule: Schedule = IntervalSchedule(interval = 5, unit = ChronoUnit.MINUTES),
enabled: Boolean = Random().nextBoolean(),
triggers: List = (1..RandomNumbers.randomIntBetween(Random(), 0, 10)).map { randomQueryLevelTrigger() },
enabledTime: Instant? = if (enabled) Instant.now().truncatedTo(ChronoUnit.MILLIS) else null,
lastUpdateTime: Instant = Instant.now().truncatedTo(ChronoUnit.MILLIS),
withMetadata: Boolean = false
): Monitor {
return Monitor(
name = name, monitorType = Monitor.MonitorType.QUERY_LEVEL_MONITOR, enabled = enabled, inputs = inputs,
schedule = schedule, triggers = triggers, enabledTime = enabledTime, lastUpdateTime = lastUpdateTime, user = null,
uiMetadata = if (withMetadata) mapOf("foo" to "bar") else mapOf()
)
}
fun randomBucketLevelMonitor(
name: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
user: User = randomUser(),
inputs: List = listOf(
SearchInput(
emptyList(),
SearchSourceBuilder().query(QueryBuilders.matchAllQuery())
.aggregation(TermsAggregationBuilder("test_agg").field("test_field"))
)
),
schedule: Schedule = IntervalSchedule(interval = 5, unit = ChronoUnit.MINUTES),
enabled: Boolean = Random().nextBoolean(),
triggers: List = (1..RandomNumbers.randomIntBetween(Random(), 0, 10)).map { randomBucketLevelTrigger() },
enabledTime: Instant? = if (enabled) Instant.now().truncatedTo(ChronoUnit.MILLIS) else null,
lastUpdateTime: Instant = Instant.now().truncatedTo(ChronoUnit.MILLIS),
withMetadata: Boolean = false
): Monitor {
return Monitor(
name = name, monitorType = Monitor.MonitorType.BUCKET_LEVEL_MONITOR, enabled = enabled, inputs = inputs,
schedule = schedule, triggers = triggers, enabledTime = enabledTime, lastUpdateTime = lastUpdateTime, user = user,
uiMetadata = if (withMetadata) mapOf("foo" to "bar") else mapOf()
)
}
fun randomClusterMetricsMonitor(
name: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
user: User = randomUser(),
inputs: List = listOf(randomClusterMetricsInput()),
schedule: Schedule = IntervalSchedule(interval = 5, unit = ChronoUnit.MINUTES),
enabled: Boolean = Random().nextBoolean(),
triggers: List = (1..RandomNumbers.randomIntBetween(Random(), 0, 10)).map { randomQueryLevelTrigger() },
enabledTime: Instant? = if (enabled) Instant.now().truncatedTo(ChronoUnit.MILLIS) else null,
lastUpdateTime: Instant = Instant.now().truncatedTo(ChronoUnit.MILLIS),
withMetadata: Boolean = false
): Monitor {
return Monitor(
name = name, monitorType = Monitor.MonitorType.CLUSTER_METRICS_MONITOR, enabled = enabled, inputs = inputs,
schedule = schedule, triggers = triggers, enabledTime = enabledTime, lastUpdateTime = lastUpdateTime, user = user,
uiMetadata = if (withMetadata) mapOf("foo" to "bar") else mapOf()
)
}
fun randomDocumentLevelMonitor(
name: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
user: User? = randomUser(),
inputs: List = listOf(DocLevelMonitorInput("description", listOf("index"), emptyList())),
schedule: Schedule = IntervalSchedule(interval = 5, unit = ChronoUnit.MINUTES),
enabled: Boolean = Random().nextBoolean(),
triggers: List = (1..RandomNumbers.randomIntBetween(Random(), 0, 10)).map { randomQueryLevelTrigger() },
enabledTime: Instant? = if (enabled) Instant.now().truncatedTo(ChronoUnit.MILLIS) else null,
lastUpdateTime: Instant = Instant.now().truncatedTo(ChronoUnit.MILLIS),
withMetadata: Boolean = false
): Monitor {
return Monitor(
name = name, monitorType = Monitor.MonitorType.DOC_LEVEL_MONITOR, enabled = enabled, inputs = inputs,
schedule = schedule, triggers = triggers, enabledTime = enabledTime, lastUpdateTime = lastUpdateTime, user = user,
uiMetadata = if (withMetadata) mapOf("foo" to "bar") else mapOf()
)
}
fun randomWorkflow(
name: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
user: User? = randomUser(),
monitorIds: List? = null,
schedule: Schedule = IntervalSchedule(interval = 5, unit = ChronoUnit.MINUTES),
enabled: Boolean = Random().nextBoolean(),
enabledTime: Instant? = if (enabled) Instant.now().truncatedTo(ChronoUnit.MILLIS) else null,
lastUpdateTime: Instant = Instant.now().truncatedTo(ChronoUnit.MILLIS),
triggers: List = listOf(randomChainedAlertTrigger()),
auditDelegateMonitorAlerts: Boolean? = true
): Workflow {
val delegates = mutableListOf()
if (!monitorIds.isNullOrEmpty()) {
delegates.add(Delegate(1, monitorIds[0]))
for (i in 1 until monitorIds.size) {
// Order of monitors in workflow will be the same like forwarded meaning that the first monitorId will be used as second monitor chained finding
delegates.add(Delegate(i + 1, monitorIds [i], ChainedMonitorFindings(monitorIds[i - 1])))
}
}
var input = listOf(CompositeInput(Sequence(delegates)))
if (input == null) {
input = listOf(
CompositeInput(
Sequence(
listOf(Delegate(1, "delegate1"))
)
)
)
}
return Workflow(
name = name, workflowType = Workflow.WorkflowType.COMPOSITE, enabled = enabled, inputs = input,
schedule = schedule, enabledTime = enabledTime, lastUpdateTime = lastUpdateTime, user = user,
triggers = triggers, auditDelegateMonitorAlerts = auditDelegateMonitorAlerts
)
}
fun randomWorkflowWithDelegates(
name: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
user: User? = randomUser(),
input: List,
schedule: Schedule = IntervalSchedule(interval = 5, unit = ChronoUnit.MINUTES),
enabled: Boolean = Random().nextBoolean(),
enabledTime: Instant? = if (enabled) Instant.now().truncatedTo(ChronoUnit.MILLIS) else null,
lastUpdateTime: Instant = Instant.now().truncatedTo(ChronoUnit.MILLIS),
triggers: List = (1..RandomNumbers.randomIntBetween(Random(), 0, 10)).map { randomChainedAlertTrigger() },
): Workflow {
return Workflow(
name = name, workflowType = Workflow.WorkflowType.COMPOSITE, enabled = enabled, inputs = input,
schedule = schedule, enabledTime = enabledTime, lastUpdateTime = lastUpdateTime, user = user,
triggers = triggers
)
}
fun Workflow.toJsonStringWithUser(): String {
val builder = XContentFactory.jsonBuilder()
return this.toXContentWithUser(builder, ToXContent.EMPTY_PARAMS).string()
}
fun randomSequence(
delegates: List = listOf(randomDelegate())
): Sequence {
return Sequence(delegates)
}
fun randomDelegate(
order: Int = 1,
monitorId: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
chainedMonitorFindings: ChainedMonitorFindings? = null
): Delegate {
return Delegate(order, monitorId, chainedMonitorFindings)
}
fun randomQueryLevelTrigger(
id: String = UUIDs.base64UUID(),
name: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
severity: String = "1",
condition: Script = randomScript(),
actions: List = mutableListOf(),
destinationId: String = ""
): QueryLevelTrigger {
return QueryLevelTrigger(
id = id,
name = name,
severity = severity,
condition = condition,
actions = if (actions.isEmpty()) (0..RandomNumbers.randomIntBetween(Random(), 0, 10)).map { randomAction(destinationId = destinationId) } else actions
)
}
fun randomBucketLevelTrigger(
id: String = UUIDs.base64UUID(),
name: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
severity: String = "1",
bucketSelector: BucketSelectorExtAggregationBuilder = randomBucketSelectorExtAggregationBuilder(name = id),
actions: List = mutableListOf(),
destinationId: String = ""
): BucketLevelTrigger {
return BucketLevelTrigger(
id = id,
name = name,
severity = severity,
bucketSelector = bucketSelector,
actions = if (actions.isEmpty()) randomActionsForBucketLevelTrigger(destinationId = destinationId) else actions
)
}
fun randomActionsForBucketLevelTrigger(min: Int = 0, max: Int = 10, destinationId: String = ""): List =
(min..RandomNumbers.randomIntBetween(Random(), 0, max)).map { randomActionWithPolicy(destinationId = destinationId) }
fun randomDocumentLevelTrigger(
id: String = UUIDs.base64UUID(),
name: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
severity: String = "1",
condition: Script = randomScript(),
actions: List = mutableListOf(),
destinationId: String = ""
): DocumentLevelTrigger {
return DocumentLevelTrigger(
id = id,
name = name,
severity = severity,
condition = condition,
actions = if (actions.isEmpty() && destinationId.isNotBlank())
(0..RandomNumbers.randomIntBetween(Random(), 0, 10)).map { randomAction(destinationId = destinationId) }
else actions
)
}
fun randomChainedAlertTrigger(
id: String = UUIDs.base64UUID(),
name: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
severity: String = "1",
condition: Script = randomScript(),
actions: List = mutableListOf(),
destinationId: String = ""
): ChainedAlertTrigger {
return ChainedAlertTrigger(
id = id,
name = name,
severity = severity,
condition = condition,
actions = if (actions.isEmpty() && destinationId.isNotBlank()) {
(0..RandomNumbers.randomIntBetween(Random(), 0, 10)).map { randomAction(destinationId = destinationId) }
} else actions
)
}
fun randomBucketSelectorExtAggregationBuilder(
name: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
bucketsPathsMap: MutableMap = mutableMapOf("avg" to "10"),
script: Script = randomBucketSelectorScript(params = bucketsPathsMap),
parentBucketPath: String = "testPath",
filter: BucketSelectorExtFilter = BucketSelectorExtFilter(IncludeExclude("foo*", "bar*"))
): BucketSelectorExtAggregationBuilder {
return BucketSelectorExtAggregationBuilder(name, bucketsPathsMap, script, parentBucketPath, filter)
}
fun randomBucketSelectorScript(
idOrCode: String = "params.avg >= 0",
params: Map = mutableMapOf("avg" to "10")
): Script {
return Script(Script.DEFAULT_SCRIPT_TYPE, Script.DEFAULT_SCRIPT_LANG, idOrCode, emptyMap(), params)
}
fun randomScript(source: String = "return " + Random().nextBoolean().toString()): Script = Script(source)
fun randomTemplateScript(
source: String,
params: Map = emptyMap()
): Script = Script(ScriptType.INLINE, Script.DEFAULT_TEMPLATE_LANG, source, params)
fun randomAction(
name: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
template: Script = randomTemplateScript("Hello World"),
destinationId: String = "",
throttleEnabled: Boolean = false,
throttle: Throttle = randomThrottle()
) = Action(name, destinationId, template, template, throttleEnabled, throttle, actionExecutionPolicy = null)
fun randomActionWithPolicy(
name: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
template: Script = randomTemplateScript("Hello World"),
destinationId: String = "",
throttleEnabled: Boolean = false,
throttle: Throttle = randomThrottle(),
actionExecutionPolicy: ActionExecutionPolicy? = randomActionExecutionPolicy()
): Action {
return if (actionExecutionPolicy?.actionExecutionScope is PerExecutionActionScope) {
// Return null for throttle when using PerExecutionActionScope since throttling is currently not supported for it
Action(name, destinationId, template, template, throttleEnabled, null, actionExecutionPolicy = actionExecutionPolicy)
} else {
Action(name, destinationId, template, template, throttleEnabled, throttle, actionExecutionPolicy = actionExecutionPolicy)
}
}
fun randomThrottle(
value: Int = RandomNumbers.randomIntBetween(Random(), 60, 120),
unit: ChronoUnit = ChronoUnit.MINUTES
) = Throttle(value, unit)
fun randomActionExecutionPolicy(
actionExecutionScope: ActionExecutionScope = randomActionExecutionScope()
) = ActionExecutionPolicy(actionExecutionScope)
fun randomActionExecutionScope(): ActionExecutionScope {
return if (Random().nextBoolean()) {
val alertCategories = AlertCategory.values()
PerAlertActionScope(actionableAlerts = (1..RandomNumbers.randomIntBetween(Random(), 0, alertCategories.size)).map { alertCategories[it - 1] }.toSet())
} else {
PerExecutionActionScope()
}
}
fun randomDocLevelQuery(
id: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
query: String = RandomStrings.randomAsciiLettersOfLength(Random(), 10),
name: String = "${RandomNumbers.randomIntBetween(Random(), 0, 5)}",
tags: List = mutableListOf(0..RandomNumbers.randomIntBetween(Random(), 0, 10)).map { RandomStrings.randomAsciiLettersOfLength(Random(), 10) }
): DocLevelQuery {
return DocLevelQuery(id = id, query = query, name = name, tags = tags)
}
fun randomDocLevelMonitorInput(
description: String = RandomStrings.randomAsciiLettersOfLength(Random(), RandomNumbers.randomIntBetween(Random(), 0, 10)),
indices: List = listOf(1..RandomNumbers.randomIntBetween(Random(), 0, 10)).map { RandomStrings.randomAsciiLettersOfLength(Random(), 10) },
queries: List = listOf(1..RandomNumbers.randomIntBetween(Random(), 0, 10)).map { randomDocLevelQuery() }
): DocLevelMonitorInput {
return DocLevelMonitorInput(description = description, indices = indices, queries = queries)
}
fun randomClusterMetricsInput(
path: String = ClusterMetricsInput.ClusterMetricType.values()
.filter { it.defaultPath.isNotBlank() && !it.requiresPathParams }
.random()
.defaultPath,
pathParams: String = "",
url: String = ""
): ClusterMetricsInput {
return ClusterMetricsInput(path, pathParams, url)
}
fun Workflow.toJsonString(): String {
val builder = XContentFactory.jsonBuilder()
return this.toXContentWithUser(builder, ToXContent.EMPTY_PARAMS).string()
}
fun Monitor.toJsonString(): String {
val builder = XContentFactory.jsonBuilder()
return this.toXContent(builder, ToXContent.EMPTY_PARAMS).string()
}
fun Monitor.toJsonStringWithUser(): String {
val builder = XContentFactory.jsonBuilder()
return this.toXContentWithUser(builder, ToXContent.EMPTY_PARAMS).string()
}
fun randomUser(): User {
return User(
RandomStrings.randomAsciiLettersOfLength(Random(), 10),
listOf(
RandomStrings.randomAsciiLettersOfLength(Random(), 10),
RandomStrings.randomAsciiLettersOfLength(Random(), 10)
),
listOf(RandomStrings.randomAsciiLettersOfLength(Random(), 10), ALL_ACCESS_ROLE),
listOf("test_attr=test")
)
}
fun randomUserEmpty(): User {
return User("", listOf(), listOf(), listOf())
}
/**
* Wrapper for [RestClient.performRequest] which was deprecated in ES 6.5 and is used in tests. This provides
* a single place to suppress deprecation warnings. This will probably need further work when the API is removed entirely
* but that's an exercise for another day.
*/
@Suppress("DEPRECATION")
fun RestClient.makeRequest(
method: String,
endpoint: String,
params: Map = emptyMap(),
entity: HttpEntity? = null,
vararg headers: Header
): Response {
val request = Request(method, endpoint)
// TODO: remove PERMISSIVE option after moving system index access to REST API call
val options = RequestOptions.DEFAULT.toBuilder()
options.setWarningsHandler(WarningsHandler.PERMISSIVE)
headers.forEach { options.addHeader(it.name, it.value) }
request.options = options.build()
params.forEach { request.addParameter(it.key, it.value) }
if (entity != null) {
request.entity = entity
}
return performRequest(request)
}
/**
* Wrapper for [RestClient.performRequest] which was deprecated in ES 6.5 and is used in tests. This provides
* a single place to suppress deprecation warnings. This will probably need further work when the API is removed entirely
* but that's an exercise for another day.
*/
@Suppress("DEPRECATION")
fun RestClient.makeRequest(
method: String,
endpoint: String,
entity: HttpEntity? = null,
vararg headers: Header
): Response {
val request = Request(method, endpoint)
val options = RequestOptions.DEFAULT.toBuilder()
// TODO: remove PERMISSIVE option after moving system index access to REST API call
options.setWarningsHandler(WarningsHandler.PERMISSIVE)
headers.forEach { options.addHeader(it.name, it.value) }
request.options = options.build()
if (entity != null) {
request.entity = entity
}
return performRequest(request)
}
fun builder(): XContentBuilder {
return XContentBuilder.builder(XContentType.JSON.xContent())
}
fun parser(xc: String): XContentParser {
val parser = XContentType.JSON.xContent().createParser(xContentRegistry(), LoggingDeprecationHandler.INSTANCE, xc)
parser.nextToken()
return parser
}
fun xContentRegistry(): NamedXContentRegistry {
return NamedXContentRegistry(
listOf(
SearchInput.XCONTENT_REGISTRY,
DocLevelMonitorInput.XCONTENT_REGISTRY,
QueryLevelTrigger.XCONTENT_REGISTRY,
BucketLevelTrigger.XCONTENT_REGISTRY,
DocumentLevelTrigger.XCONTENT_REGISTRY,
ChainedAlertTrigger.XCONTENT_REGISTRY,
NoOpTrigger.XCONTENT_REGISTRY
) + SearchModule(Settings.EMPTY, emptyList()).namedXContents
)
}
fun assertUserNull(map: Map) {
val user = map["user"]
assertNull("User is not null", user)
}
fun assertUserNull(monitor: Monitor) {
assertNull("User is not null", monitor.user)
}
fun randomAlert(monitor: Monitor = randomQueryLevelMonitor()): Alert {
val trigger = randomQueryLevelTrigger()
val actionExecutionResults = mutableListOf(randomActionExecutionResult(), randomActionExecutionResult())
return Alert(
monitor, trigger, Instant.now().truncatedTo(ChronoUnit.MILLIS), null,
actionExecutionResults = actionExecutionResults
)
}
fun randomChainedAlert(
workflow: Workflow = randomWorkflow(),
trigger: ChainedAlertTrigger = randomChainedAlertTrigger(),
): Alert {
return Alert(
startTime = Instant.now(),
lastNotificationTime = Instant.now(),
state = Alert.State.ACTIVE,
errorMessage = null,
executionId = UUID.randomUUID().toString(),
chainedAlertTrigger = trigger,
workflow = workflow,
associatedAlertIds = listOf("a1")
)
}
fun randomActionExecutionResult(
actionId: String = UUIDs.base64UUID(),
lastExecutionTime: Instant = Instant.now().truncatedTo(ChronoUnit.MILLIS),
throttledCount: Int = 0
) = ActionExecutionResult(actionId, lastExecutionTime, throttledCount)
fun randomAlertWithAggregationResultBucket(monitor: Monitor = randomBucketLevelMonitor()): Alert {
val trigger = randomBucketLevelTrigger()
val actionExecutionResults = mutableListOf(randomActionExecutionResult(), randomActionExecutionResult())
return Alert(
monitor, trigger, Instant.now().truncatedTo(ChronoUnit.MILLIS), null,
actionExecutionResults = actionExecutionResults,
aggregationResultBucket = AggregationResultBucket(
"parent_bucket_path_1",
listOf("bucket_key_1"),
mapOf("k1" to "val1", "k2" to "val2")
)
)
}
fun randomFinding(
id: String = UUIDs.base64UUID(),
relatedDocIds: List = listOf(UUIDs.base64UUID()),
monitorId: String = UUIDs.base64UUID(),
monitorName: String = UUIDs.base64UUID(),
index: String = UUIDs.base64UUID(),
docLevelQueries: List = listOf(randomDocLevelQuery()),
timestamp: Instant = Instant.now()
): Finding {
return Finding(
id = id,
relatedDocIds = relatedDocIds,
monitorId = monitorId,
monitorName = monitorName,
index = index,
docLevelQueries = docLevelQueries,
timestamp = timestamp
)
}