alerting(api): cross-field validation for PER_EXCHANGE + empty-targets guard

PER_EXCHANGE rules: 400 if reNotifyMinutes != 0 or forDurationSeconds != 0.
Any rule: 400 if webhooks + targets are both empty (never notifies anyone).

Turns green: AlertRuleControllerIT#createPerExchangeRule_with*NonZero_returns400,
AlertRuleControllerIT#createAnyRule_withEmptyWebhooksAndTargets_returns400.
This commit is contained in:
hsiegeln
2026-04-22 17:31:11 +02:00
parent 377968eb53
commit 0f6bafae8e
2 changed files with 38 additions and 2 deletions

View File

@@ -164,7 +164,8 @@ class AlertRuleControllerIT extends AbstractPostgresIT {
{"name":"valid-attr","severity":"WARNING","conditionKind":"EXCHANGE_MATCH",
"condition":{"kind":"EXCHANGE_MATCH","scope":{},
"filter":{"status":"FAILED","attributes":{"order.type":"x"}},
"fireMode":"PER_EXCHANGE"}}
"fireMode":"PER_EXCHANGE"},
"targets":[{"kind":"USER","targetId":"test-operator"}]}
""";
ResponseEntity<String> resp = restTemplate.exchange(
@@ -324,10 +325,12 @@ class AlertRuleControllerIT extends AbstractPostgresIT {
}
private static String routeMetricRuleBody(String name) {
// Includes a USER target so the rule passes the "at least one webhook or target" guard.
return """
{"name":"%s","severity":"WARNING","conditionKind":"ROUTE_METRIC",
"condition":{"kind":"ROUTE_METRIC","scope":{},
"metric":"ERROR_RATE","comparator":"GT","threshold":0.05,"windowSeconds":60}}
"metric":"ERROR_RATE","comparator":"GT","threshold":0.05,"windowSeconds":60},
"targets":[{"kind":"USER","targetId":"test-operator"}]}
""".formatted(name);
}