mirror of
https://github.com/nezhahq/nezha.git
synced 2025-03-12 08:48:12 -04:00
fix: ignore the duration of out-of-bound rules (#1019)
Some checks are pending
CodeQL / Analyze (go) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
Contributors / contributors (push) Waiting to run
Sync / sync-to-jihulab (push) Waiting to run
Run Tests / tests (macos) (push) Waiting to run
Run Tests / tests (ubuntu) (push) Waiting to run
Run Tests / tests (windows) (push) Waiting to run
Some checks are pending
CodeQL / Analyze (go) (push) Waiting to run
CodeQL / Analyze (javascript) (push) Waiting to run
Contributors / contributors (push) Waiting to run
Sync / sync-to-jihulab (push) Waiting to run
Run Tests / tests (macos) (push) Waiting to run
Run Tests / tests (ubuntu) (push) Waiting to run
Run Tests / tests (windows) (push) Waiting to run
This commit is contained in:
parent
731bc9521a
commit
79884c781a
@ -109,12 +109,12 @@ func (r *AlertRule) Check(points [][]bool) (int, bool) {
|
|||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
// 常规报警
|
// 常规报警
|
||||||
if duration > durations[ruleIndex] {
|
|
||||||
durations[ruleIndex] = duration
|
|
||||||
}
|
|
||||||
if hasPassedRule = boundCheck(len(points), duration, hasPassedRule); hasPassedRule {
|
if hasPassedRule = boundCheck(len(points), duration, hasPassedRule); hasPassedRule {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if duration > durations[ruleIndex] {
|
||||||
|
durations[ruleIndex] = duration
|
||||||
|
}
|
||||||
total, fail := duration, 0
|
total, fail := duration, 0
|
||||||
for timeTick := len(points) - duration; timeTick < len(points); timeTick++ {
|
for timeTick := len(points) - duration; timeTick < len(points); timeTick++ {
|
||||||
if !points[timeTick][ruleIndex] {
|
if !points[timeTick][ruleIndex] {
|
||||||
|
310
model/alertrule_test.go
Normal file
310
model/alertrule_test.go
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
package model
|
||||||
|
|
||||||
|
import (
|
||||||
|
"slices"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type arSt struct {
|
||||||
|
msg string
|
||||||
|
rule *AlertRule
|
||||||
|
points [][]bool
|
||||||
|
expD int
|
||||||
|
exp bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCycleRules(t *testing.T) {
|
||||||
|
cases := []arSt{
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Type: "_cycle",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "CyclePass",
|
||||||
|
points: [][]bool{{false}, {true}},
|
||||||
|
expD: 1,
|
||||||
|
exp: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Type: "_cycle",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "CycleFail",
|
||||||
|
points: [][]bool{{true}, {false}},
|
||||||
|
expD: 1,
|
||||||
|
exp: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
d, passed := c.rule.Check(c.points)
|
||||||
|
assertEq(t, c.msg, c.expD, d)
|
||||||
|
assertEq(t, c.msg, c.exp, passed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOfflineRules(t *testing.T) {
|
||||||
|
cases := []arSt{
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Type: "offline",
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "OfflineLast",
|
||||||
|
points: append([][]bool{{true}}, repeat([]bool{false}, 9)...),
|
||||||
|
expD: 10,
|
||||||
|
exp: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Type: "offline",
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "OfflineMiddle",
|
||||||
|
points: mod(repeat([]bool{false}, 10), true, 5),
|
||||||
|
expD: 5,
|
||||||
|
exp: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Type: "offline",
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "OfflineFirst",
|
||||||
|
points: mod(repeat([]bool{false}, 10), true, 9),
|
||||||
|
expD: 1,
|
||||||
|
exp: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Type: "offline",
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "OfflineBoundCheck",
|
||||||
|
points: repeat([]bool{false}, 9),
|
||||||
|
expD: 0,
|
||||||
|
exp: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
d, passed := c.rule.Check(c.points)
|
||||||
|
assertEq(t, c.msg, c.expD, d)
|
||||||
|
assertEq(t, c.msg, c.exp, passed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGeneralRules(t *testing.T) {
|
||||||
|
cases := []arSt{
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "GeneralFail",
|
||||||
|
points: repeat([]bool{false}, 10),
|
||||||
|
expD: 10,
|
||||||
|
exp: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "GeneralFail80%",
|
||||||
|
points: slices.Concat(repeat([]bool{false}, 8), repeat([]bool{true}, 2)),
|
||||||
|
expD: 10,
|
||||||
|
exp: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "GeneralPass30%",
|
||||||
|
points: slices.Concat(repeat([]bool{false}, 7), repeat([]bool{true}, 3)),
|
||||||
|
expD: 10,
|
||||||
|
exp: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "GeneralPass",
|
||||||
|
points: slices.Concat(repeat([]bool{false}, 4), repeat([]bool{true}, 6)),
|
||||||
|
expD: 10,
|
||||||
|
exp: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "GeneralBoundCheck",
|
||||||
|
points: repeat([]bool{false}, 9),
|
||||||
|
expD: 0,
|
||||||
|
exp: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
d, passed := c.rule.Check(c.points)
|
||||||
|
assertEq(t, c.msg, c.expD, d)
|
||||||
|
assertEq(t, c.msg, c.exp, passed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCombinedRules(t *testing.T) {
|
||||||
|
cases := []arSt{
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Type: "offline",
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "OfflineGeneralOfflinePass",
|
||||||
|
points: slices.Concat(repeat([]bool{false, true}, 2), repeat([]bool{true, false}, 8)),
|
||||||
|
expD: 1,
|
||||||
|
exp: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Type: "offline",
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "OfflineGeneralOfflineFail",
|
||||||
|
points: slices.Concat(repeat([]bool{false, false}, 2), repeat([]bool{false, true}, 8)),
|
||||||
|
expD: 10,
|
||||||
|
exp: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: "offline",
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "GeneralOffline",
|
||||||
|
points: slices.Concat(repeat([]bool{false, true}, 2), repeat([]bool{true, false}, 8)),
|
||||||
|
expD: 10,
|
||||||
|
exp: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Duration: 30,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "GeneralGeneral",
|
||||||
|
points: slices.Concat(repeat([]bool{false, true}, 2), repeat([]bool{false, false}, 28)),
|
||||||
|
expD: 30,
|
||||||
|
exp: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
rule: &AlertRule{
|
||||||
|
Rules: []*Rule{
|
||||||
|
{
|
||||||
|
Duration: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Duration: 30,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
msg: "CombinedBoundCheck",
|
||||||
|
points: slices.Concat(repeat([]bool{false, true}, 2), repeat([]bool{false, false}, 27)),
|
||||||
|
expD: 10,
|
||||||
|
exp: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
d, passed := c.rule.Check(c.points)
|
||||||
|
assertEq(t, c.msg, c.expD, d)
|
||||||
|
assertEq(t, c.msg, c.exp, passed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func repeat[S ~[]E, E any](x S, count int) []S {
|
||||||
|
var slices []S
|
||||||
|
for range count {
|
||||||
|
tmp := make([]E, len(x))
|
||||||
|
copy(tmp, x)
|
||||||
|
slices = append(slices, tmp)
|
||||||
|
}
|
||||||
|
return slices
|
||||||
|
}
|
||||||
|
|
||||||
|
func mod[S ~[][]E, E any](x S, val E, i int) S {
|
||||||
|
x[i][0] = val
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertEq(t *testing.T, msg string, exp, act any) {
|
||||||
|
t.Helper()
|
||||||
|
if exp != act {
|
||||||
|
t.Fatalf("failed to test for %s. exp=[%v] but act=[%v]", msg, exp, act)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user