2020-06-21 12:32:46 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2021-05-25 15:27:22 +02:00
|
|
|
"context"
|
2020-06-21 12:32:46 +02:00
|
|
|
"fmt"
|
|
|
|
"net/url"
|
|
|
|
"os"
|
|
|
|
"testing"
|
2021-05-25 15:27:22 +02:00
|
|
|
"time"
|
2020-06-21 12:32:46 +02:00
|
|
|
|
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/notifier"
|
2021-11-30 00:18:48 +01:00
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/app/vmalert/remotewrite"
|
2021-05-25 15:27:22 +02:00
|
|
|
"github.com/VictoriaMetrics/VictoriaMetrics/lib/procutil"
|
2020-06-21 12:32:46 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestGetExternalURL(t *testing.T) {
|
|
|
|
expURL := "https://vicotriametrics.com/path"
|
|
|
|
u, err := getExternalURL(expURL, "", false)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error %s", err)
|
|
|
|
}
|
|
|
|
if u.String() != expURL {
|
|
|
|
t.Errorf("unexpected url want %s, got %s", expURL, u.String())
|
|
|
|
}
|
|
|
|
h, _ := os.Hostname()
|
|
|
|
expURL = fmt.Sprintf("https://%s:4242", h)
|
|
|
|
u, err = getExternalURL("", "0.0.0.0:4242", true)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error %s", err)
|
|
|
|
}
|
|
|
|
if u.String() != expURL {
|
|
|
|
t.Errorf("unexpected url want %s, got %s", expURL, u.String())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestGetAlertURLGenerator(t *testing.T) {
|
2022-10-05 19:25:03 +02:00
|
|
|
testAlert := notifier.Alert{GroupID: 42, ID: 2, Value: 4, Labels: map[string]string{"tenant": "baz"}}
|
2020-06-21 12:32:46 +02:00
|
|
|
u, _ := url.Parse("https://victoriametrics.com/path")
|
|
|
|
fn, err := getAlertURLGenerator(u, "", false)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error %s", err)
|
|
|
|
}
|
2022-08-17 14:46:28 +02:00
|
|
|
exp := fmt.Sprintf("https://victoriametrics.com/path/vmalert/alert?%s=42&%s=2", paramGroupID, paramAlertID)
|
2022-07-08 10:26:13 +02:00
|
|
|
if exp != fn(testAlert) {
|
2020-06-21 12:32:46 +02:00
|
|
|
t.Errorf("unexpected url want %s, got %s", exp, fn(testAlert))
|
|
|
|
}
|
|
|
|
_, err = getAlertURLGenerator(nil, "foo?{{invalid}}", true)
|
|
|
|
if err == nil {
|
2022-07-18 11:02:51 +02:00
|
|
|
t.Errorf("expected template validation error got nil")
|
2020-06-21 12:32:46 +02:00
|
|
|
}
|
2022-10-05 19:25:03 +02:00
|
|
|
fn, err = getAlertURLGenerator(u, "foo?query={{$value}}&ds={{ $labels.tenant }}", true)
|
2020-06-21 12:32:46 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Errorf("unexpected error %s", err)
|
|
|
|
}
|
2022-10-26 16:00:14 +02:00
|
|
|
if exp := "https://victoriametrics.com/path/foo%3Fquery%3D4%26ds%3Dbaz"; exp != fn(testAlert) {
|
2020-06-21 12:32:46 +02:00
|
|
|
t.Errorf("unexpected url want %s, got %s", exp, fn(testAlert))
|
|
|
|
}
|
|
|
|
}
|
2021-05-25 15:27:22 +02:00
|
|
|
|
|
|
|
func TestConfigReload(t *testing.T) {
|
|
|
|
originalRulePath := *rulePath
|
|
|
|
defer func() {
|
|
|
|
*rulePath = originalRulePath
|
|
|
|
}()
|
|
|
|
|
|
|
|
const (
|
|
|
|
rules1 = `
|
|
|
|
groups:
|
|
|
|
- name: group-1
|
|
|
|
rules:
|
|
|
|
- alert: ExampleAlertAlwaysFiring
|
|
|
|
expr: sum by(job) (up == 1)
|
|
|
|
- record: handler:requests:rate5m
|
|
|
|
expr: sum(rate(prometheus_http_requests_total[5m])) by (handler)
|
|
|
|
`
|
|
|
|
rules2 = `
|
|
|
|
groups:
|
|
|
|
- name: group-1
|
|
|
|
rules:
|
|
|
|
- alert: ExampleAlertAlwaysFiring
|
|
|
|
expr: sum by(job) (up == 1)
|
|
|
|
- name: group-2
|
|
|
|
rules:
|
|
|
|
- record: handler:requests:rate5m
|
|
|
|
expr: sum(rate(prometheus_http_requests_total[5m])) by (handler)
|
|
|
|
`
|
|
|
|
)
|
|
|
|
|
2022-08-21 23:20:55 +02:00
|
|
|
f, err := os.CreateTemp("", "")
|
2021-05-25 15:27:22 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
writeToFile(t, f.Name(), rules1)
|
|
|
|
|
|
|
|
*rulesCheckInterval = 200 * time.Millisecond
|
|
|
|
*rulePath = []string{f.Name()}
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
|
|
|
|
|
m := &manager{
|
|
|
|
querierBuilder: &fakeQuerier{},
|
|
|
|
groups: make(map[uint64]*Group),
|
|
|
|
labels: map[string]string{},
|
2022-02-02 13:11:41 +01:00
|
|
|
notifiers: func() []notifier.Notifier { return []notifier.Notifier{&fakeNotifier{}} },
|
2021-11-30 00:18:48 +01:00
|
|
|
rw: &remotewrite.Client{},
|
2021-05-25 15:27:22 +02:00
|
|
|
}
|
2021-09-13 14:48:18 +02:00
|
|
|
|
|
|
|
syncCh := make(chan struct{})
|
2021-10-19 15:35:27 +02:00
|
|
|
sighupCh := procutil.NewSighupChan()
|
2021-09-13 14:48:18 +02:00
|
|
|
go func() {
|
2021-10-19 15:35:27 +02:00
|
|
|
configReload(ctx, m, nil, sighupCh)
|
2021-09-13 14:48:18 +02:00
|
|
|
close(syncCh)
|
|
|
|
}()
|
2021-05-25 15:27:22 +02:00
|
|
|
|
|
|
|
lenLocked := func(m *manager) int {
|
|
|
|
m.groupsMu.RLock()
|
|
|
|
defer m.groupsMu.RUnlock()
|
|
|
|
return len(m.groups)
|
|
|
|
}
|
|
|
|
|
|
|
|
time.Sleep(*rulesCheckInterval * 2)
|
|
|
|
groupsLen := lenLocked(m)
|
|
|
|
if groupsLen != 1 {
|
|
|
|
t.Fatalf("expected to have exactly 1 group loaded; got %d", groupsLen)
|
|
|
|
}
|
|
|
|
|
|
|
|
writeToFile(t, f.Name(), rules2)
|
|
|
|
time.Sleep(*rulesCheckInterval * 2)
|
|
|
|
groupsLen = lenLocked(m)
|
|
|
|
if groupsLen != 2 {
|
|
|
|
fmt.Println(m.groups)
|
|
|
|
t.Fatalf("expected to have exactly 2 groups loaded; got %d", groupsLen)
|
|
|
|
}
|
|
|
|
|
|
|
|
writeToFile(t, f.Name(), rules1)
|
|
|
|
procutil.SelfSIGHUP()
|
|
|
|
time.Sleep(*rulesCheckInterval / 2)
|
|
|
|
groupsLen = lenLocked(m)
|
|
|
|
if groupsLen != 1 {
|
|
|
|
t.Fatalf("expected to have exactly 1 group loaded; got %d", groupsLen)
|
|
|
|
}
|
|
|
|
|
|
|
|
writeToFile(t, f.Name(), `corrupted`)
|
|
|
|
procutil.SelfSIGHUP()
|
|
|
|
time.Sleep(*rulesCheckInterval / 2)
|
|
|
|
groupsLen = lenLocked(m)
|
|
|
|
if groupsLen != 1 { // should remain unchanged
|
|
|
|
t.Fatalf("expected to have exactly 1 group loaded; got %d", groupsLen)
|
|
|
|
}
|
2021-09-13 14:48:18 +02:00
|
|
|
|
|
|
|
cancel()
|
|
|
|
<-syncCh
|
2021-05-25 15:27:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func writeToFile(t *testing.T, file, b string) {
|
|
|
|
t.Helper()
|
2022-08-21 22:51:13 +02:00
|
|
|
err := os.WriteFile(file, []byte(b), 0644)
|
2021-05-25 15:27:22 +02:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|