Add alert tests
This commit is contained in:
parent
68ee048b76
commit
71574dd8a9
39
alert.go
39
alert.go
@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"text/template"
|
"text/template"
|
||||||
@ -36,7 +37,7 @@ func (alert Alert) IsValid() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// BuildTemplates compiles command templates for the Alert
|
// BuildTemplates compiles command templates for the Alert
|
||||||
func (alert *Alert) BuildTemplates() {
|
func (alert *Alert) BuildTemplates() error {
|
||||||
if alert.commandTemplate == nil && alert.Command != nil {
|
if alert.commandTemplate == nil && alert.Command != nil {
|
||||||
// build template
|
// build template
|
||||||
log.Println("Building template for command...")
|
log.Println("Building template for command...")
|
||||||
@ -52,46 +53,50 @@ func (alert *Alert) BuildTemplates() {
|
|||||||
alert.commandShellTemplate = template.Must(
|
alert.commandShellTemplate = template.Must(
|
||||||
template.New(alert.Name).Parse(alert.CommandShell),
|
template.New(alert.Name).Parse(alert.CommandShell),
|
||||||
)
|
)
|
||||||
log.Printf("Template built: %v", alert.commandShellTemplate)
|
|
||||||
} else {
|
} else {
|
||||||
log.Fatalf("No template provided for alert %s", alert.Name)
|
return fmt.Errorf("No template provided for alert %s", alert.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send will send an alert notice by executing the command template
|
// Send will send an alert notice by executing the command template
|
||||||
func (alert Alert) Send(notice AlertNotice) {
|
func (alert Alert) Send(notice AlertNotice) (output_str string, err error) {
|
||||||
var cmd *exec.Cmd
|
var cmd *exec.Cmd
|
||||||
|
|
||||||
if alert.commandTemplate != nil {
|
if alert.commandTemplate != nil {
|
||||||
// build template
|
|
||||||
log.Println("Send command thing...")
|
|
||||||
command := []string{}
|
command := []string{}
|
||||||
for _, cmdTmp := range alert.commandTemplate {
|
for _, cmdTmp := range alert.commandTemplate {
|
||||||
var commandBuffer bytes.Buffer
|
var commandBuffer bytes.Buffer
|
||||||
err := cmdTmp.Execute(&commandBuffer, notice)
|
err = cmdTmp.Execute(&commandBuffer, notice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return
|
||||||
}
|
}
|
||||||
command = append(command, commandBuffer.String())
|
command = append(command, commandBuffer.String())
|
||||||
}
|
}
|
||||||
cmd = exec.Command(command[0], command[1:]...)
|
cmd = exec.Command(command[0], command[1:]...)
|
||||||
} else if alert.commandShellTemplate != nil {
|
} else if alert.commandShellTemplate != nil {
|
||||||
var commandBuffer bytes.Buffer
|
var commandBuffer bytes.Buffer
|
||||||
err := alert.commandShellTemplate.Execute(&commandBuffer, notice)
|
err = alert.commandShellTemplate.Execute(&commandBuffer, notice)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return
|
||||||
}
|
}
|
||||||
shellCommand := commandBuffer.String()
|
shellCommand := commandBuffer.String()
|
||||||
|
|
||||||
log.Printf("About to run alert command: %s", shellCommand)
|
|
||||||
cmd = ShellCommand(shellCommand)
|
cmd = ShellCommand(shellCommand)
|
||||||
} else {
|
} else {
|
||||||
panic("No template compiled?")
|
err = fmt.Errorf("No templates compiled for alert %v", alert.Name)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
output, err := cmd.CombinedOutput()
|
// Exit if we're not ready to run the command
|
||||||
log.Printf("Check %s\n---\n%s\n---", alert.Name, string(output))
|
if cmd == nil || err != nil {
|
||||||
if err != nil {
|
return
|
||||||
panic(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var output []byte
|
||||||
|
output, err = cmd.CombinedOutput()
|
||||||
|
output_str = string(output)
|
||||||
|
log.Printf("Check %s\n---\n%s\n---", alert.Name, output_str)
|
||||||
|
|
||||||
|
return output_str, err
|
||||||
}
|
}
|
||||||
|
121
alert_test.go
Normal file
121
alert_test.go
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAlertIsValid(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
alert Alert
|
||||||
|
expected bool
|
||||||
|
name string
|
||||||
|
}{
|
||||||
|
{Alert{Command: []string{"echo", "test"}}, true, "Command only"},
|
||||||
|
{Alert{CommandShell: "echo test"}, true, "CommandShell only"},
|
||||||
|
{Alert{}, false, "No commands"},
|
||||||
|
{
|
||||||
|
Alert{Command: []string{"echo", "test"}, CommandShell: "echo test"},
|
||||||
|
false,
|
||||||
|
"Both commands",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
log.Printf("Testing case %s", c.name)
|
||||||
|
actual := c.alert.IsValid()
|
||||||
|
if actual != c.expected {
|
||||||
|
t.Errorf("IsValid(%v), expected=%t actual=%t", c.name, c.expected, actual)
|
||||||
|
log.Printf("Case failed: %s", c.name)
|
||||||
|
}
|
||||||
|
log.Println("-----")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAlertSend(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
alert Alert
|
||||||
|
notice AlertNotice
|
||||||
|
expectedOutput string
|
||||||
|
expectErr bool
|
||||||
|
name string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Alert{Command: []string{"echo", "{{.MonitorName}}"}},
|
||||||
|
AlertNotice{MonitorName: "test"},
|
||||||
|
"test\n",
|
||||||
|
false,
|
||||||
|
"Command with template",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alert{CommandShell: "echo {{.MonitorName}}"},
|
||||||
|
AlertNotice{MonitorName: "test"},
|
||||||
|
"test\n",
|
||||||
|
false,
|
||||||
|
"Command shell with template",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alert{Command: []string{"echo", "{{.Bad}}"}},
|
||||||
|
AlertNotice{MonitorName: "test"},
|
||||||
|
"",
|
||||||
|
true,
|
||||||
|
"Command with bad template",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Alert{CommandShell: "echo {{.Bad}}"},
|
||||||
|
AlertNotice{MonitorName: "test"},
|
||||||
|
"",
|
||||||
|
true,
|
||||||
|
"Command shell with bad template",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
log.Printf("Testing case %s", c.name)
|
||||||
|
c.alert.BuildTemplates()
|
||||||
|
output, err := c.alert.Send(c.notice)
|
||||||
|
hasErr := (err != nil)
|
||||||
|
if output != c.expectedOutput {
|
||||||
|
t.Errorf("Send(%v output), expected=%v actual=%v", c.name, c.expectedOutput, output)
|
||||||
|
log.Printf("Case failed: %s", c.name)
|
||||||
|
}
|
||||||
|
if hasErr != c.expectErr {
|
||||||
|
t.Errorf("Send(%v err), expected=%v actual=%v", c.name, "Err", err)
|
||||||
|
log.Printf("Case failed: %s", c.name)
|
||||||
|
}
|
||||||
|
log.Println("-----")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAlertSendNoTemplates(t *testing.T) {
|
||||||
|
alert := Alert{}
|
||||||
|
notice := AlertNotice{}
|
||||||
|
output, err := alert.Send(notice)
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Send(no template), expected=%v actual=%v", "Err", output)
|
||||||
|
}
|
||||||
|
log.Println("-----")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAlertBuildTemplate(t *testing.T) {
|
||||||
|
cases := []struct {
|
||||||
|
alert Alert
|
||||||
|
expectErr bool
|
||||||
|
name string
|
||||||
|
}{
|
||||||
|
{Alert{Command: []string{"echo", "test"}}, false, "Command only"},
|
||||||
|
{Alert{CommandShell: "echo test"}, false, "CommandShell only"},
|
||||||
|
{Alert{}, true, "No commands"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range cases {
|
||||||
|
log.Printf("Testing case %s", c.name)
|
||||||
|
err := c.alert.BuildTemplates()
|
||||||
|
hasErr := (err != nil)
|
||||||
|
if hasErr != c.expectErr {
|
||||||
|
t.Errorf("IsValid(%v), expected=%t actual=%t", c.name, c.expectErr, err)
|
||||||
|
log.Printf("Case failed: %s", c.name)
|
||||||
|
}
|
||||||
|
log.Println("-----")
|
||||||
|
}
|
||||||
|
}
|
@ -38,7 +38,9 @@ func (config Config) IsValid() (isValid bool) {
|
|||||||
func (config *Config) Init() {
|
func (config *Config) Init() {
|
||||||
for name, alert := range config.Alerts {
|
for name, alert := range config.Alerts {
|
||||||
alert.Name = name
|
alert.Name = name
|
||||||
alert.BuildTemplates()
|
if err := alert.BuildTemplates(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
5
main.go
5
main.go
@ -29,7 +29,10 @@ func main() {
|
|||||||
}
|
}
|
||||||
for _, alertName := range alerts {
|
for _, alertName := range alerts {
|
||||||
if alert, ok := config.Alerts[alertName]; ok {
|
if alert, ok := config.Alerts[alertName]; ok {
|
||||||
alert.Send(*alertNotice)
|
_, err := alert.Send(*alertNotice)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Printf("WARNING: Could not find alert for %s", alertName)
|
log.Printf("WARNING: Could not find alert for %s", alertName)
|
||||||
}
|
}
|
||||||
|
@ -146,13 +146,13 @@ func TestMonitorFailureAlertEvery(t *testing.T) {
|
|||||||
name string
|
name string
|
||||||
}{
|
}{
|
||||||
/*
|
/*
|
||||||
TODO: Actually found a bug in original implementation. There is an inconsistency in the way AlertAfter is treated.
|
TODO: Actually found a bug in original implementation. There is an inconsistency in the way AlertAfter is treated.
|
||||||
For "First alert only" (ie. AlertEvery=0), it is the number of failures to ignore before alerting, so AlertAfter=1
|
For "First alert only" (ie. AlertEvery=0), it is the number of failures to ignore before alerting, so AlertAfter=1
|
||||||
will ignore the first failure and alert on the second failure
|
will ignore the first failure and alert on the second failure
|
||||||
For other intervals (ie. AlertEvery=1), it is essentially indexed on one. Essentially making AlertAfter=1 trigger
|
For other intervals (ie. AlertEvery=1), it is essentially indexed on one. Essentially making AlertAfter=1 trigger
|
||||||
on the first failure.
|
on the first failure.
|
||||||
|
|
||||||
For usabilty, this should be consistent. Consistent with what though? minitor-py? Or itself? Dun dun duuuunnnnn!
|
For usabilty, this should be consistent. Consistent with what though? minitor-py? Or itself? Dun dun duuuunnnnn!
|
||||||
*/
|
*/
|
||||||
{Monitor{AlertAfter: 1}, true, "Empty"}, // Defaults to true because AlertAfter and AlertEvery default to 0
|
{Monitor{AlertAfter: 1}, true, "Empty"}, // Defaults to true because AlertAfter and AlertEvery default to 0
|
||||||
// Alert first time only, after 1
|
// Alert first time only, after 1
|
||||||
|
Loading…
Reference in New Issue
Block a user