Alerting: update rules POST API to validate query and condition only for rules that changed. (#68667)

* replace condition validation with just structural validation
* validate conditions of only new and updated rules
* add integration tests for rule update\delete API

Co-authored-by: George Robinson <george.robinson@grafana.com>
This commit is contained in:
Yuri Tseretyan
2023-06-15 13:33:42 -04:00
committed by GitHub
co-authored by George Robinson
parent 94881597d8
commit b963defa44
10 changed files with 542 additions and 108 deletions
@@ -3,6 +3,7 @@ package api
import (
"context"
"encoding/json"
"errors"
"fmt"
"math/rand"
"net/http"
@@ -518,6 +519,71 @@ func TestVerifyProvisionedRulesNotAffected(t *testing.T) {
})
}
func TestValidateQueries(t *testing.T) {
delta := store.GroupDelta{
New: []*models.AlertRule{
models.AlertRuleGen(func(rule *models.AlertRule) {
rule.Condition = "New"
})(),
},
Update: []store.RuleDelta{
{
Existing: models.AlertRuleGen(func(rule *models.AlertRule) {
rule.Condition = "Update_Existing"
})(),
New: models.AlertRuleGen(func(rule *models.AlertRule) {
rule.Condition = "Update_New"
})(),
Diff: nil,
},
},
Delete: []*models.AlertRule{
models.AlertRuleGen(func(rule *models.AlertRule) {
rule.Condition = "Deleted"
})(),
},
}
t.Run("should validate New and Updated only", func(t *testing.T) {
validator := &recordingConditionValidator{}
err := validateQueries(context.Background(), &delta, validator, nil)
require.NoError(t, err)
for _, condition := range validator.recorded {
if condition.Condition == "New" || condition.Condition == "Update_New" {
continue
}
assert.Failf(t, "validated unexpected condition", "condition '%s' was validated but should not", condition.Condition)
}
})
t.Run("should return rule validate error if fails on new rule", func(t *testing.T) {
validator := &recordingConditionValidator{
hook: func(c models.Condition) error {
if c.Condition == "New" {
return errors.New("test")
}
return nil
},
}
err := validateQueries(context.Background(), &delta, validator, nil)
require.Error(t, err)
require.ErrorIs(t, err, models.ErrAlertRuleFailedValidation)
})
t.Run("should return rule validate error with UID if fails on updated rule", func(t *testing.T) {
validator := &recordingConditionValidator{
hook: func(c models.Condition) error {
if c.Condition == "Update_New" {
return errors.New("test")
}
return nil
},
}
err := validateQueries(context.Background(), &delta, validator, nil)
require.Error(t, err)
require.ErrorIs(t, err, models.ErrAlertRuleFailedValidation)
require.ErrorContains(t, err, delta.Update[0].New.UID)
})
}
func createServiceWithProvenanceStore(store *fakes.RuleStore, provenanceStore provisioning.ProvisioningStore) *RulerSrv {
svc := createService(store)
svc.provenanceStore = provenanceStore