Implement silencing for acceptance tests, use api package

This commit is contained in:
Fabian Reinartz 2015-10-01 20:58:46 +02:00
parent fdf4d80003
commit 38b324eab2
4 changed files with 108 additions and 19 deletions

View File

@ -13,7 +13,9 @@ import (
"testing"
"time"
"github.com/prometheus/client_golang/api/alertmanager"
"github.com/prometheus/common/model"
"golang.org/x/net/context"
)
type AcceptanceTest struct {
@ -57,7 +59,7 @@ func freeAddress() string {
if err != nil {
panic(err)
}
defer l.Close()
l.Close()
return l.Addr().String()
}
@ -81,13 +83,20 @@ func (t *AcceptanceTest) Alertmanager() *Alertmanager {
t.Fatal(err)
}
addr := freeAddress()
am.addr = freeAddress()
client, err := alertmanager.New(alertmanager.Config{
Address: fmt.Sprintf("http://%s", am.addr),
})
if err != nil {
t.Error(err)
}
am.client = client
am.url = fmt.Sprintf("http://%s", addr)
am.cmd = exec.Command("../../alertmanager",
"-config.file", cf.Name(),
"-log.level", "debug",
"-web.listen-address", addr,
"-web.listen-address", am.addr,
)
var outb, errb bytes.Buffer
@ -149,16 +158,17 @@ func (t *AcceptanceTest) Run() {
// declaring alerts being pushed to it at fixed points in time.
type Alertmanager struct {
t *testing.T
url string
cmd *exec.Cmd
opts *AcceptanceOpts
addr string
client alertmanager.Client
cmd *exec.Cmd
confFile *os.File
actions map[float64][]func()
}
// push declares alerts that are to be pushed to the Alertmanager
// Push declares alerts that are to be pushed to the Alertmanager
// server at a relative point in time.
func (am *Alertmanager) Push(at float64, alerts ...*TestAlert) {
var nas model.Alerts
@ -173,7 +183,7 @@ func (am *Alertmanager) Push(at float64, alerts ...*TestAlert) {
return
}
resp, err := http.Post(am.url+"/api/alerts", "application/json", &buf)
resp, err := http.Post(fmt.Sprintf("http://%s/api/alerts", am.addr), "application/json", &buf)
if err != nil {
am.t.Error(err)
return
@ -182,14 +192,32 @@ func (am *Alertmanager) Push(at float64, alerts ...*TestAlert) {
})
}
func (am *Alertmanager) SetSilence(at float64) {
// SetSilence updates or creates the given Silence.
func (am *Alertmanager) SetSilence(at float64, sil *TestSilence) {
silences := alertmanager.NewSilenceAPI(am.client)
am.Do(at, func() {
sid, err := silences.Set(context.Background(), sil.nativeSilence(am.opts))
if err != nil {
am.t.Error(err)
return
}
sil.ID = sid
})
}
func (am *Alertmanager) DelSilence(at float64) {
// DelSilence deletes the silence with the sid at the given time.
func (am *Alertmanager) DelSilence(at float64, sil *TestSilence) {
silences := alertmanager.NewSilenceAPI(am.client)
am.Do(at, func() {
if err := silences.Del(context.Background(), sil.ID); err != nil {
am.t.Error(err)
}
})
}
// Do sets the given function to be executed at the given time.
func (am *Alertmanager) Do(at float64, f func()) {
am.actions[at] = append(am.actions[at], f)
}

View File

@ -12,12 +12,6 @@ import (
"github.com/prometheus/alertmanager/notify"
)
type TestAlert struct {
labels model.LabelSet
annotations model.LabelSet
startsAt, endsAt float64
}
// At is a convenience method to allow for declarative syntax of Acceptance
// test definitions.
func At(ts float64) float64 {
@ -42,6 +36,73 @@ func Between(start, end float64) Interval {
return Interval{start: start, end: end}
}
// TestSilence models a model.Silence with relative times.
type TestSilence struct {
ID uint64
match []string
matchRE []string
startsAt, endsAt float64
}
// Silence creates a new TestSilence active for the relative interval given
// by start and end.
func Silence(start, end float64) *TestSilence {
return &TestSilence{
startsAt: start,
endsAt: end,
}
}
// Match adds a new plain matcher to the silence.
func (s *TestSilence) Match(v ...string) *TestSilence {
s.match = append(s.match, v...)
return s
}
// MatchRE adds a new regex matcher to the silence
func (s *TestSilence) MatchRE(v ...string) *TestSilence {
if len(v)%2 == 1 {
panic("bad key/values")
}
s.matchRE = append(s.matchRE, v...)
return s
}
// nativeSilence converts the declared test silence into a regular
// silence with resolved times.
func (sil *TestSilence) nativeSilence(opts *AcceptanceOpts) *model.Silence {
nsil := &model.Silence{}
for i := 0; i < len(sil.match); i += 2 {
nsil.Matchers = append(nsil.Matchers, &model.Matcher{
Name: model.LabelName(sil.match[i]),
Value: sil.match[i+1],
})
}
for i := 0; i < len(sil.matchRE); i += 2 {
nsil.Matchers = append(nsil.Matchers, &model.Matcher{
Name: model.LabelName(sil.match[i]),
Value: sil.match[i+1],
IsRegex: true,
})
}
if sil.startsAt > 0 {
nsil.StartsAt = opts.expandTime(sil.startsAt)
}
if sil.endsAt > 0 {
nsil.EndsAt = opts.expandTime(sil.endsAt)
}
return nsil
}
// TestAlert models a model.Alert with relative times.
type TestAlert struct {
labels model.LabelSet
annotations model.LabelSet
startsAt, endsAt float64
}
// alert creates a new alert declaration with the given key/value pairs
// as identifying labels.
func Alert(keyval ...interface{}) *TestAlert {

View File

@ -37,7 +37,7 @@ func (m *Matcher) UnmarshalJSON(b []byte) error {
return fmt.Errorf("label name in matcher must not be empty")
}
if m.IsRegex {
if _, err := regexp.Compile(expr); err != nil {
if _, err := regexp.Compile(m.Value); err != nil {
return err
}
}

4
vendor/vendor.json vendored
View File

@ -59,8 +59,8 @@
},
{
"path": "github.com/prometheus/common/model",
"revision": "4e3fbe8499d234bee309a86d934b0f77d2963a17",
"revisionTime": "2015-10-01T18:06:56+02:00"
"revision": "4c9032a3f7aceade2585f2bbe302bf8c9ea3e9a9",
"revisionTime": "2015-10-01T18:35:54+02:00"
},
{
"path": "github.com/prometheus/common/route",