influxdb/kapacitor/tickscripts_test.go

818 lines
16 KiB
Go
Raw Normal View History

2016-11-03 00:59:25 +00:00
package kapacitor
import (
"fmt"
2016-11-03 00:59:25 +00:00
"testing"
"github.com/influxdata/chronograf"
)
func TestGenerate(t *testing.T) {
alert := chronograf.AlertRule{
Name: "name",
Trigger: "relative",
Alerts: []string{"slack", "victorops", "email"},
TriggerValues: chronograf.TriggerValues{
Change: "change",
Period: "10m",
Shift: "1m",
Operator: "greater than",
Value: "90",
},
Every: "30s",
2016-11-03 00:59:25 +00:00
Query: chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
Fields: []struct {
Field string `json:"field"`
Funcs []string `json:"funcs"`
}{
{
Field: "usage_user",
Funcs: []string{"mean"},
},
},
Tags: map[string][]string{
"host": []string{
"acc-0eabc309-eu-west-1-data-3",
"prod",
},
"cpu": []string{
"cpu_total",
},
},
GroupBy: struct {
Time string `json:"time"`
Tags []string `json:"tags"`
}{
Time: "",
Tags: []string{"host", "cluster_id"},
},
AreTagsAccepted: true,
RawText: "",
},
}
gen := Alert{}
tick, err := gen.Generate(alert)
2016-11-03 00:59:25 +00:00
if err != nil {
fmt.Printf("%s", tick)
2016-11-03 00:59:25 +00:00
t.Errorf("Error generating alert: %v", err)
}
}
func TestThreshold(t *testing.T) {
alert := chronograf.AlertRule{
Name: "name",
Trigger: "threshold",
Alerts: []string{"slack", "victorops", "email"},
TriggerValues: chronograf.TriggerValues{
Relation: "once",
Period: "10m",
Percentile: "", // TODO: if relation is not once then this will have a number
Operator: "greater than",
Value: "90",
},
Every: "30s",
Message: "message",
2016-11-03 00:59:25 +00:00
Query: chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
Fields: []struct {
Field string `json:"field"`
Funcs []string `json:"funcs"`
}{
{
Field: "usage_user",
Funcs: []string{"mean"},
},
},
Tags: map[string][]string{
"host": []string{
"acc-0eabc309-eu-west-1-data-3",
"prod",
},
"cpu": []string{
"cpu_total",
},
},
GroupBy: struct {
Time string `json:"time"`
Tags []string `json:"tags"`
}{
Time: "",
Tags: []string{"host", "cluster_id"},
},
AreTagsAccepted: true,
RawText: "",
},
}
tests := []struct {
name string
alert chronograf.AlertRule
want chronograf.TICKScript
wantErr bool
}{
{
name: "Test valid template alert",
alert: alert,
want: `var db = 'telegraf'
var rp = 'autogen'
var measurement = 'cpu'
var groupBy = ['host', 'cluster_id']
2016-11-03 00:59:25 +00:00
var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod')
2016-11-03 00:59:25 +00:00
var period = 10m
var name = 'name'
var idVar = name + ':{{.Group}}'
var message = 'message'
var idTag = 'alertID'
2016-11-03 00:59:25 +00:00
var levelTag = 'level'
2016-11-03 00:59:25 +00:00
var messageField = 'message'
2016-11-03 00:59:25 +00:00
var durationField = 'duration'
var outputDB = 'chronograf'
2016-11-03 00:59:25 +00:00
var outputRP = 'autogen'
2016-11-03 00:59:25 +00:00
var outputMeasurement = 'alerts'
2016-11-03 00:59:25 +00:00
var triggerType = 'threshold'
var every = 30s
var crit = 90
2016-11-03 00:59:25 +00:00
var data = stream
|from()
.database(db)
.retentionPolicy(rp)
.measurement(measurement)
.groupBy(groupBy)
.where(whereFilter)
2016-11-03 00:59:25 +00:00
|window()
.period(period)
.every(every)
.align()
|mean('usage_user')
.as('value')
2016-11-03 00:59:25 +00:00
var trigger = data
|alert()
.stateChangesOnly()
.crit(lambda: "value" > crit)
.message(message)
.id(idVar)
.idTag(idTag)
.levelTag(levelTag)
.messageField(messageField)
.durationField(durationField)
2016-11-03 00:59:25 +00:00
.slack()
.victorOps()
.email()
trigger
|influxDBOut()
.create()
.database(outputDB)
.retentionPolicy(outputRP)
.measurement(outputMeasurement)
.tag('alertName', name)
.tag('triggerType', triggerType)
2016-11-03 00:59:25 +00:00
`,
wantErr: false,
},
}
for _, tt := range tests {
gen := Alert{}
got, err := gen.Generate(tt.alert)
if (err != nil) != tt.wantErr {
t.Errorf("%q. Threshold() error = %v, wantErr %v", tt.name, err, tt.wantErr)
continue
}
if got != tt.want {
fmt.Printf("%s", got)
2016-11-03 00:59:25 +00:00
t.Errorf("%q. Threshold() = %v, want %v", tt.name, got, tt.want)
}
}
}
func TestThresholdNoAggregate(t *testing.T) {
alert := chronograf.AlertRule{
Name: "name",
Trigger: "threshold",
Alerts: []string{"slack", "victorops", "email"},
TriggerValues: chronograf.TriggerValues{
Relation: "once",
Period: "10m",
Percentile: "", // TODO: if relation is not once then this will have a number
Operator: "greater than",
Value: "90",
},
Every: "30s",
Message: "message",
Query: chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
Fields: []struct {
Field string `json:"field"`
Funcs []string `json:"funcs"`
}{
{
Field: "usage_user",
Funcs: []string{},
},
},
Tags: map[string][]string{
"host": []string{
"acc-0eabc309-eu-west-1-data-3",
"prod",
},
"cpu": []string{
"cpu_total",
},
},
GroupBy: struct {
Time string `json:"time"`
Tags []string `json:"tags"`
}{
Time: "",
Tags: []string{"host", "cluster_id"},
},
AreTagsAccepted: true,
RawText: "",
},
}
tests := []struct {
name string
alert chronograf.AlertRule
want chronograf.TICKScript
wantErr bool
}{
{
name: "Test valid template alert",
alert: alert,
want: `var db = 'telegraf'
var rp = 'autogen'
var measurement = 'cpu'
var groupBy = ['host', 'cluster_id']
var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod')
var period = 10m
var name = 'name'
var idVar = name + ':{{.Group}}'
var message = 'message'
var idTag = 'alertID'
var levelTag = 'level'
var messageField = 'message'
var durationField = 'duration'
var outputDB = 'chronograf'
var outputRP = 'autogen'
var outputMeasurement = 'alerts'
var triggerType = 'threshold'
var every = 30s
var crit = 90
var data = stream
|from()
.database(db)
.retentionPolicy(rp)
.measurement(measurement)
.groupBy(groupBy)
.where(whereFilter)
|eval(lambda: "usage_user")
.as('value')
var trigger = data
|alert()
.stateChangesOnly()
.crit(lambda: "value" > crit)
.message(message)
.id(idVar)
.idTag(idTag)
.levelTag(levelTag)
.messageField(messageField)
.durationField(durationField)
.slack()
.victorOps()
.email()
trigger
|influxDBOut()
.create()
.database(outputDB)
.retentionPolicy(outputRP)
.measurement(outputMeasurement)
.tag('alertName', name)
.tag('triggerType', triggerType)
`,
wantErr: false,
},
}
for _, tt := range tests {
gen := Alert{}
got, err := gen.Generate(tt.alert)
if (err != nil) != tt.wantErr {
t.Errorf("%q. Threshold() error = %v, wantErr %v", tt.name, err, tt.wantErr)
continue
}
if got != tt.want {
fmt.Printf("%s", got)
t.Errorf("%q. Threshold() = %v, want %v", tt.name, got, tt.want)
}
}
}
2016-11-03 00:59:25 +00:00
func TestRelative(t *testing.T) {
alert := chronograf.AlertRule{
Name: "name",
Trigger: "relative",
Alerts: []string{"slack", "victorops", "email"},
TriggerValues: chronograf.TriggerValues{
Change: "% change",
Period: "10m",
Shift: "1m",
Operator: "greater than",
Value: "90",
},
Every: "30s",
Message: "message",
2016-11-03 00:59:25 +00:00
Query: chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
Fields: []struct {
Field string `json:"field"`
Funcs []string `json:"funcs"`
}{
{
Field: "usage_user",
Funcs: []string{"mean"},
},
},
Tags: map[string][]string{
"host": []string{
"acc-0eabc309-eu-west-1-data-3",
"prod",
},
"cpu": []string{
"cpu_total",
},
},
GroupBy: struct {
Time string `json:"time"`
Tags []string `json:"tags"`
}{
Time: "",
Tags: []string{"host", "cluster_id"},
},
AreTagsAccepted: true,
RawText: "",
},
}
tests := []struct {
name string
alert chronograf.AlertRule
want chronograf.TICKScript
wantErr bool
}{
{
name: "Test valid template alert",
alert: alert,
want: `var db = 'telegraf'
var rp = 'autogen'
var measurement = 'cpu'
var groupBy = ['host', 'cluster_id']
2016-11-03 00:59:25 +00:00
var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod')
2016-11-03 00:59:25 +00:00
var period = 10m
var name = 'name'
var idVar = name + ':{{.Group}}'
var message = 'message'
var idTag = 'alertID'
2016-11-03 00:59:25 +00:00
var levelTag = 'level'
2016-11-03 00:59:25 +00:00
var messageField = 'message'
2016-11-03 00:59:25 +00:00
var durationField = 'duration'
2016-11-03 00:59:25 +00:00
var outputDB = 'chronograf'
2016-11-03 00:59:25 +00:00
var outputRP = 'autogen'
2016-11-03 00:59:25 +00:00
var outputMeasurement = 'alerts'
2016-11-03 00:59:25 +00:00
var triggerType = 'relative'
var every = 30s
var shift = -1m
var crit = 90
2016-11-03 00:59:25 +00:00
var data = stream
|from()
.database(db)
.retentionPolicy(rp)
.measurement(measurement)
.groupBy(groupBy)
.where(whereFilter)
2016-11-03 00:59:25 +00:00
|window()
.period(period)
.every(every)
.align()
|mean('usage_user')
.as('value')
2016-11-03 00:59:25 +00:00
var past = data
|shift(shift)
var current = data
var trigger = past
|join(current)
.as('past', 'current')
|eval(lambda: abs(float("current.value" - "past.value")) / float("past.value") * 100.0)
2016-11-03 00:59:25 +00:00
.keep()
.as('value')
|alert()
.stateChangesOnly()
.crit(lambda: "value" > crit)
.message(message)
.id(idVar)
.idTag(idTag)
.levelTag(levelTag)
.messageField(messageField)
.durationField(durationField)
2016-11-03 00:59:25 +00:00
.slack()
.victorOps()
.email()
trigger
|influxDBOut()
.create()
.database(outputDB)
.retentionPolicy(outputRP)
.measurement(outputMeasurement)
.tag('alertName', name)
.tag('triggerType', triggerType)
`,
wantErr: false,
},
}
for _, tt := range tests {
gen := Alert{}
got, err := gen.Generate(tt.alert)
if (err != nil) != tt.wantErr {
t.Errorf("%q. Relative() error = %v, wantErr %v", tt.name, err, tt.wantErr)
continue
}
if got != tt.want {
fmt.Printf("%s", got)
t.Errorf("%q. Relative() = %v, want %v", tt.name, got, tt.want)
}
}
}
func TestRelativeChange(t *testing.T) {
alert := chronograf.AlertRule{
Name: "name",
Trigger: "relative",
Alerts: []string{"slack", "victorops", "email"},
TriggerValues: chronograf.TriggerValues{
Change: "change",
Period: "10m",
Shift: "1m",
Operator: "greater than",
Value: "90",
},
Every: "30s",
Message: "message",
Query: chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
Fields: []struct {
Field string `json:"field"`
Funcs []string `json:"funcs"`
}{
{
Field: "usage_user",
Funcs: []string{"mean"},
},
},
Tags: map[string][]string{
"host": []string{
"acc-0eabc309-eu-west-1-data-3",
"prod",
},
"cpu": []string{
"cpu_total",
},
},
GroupBy: struct {
Time string `json:"time"`
Tags []string `json:"tags"`
}{
Time: "",
Tags: []string{"host", "cluster_id"},
},
AreTagsAccepted: true,
RawText: "",
},
}
tests := []struct {
name string
alert chronograf.AlertRule
want chronograf.TICKScript
wantErr bool
}{
{
name: "Test valid template alert",
alert: alert,
want: `var db = 'telegraf'
var rp = 'autogen'
var measurement = 'cpu'
var groupBy = ['host', 'cluster_id']
var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod')
var period = 10m
var name = 'name'
var idVar = name + ':{{.Group}}'
var message = 'message'
var idTag = 'alertID'
var levelTag = 'level'
var messageField = 'message'
var durationField = 'duration'
var outputDB = 'chronograf'
var outputRP = 'autogen'
var outputMeasurement = 'alerts'
var triggerType = 'relative'
var every = 30s
var shift = -1m
var crit = 90
var data = stream
|from()
.database(db)
.retentionPolicy(rp)
.measurement(measurement)
.groupBy(groupBy)
.where(whereFilter)
|window()
.period(period)
.every(every)
.align()
|mean('usage_user')
.as('value')
var past = data
|shift(shift)
var current = data
var trigger = past
|join(current)
.as('past', 'current')
|eval(lambda: float("current.value" - "past.value"))
.keep()
.as('value')
|alert()
.stateChangesOnly()
.crit(lambda: "value" > crit)
.message(message)
.id(idVar)
.idTag(idTag)
.levelTag(levelTag)
.messageField(messageField)
.durationField(durationField)
.slack()
.victorOps()
.email()
2016-11-03 00:59:25 +00:00
trigger
|influxDBOut()
.create()
.database(outputDB)
.retentionPolicy(outputRP)
.measurement(outputMeasurement)
.tag('alertName', name)
.tag('triggerType', triggerType)
2016-11-03 00:59:25 +00:00
`,
wantErr: false,
},
}
for _, tt := range tests {
gen := Alert{}
got, err := gen.Generate(tt.alert)
if (err != nil) != tt.wantErr {
t.Errorf("%q. Relative() error = %v, wantErr %v", tt.name, err, tt.wantErr)
continue
}
if got != tt.want {
fmt.Printf("%s", got)
2016-11-03 00:59:25 +00:00
t.Errorf("%q. Relative() = %v, want %v", tt.name, got, tt.want)
}
}
}
func TestDeadman(t *testing.T) {
alert := chronograf.AlertRule{
Name: "name",
Trigger: "deadman",
Alerts: []string{"slack", "victorops", "email"},
TriggerValues: chronograf.TriggerValues{
Period: "10m",
},
Every: "30s",
Message: "message",
2016-11-03 00:59:25 +00:00
Query: chronograf.QueryConfig{
Database: "telegraf",
Measurement: "cpu",
RetentionPolicy: "autogen",
Fields: []struct {
Field string `json:"field"`
Funcs []string `json:"funcs"`
}{
{
Field: "usage_user",
Funcs: []string{"mean"},
},
},
Tags: map[string][]string{
"host": []string{
"acc-0eabc309-eu-west-1-data-3",
"prod",
},
"cpu": []string{
"cpu_total",
},
},
GroupBy: struct {
Time string `json:"time"`
Tags []string `json:"tags"`
}{
Time: "",
Tags: []string{"host", "cluster_id"},
},
AreTagsAccepted: true,
RawText: "",
},
}
tests := []struct {
name string
alert chronograf.AlertRule
want chronograf.TICKScript
wantErr bool
}{
{
name: "Test valid template alert",
alert: alert,
want: `var db = 'telegraf'
var rp = 'autogen'
var measurement = 'cpu'
var groupBy = ['host', 'cluster_id']
2016-11-03 00:59:25 +00:00
var whereFilter = lambda: ("cpu" == 'cpu_total') AND ("host" == 'acc-0eabc309-eu-west-1-data-3' OR "host" == 'prod')
var period = 10m
var name = 'name'
var idVar = name + ':{{.Group}}'
var message = 'message'
2016-11-03 00:59:25 +00:00
var idTag = 'alertID'
2016-11-03 00:59:25 +00:00
var levelTag = 'level'
2016-11-03 00:59:25 +00:00
var messageField = 'message'
var durationField = 'duration'
var outputDB = 'chronograf'
2016-11-03 00:59:25 +00:00
var outputRP = 'autogen'
2016-11-03 00:59:25 +00:00
var outputMeasurement = 'alerts'
2016-11-03 00:59:25 +00:00
var triggerType = 'deadman'
var threshold = 0.0
2016-11-03 00:59:25 +00:00
var data = stream
|from()
.database(db)
.retentionPolicy(rp)
.measurement(measurement)
.groupBy(groupBy)
.where(whereFilter)
2016-11-03 00:59:25 +00:00
var trigger = data
|deadman(threshold, period)
2016-11-03 00:59:25 +00:00
.stateChangesOnly()
.message(message)
.id(idVar)
.idTag(idTag)
.levelTag(levelTag)
.messageField(messageField)
.durationField(durationField)
2016-11-03 00:59:25 +00:00
.slack()
.victorOps()
.email()
trigger
|eval(lambda: "emitted")
.as('value')
.keep('value', messageField, durationField)
2016-11-03 00:59:25 +00:00
|influxDBOut()
.create()
.database(outputDB)
.retentionPolicy(outputRP)
.measurement(outputMeasurement)
.tag('alertName', name)
.tag('triggerType', triggerType)
2016-11-03 00:59:25 +00:00
`,
wantErr: false,
},
}
for _, tt := range tests {
gen := Alert{}
got, err := gen.Generate(tt.alert)
if (err != nil) != tt.wantErr {
t.Errorf("%q. Deadman() error = %v, wantErr %v", tt.name, err, tt.wantErr)
continue
}
if got != tt.want {
fmt.Printf("%s", got)
2016-11-03 00:59:25 +00:00
t.Errorf("%q. Deadman() = %v, want %v", tt.name, got, tt.want)
}
}
}