2020-05-10 16:58:17 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"math/rand"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestManagerUpdateError(t *testing.T) {
|
|
|
|
m := &manager{groups: make(map[uint64]*Group)}
|
|
|
|
path := []string{"foo/bar"}
|
|
|
|
err := m.update(context.Background(), path, true, false)
|
|
|
|
if err == nil {
|
|
|
|
t.Fatalf("expected to have err; got nil instead")
|
|
|
|
}
|
|
|
|
expErr := "no groups found"
|
|
|
|
if !strings.Contains(err.Error(), expErr) {
|
|
|
|
t.Fatalf("expected to got err %s; got %s", expErr, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestManagerUpdateConcurrent supposed to test concurrent
|
|
|
|
// execution of configuration update.
|
|
|
|
// Should be executed with -race flag
|
|
|
|
func TestManagerUpdateConcurrent(t *testing.T) {
|
2020-05-17 14:12:09 +00:00
|
|
|
m := &manager{
|
|
|
|
groups: make(map[uint64]*Group),
|
|
|
|
storage: &fakeQuerier{},
|
|
|
|
notifier: &fakeNotifier{},
|
|
|
|
}
|
2020-05-10 16:58:17 +00:00
|
|
|
paths := []string{
|
|
|
|
"testdata/dir/rules0-good.rules",
|
|
|
|
"testdata/dir/rules1-good.rules",
|
|
|
|
"testdata/rules0-good.rules",
|
|
|
|
}
|
2020-05-17 14:12:09 +00:00
|
|
|
*evaluationInterval = time.Millisecond
|
|
|
|
if err := m.start(context.Background(), []string{paths[0]}, true); err != nil {
|
|
|
|
t.Fatalf("failed to start: %s", err)
|
|
|
|
}
|
2020-05-10 16:58:17 +00:00
|
|
|
|
2020-05-17 14:12:09 +00:00
|
|
|
const workers = 500
|
|
|
|
const iterations = 10
|
2020-05-10 16:58:17 +00:00
|
|
|
wg := sync.WaitGroup{}
|
2020-05-17 14:12:09 +00:00
|
|
|
wg.Add(workers)
|
|
|
|
for i := 0; i < workers; i++ {
|
2020-05-10 16:58:17 +00:00
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
2020-05-17 14:12:09 +00:00
|
|
|
for i := 0; i < iterations; i++ {
|
|
|
|
rnd := rand.Intn(len(paths))
|
|
|
|
path := []string{paths[rnd]}
|
|
|
|
err := m.update(context.Background(), path, true, false)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("update error: %s", err)
|
|
|
|
}
|
2020-05-10 16:58:17 +00:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
wg.Wait()
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestManagerUpdate tests sequential configuration
|
|
|
|
// updates.
|
|
|
|
func TestManagerUpdate(t *testing.T) {
|
|
|
|
testCases := []struct {
|
|
|
|
name string
|
|
|
|
initPath string
|
|
|
|
updatePath string
|
|
|
|
want []*Group
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
name: "update good rules",
|
|
|
|
initPath: "testdata/rules0-good.rules",
|
|
|
|
updatePath: "testdata/dir/rules1-good.rules",
|
|
|
|
want: []*Group{
|
|
|
|
{
|
|
|
|
File: "testdata/dir/rules1-good.rules",
|
|
|
|
Name: "duplicatedGroupDiffFiles",
|
|
|
|
Rules: []*Rule{newTestRule("VMRows", time.Second*10)},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "update good rules from 1 to 2 groups",
|
|
|
|
initPath: "testdata/dir/rules1-good.rules",
|
|
|
|
updatePath: "testdata/rules0-good.rules",
|
|
|
|
want: []*Group{
|
|
|
|
{
|
|
|
|
File: "testdata/rules0-good.rules",
|
|
|
|
Name: "groupGorSingleAlert", Rules: []*Rule{
|
|
|
|
newTestRule("VMRows", time.Second*10),
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
File: "testdata/rules0-good.rules",
|
|
|
|
Name: "TestGroup", Rules: []*Rule{
|
|
|
|
newTestRule("Conns", time.Duration(0)),
|
|
|
|
newTestRule("ExampleAlertAlwaysFiring", time.Duration(0)),
|
|
|
|
}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "update with one bad rule file",
|
|
|
|
initPath: "testdata/rules0-good.rules",
|
|
|
|
updatePath: "testdata/dir/rules2-bad.rules",
|
|
|
|
want: []*Group{
|
|
|
|
{
|
|
|
|
File: "testdata/rules0-good.rules",
|
|
|
|
Name: "groupGorSingleAlert", Rules: []*Rule{
|
|
|
|
newTestRule("VMRows", time.Second*10),
|
|
|
|
}},
|
|
|
|
{
|
|
|
|
File: "testdata/rules0-good.rules",
|
|
|
|
Name: "TestGroup", Rules: []*Rule{
|
|
|
|
newTestRule("Conns", time.Duration(0)),
|
|
|
|
newTestRule("ExampleAlertAlwaysFiring", time.Duration(0)),
|
|
|
|
}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
|
|
ctx, cancel := context.WithCancel(context.TODO())
|
2020-05-17 14:12:09 +00:00
|
|
|
m := &manager{groups: make(map[uint64]*Group), storage: &fakeQuerier{}}
|
2020-05-10 16:58:17 +00:00
|
|
|
path := []string{tc.initPath}
|
|
|
|
if err := m.update(ctx, path, true, false); err != nil {
|
|
|
|
t.Fatalf("failed to complete initial rules update: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
path = []string{tc.updatePath}
|
|
|
|
_ = m.update(ctx, path, true, false)
|
|
|
|
if len(tc.want) != len(m.groups) {
|
|
|
|
t.Fatalf("\nwant number of groups: %d;\ngot: %d ", len(tc.want), len(m.groups))
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, wantG := range tc.want {
|
|
|
|
gotG, ok := m.groups[wantG.ID()]
|
|
|
|
if !ok {
|
|
|
|
t.Fatalf("expected to have group %q", wantG.Name)
|
|
|
|
}
|
|
|
|
compareGroups(t, gotG, wantG)
|
|
|
|
}
|
|
|
|
|
|
|
|
cancel()
|
|
|
|
m.close()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func compareGroups(t *testing.T, a, b *Group) {
|
|
|
|
t.Helper()
|
|
|
|
if len(a.Rules) != len(b.Rules) {
|
|
|
|
t.Fatalf("expected group %s to have %d rules; got: %d",
|
|
|
|
a.Name, len(a.Rules), len(b.Rules))
|
|
|
|
}
|
|
|
|
for i, r := range a.Rules {
|
|
|
|
got, want := r, b.Rules[i]
|
|
|
|
if got.Name != want.Name {
|
|
|
|
t.Fatalf("expected to have rule %q; got %q", want.Name, got.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|