diff --git a/email.go b/email.go index 6a08f85..ceea9fd 100644 --- a/email.go +++ b/email.go @@ -7,6 +7,9 @@ import ( "text/template" ) +type emailNotifier struct { +} + const emailTemplate = `From: {{.From}} To: {{.To}} Subject: {{.Subject}} @@ -26,7 +29,7 @@ type EmailData struct { Body string } -func sendEmail(class string, data []byte) { +func (e *emailNotifier) sendMessage(class string, data []byte) NotifierResponse { var err error var doc bytes.Buffer @@ -55,22 +58,7 @@ func sendEmail(class string, data []byte) { // drop e-mail job on a rate limited (max workers) queue // already experienced a connection reset by peer locally -} - -func sendEmailNotification(s *Stat, notifier *Notifier) { - var err error - var doc bytes.Buffer - - t := template.New("notificationTemplate") - t, err = t.Parse(notifier.Template) - if err != nil { - log.Fatal("t.Parse of n.Template", err) - } - - err = t.Execute(&doc, s.toMap()) - if err != nil { - log.Fatal("t.Execute ", err) + return NotifierResponse{ + error: err, } - - sendEmail(s.Key, doc.Bytes()) } diff --git a/notifier.go b/notifier.go index ae7dcf1..805d8e8 100644 --- a/notifier.go +++ b/notifier.go @@ -9,6 +9,15 @@ import ( "github.com/jmoiron/sqlx/types" ) +type NotifierResponse struct { + response *slackResponse + error error +} + +type MessageNotifier interface { + sendMessage(string, []byte) NotifierResponse +} + type Notifier struct { Id int `db:"id"` NotificationType string `db:"notification_type"` @@ -19,6 +28,16 @@ type Notifier struct { // email address, slack channel, phone number, how to store? } +func (n *Notifier) newNotifier() MessageNotifier { + switch n.NotificationType { + case "email": + return &emailNotifier{} + case "slack": + return &slackNotifier{} + } + return &slackNotifier{} +} + func (n *Notifier) getRules() []*Rule { rules := []*Rule{} n.Rules.Unmarshal(&rules) @@ -60,19 +79,14 @@ func (n *Notifier) renderTemplate(s *Stat) []byte { return doc.Bytes() } -func (n *Notifier) notify(s *Stat) { +func (n *Notifier) notify(s *Stat, mn MessageNotifier) { nt := n.NotificationType fmt.Printf("Notifying notifier id: %d type: %s\n", n.Id, nt) if !n.checkRules(s) { - // early return + return } message := n.renderTemplate(s) - switch nt { - case "email": - sendEmail(s.Key, message) - case "slack": - sendSlack(s.Key, message) - } + mn.sendMessage(s.Key, message) } diff --git a/notifier_test.go b/notifier_test.go index 12afc28..789445b 100644 --- a/notifier_test.go +++ b/notifier_test.go @@ -7,6 +7,31 @@ import ( "github.com/stretchr/testify/assert" ) +type LocalMessageNotifier struct { + class string + message []byte + processed bool +} + +func (mn *LocalMessageNotifier) sendMessage(class string, data []byte) NotifierResponse { + mn.class = class + mn.message = data + mn.processed = true + + return NotifierResponse{} +} + +func TestNewNotifier(t *testing.T) { + n := Notifier{} + assert.Equal(t, n.newNotifier(), &slackNotifier{}) + + n.NotificationType = "email" + assert.Equal(t, n.newNotifier(), &slackNotifier{}) + + n.NotificationType = "slack" + assert.Equal(t, n.newNotifier(), &slackNotifier{}) +} + func TestNotifierCheckRulesSingle(t *testing.T) { var rules = types.JsonText(`[{"key": "number", "type": "number", "setting": "eq", "value": "12"}]`) n := Notifier{ @@ -73,10 +98,41 @@ func TestNotifierCheckRulesSettingIsBlank(t *testing.T) { } func TestNotifierNotify(t *testing.T) { - // fake sendSlackNotification somehow? + n := Notifier{ + Id: 1, + NotificationType: "email", + Class: "User", + Template: "name: {{.name}}", + } + + var jt = types.JsonText(`{"active": true, "name": "Go", "number": "12"}`) + s := Stat{"Mark", jt} + + mn := &LocalMessageNotifier{} + n.notify(&s, mn) + + assert.Equal(t, mn.class, "Mark") + assert.Equal(t, mn.message, []byte("name: Go")) + assert.Equal(t, mn.processed, true) } func TestNotifierNotifyReturnsEarlyIfRulesAreNotMet(t *testing.T) { + var rules = types.JsonText(`[{"key": "number", "type": "number", "setting": "gt", "value": "1"}]`) + n := Notifier{ + Id: 1, + NotificationType: "email", + Class: "User", + Template: "name: {{.name}}", + Rules: rules, + } + + var jt = types.JsonText(`{"active": true, "name": "Go", "number": "0"}`) + s := Stat{"Mark", jt} + + mn := &LocalMessageNotifier{} + n.notify(&s, mn) + + assert.Equal(t, mn.processed, false) } func TestNotifierRenderTemplate(t *testing.T) { diff --git a/slack.go b/slack.go index 0822fb8..97b4ec7 100644 --- a/slack.go +++ b/slack.go @@ -9,13 +9,16 @@ import ( "net/url" ) -var transport http.RoundTripper +type slackNotifier struct { +} type slackResponse struct { Ok bool `json:"ok"` Ts string `json:"ts"` } +var transport http.RoundTripper + func getTransport() http.RoundTripper { // If we have overridden this variable in testing if transport != nil { @@ -29,7 +32,7 @@ func SetTransport(t http.RoundTripper) { } // TODO: Get settings from env variables -func sendSlack(class string, data []byte) (*slackResponse, error) { +func (s *slackNotifier) sendMessage(class string, data []byte) NotifierResponse { client := &http.Client{Transport: getTransport()} // https://api.slack.com/methods/chat.postMessage // format := "http://slack.com/api/chat.postMessage?token=%s&channel=%s&text=%s&username=%s&icon_url=%s" @@ -46,7 +49,7 @@ func sendSlack(class string, data []byte) (*slackResponse, error) { res, err := client.Get(url) if err != nil { log.Println("http.Get", err) - return &slackResponse{}, err + return NotifierResponse{&slackResponse{}, err} } defer res.Body.Close() contents, err := ioutil.ReadAll(res.Body) @@ -60,5 +63,5 @@ func sendSlack(class string, data []byte) (*slackResponse, error) { log.Println("json.Unmarshal", err) } - return slackResponse, err + return NotifierResponse{slackResponse, err} } diff --git a/slack_test.go b/slack_test.go index 0288461..f3585c4 100644 --- a/slack_test.go +++ b/slack_test.go @@ -49,8 +49,9 @@ func TestSendSlack(t *testing.T) { test_server := returnTestResponseForPath("/api/chat.postMessage", resp, t) defer closeTestServer(test_server) - response, _ := sendSlack("mark", []byte{10, 10}) - if response.Ok != true { + s := slackNotifier{} + notifierResponse := s.sendMessage("mark", []byte("Message")) + if notifierResponse.response.Ok != true { t.Error("response is not correct") } } diff --git a/udp_listener.go b/udp_listener.go index 482561f..81310c9 100644 --- a/udp_listener.go +++ b/udp_listener.go @@ -77,7 +77,7 @@ func (s *Stat) notify() { for i := 0; i < len(notifiers); i++ { notifier := notifiers[i] - notifier.notify(s) + notifier.notify(s, notifier.newNotifier()) } }