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 (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log"
|
||||
"os/exec"
|
||||
"text/template"
|
||||
@ -36,7 +37,7 @@ func (alert Alert) IsValid() bool {
|
||||
}
|
||||
|
||||
// BuildTemplates compiles command templates for the Alert
|
||||
func (alert *Alert) BuildTemplates() {
|
||||
func (alert *Alert) BuildTemplates() error {
|
||||
if alert.commandTemplate == nil && alert.Command != nil {
|
||||
// build template
|
||||
log.Println("Building template for command...")
|
||||
@ -52,46 +53,50 @@ func (alert *Alert) BuildTemplates() {
|
||||
alert.commandShellTemplate = template.Must(
|
||||
template.New(alert.Name).Parse(alert.CommandShell),
|
||||
)
|
||||
log.Printf("Template built: %v", alert.commandShellTemplate)
|
||||
} 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
|
||||
func (alert Alert) Send(notice AlertNotice) {
|
||||
func (alert Alert) Send(notice AlertNotice) (output_str string, err error) {
|
||||
var cmd *exec.Cmd
|
||||
|
||||
if alert.commandTemplate != nil {
|
||||
// build template
|
||||
log.Println("Send command thing...")
|
||||
command := []string{}
|
||||
for _, cmdTmp := range alert.commandTemplate {
|
||||
var commandBuffer bytes.Buffer
|
||||
err := cmdTmp.Execute(&commandBuffer, notice)
|
||||
err = cmdTmp.Execute(&commandBuffer, notice)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return
|
||||
}
|
||||
command = append(command, commandBuffer.String())
|
||||
}
|
||||
cmd = exec.Command(command[0], command[1:]...)
|
||||
} else if alert.commandShellTemplate != nil {
|
||||
var commandBuffer bytes.Buffer
|
||||
err := alert.commandShellTemplate.Execute(&commandBuffer, notice)
|
||||
err = alert.commandShellTemplate.Execute(&commandBuffer, notice)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return
|
||||
}
|
||||
shellCommand := commandBuffer.String()
|
||||
|
||||
log.Printf("About to run alert command: %s", shellCommand)
|
||||
cmd = ShellCommand(shellCommand)
|
||||
} else {
|
||||
panic("No template compiled?")
|
||||
err = fmt.Errorf("No templates compiled for alert %v", alert.Name)
|
||||
return
|
||||
}
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
log.Printf("Check %s\n---\n%s\n---", alert.Name, string(output))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
// Exit if we're not ready to run the command
|
||||
if cmd == nil || err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
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() {
|
||||
for name, alert := range config.Alerts {
|
||||
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 {
|
||||
if alert, ok := config.Alerts[alertName]; ok {
|
||||
alert.Send(*alertNotice)
|
||||
_, err := alert.Send(*alertNotice)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
log.Printf("WARNING: Could not find alert for %s", alertName)
|
||||
}
|
||||
|
@ -146,13 +146,13 @@ func TestMonitorFailureAlertEvery(t *testing.T) {
|
||||
name string
|
||||
}{
|
||||
/*
|
||||
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
|
||||
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
|
||||
on the first failure.
|
||||
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
|
||||
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
|
||||
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
|
||||
// Alert first time only, after 1
|
||||
|
Loading…
Reference in New Issue
Block a user