Skip to content

Commit

Permalink
refactor: Issue #797
Browse files Browse the repository at this point in the history
Use constructor function NewSender instead of Init method, remove Init method from Sender interface.
  • Loading branch information
Dimedrolity committed Nov 11, 2022
1 parent 426a179 commit f7efa24
Show file tree
Hide file tree
Showing 29 changed files with 381 additions and 302 deletions.
79 changes: 45 additions & 34 deletions integration_tests/notifier/notifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/moira-alert/moira/notifier"
"github.com/moira-alert/moira/notifier/events"
"github.com/moira-alert/moira/notifier/notifications"
. "github.com/smartystreets/goconvey/convey"
)

var senderSettings = map[string]string{
Expand Down Expand Up @@ -78,41 +79,51 @@ var event = moira.NotificationEvent{
func TestNotifier(t *testing.T) {
mockCtrl = gomock.NewController(t)
defer mockCtrl.Finish()
database := redis.NewTestDatabase(logger)
metricsSourceProvider := metricSource.CreateMetricSourceProvider(local.Create(database), nil)
database.SaveContact(&contact) //nolint
database.SaveSubscription(&subscription) //nolint
database.SaveTrigger(trigger.ID, &trigger) //nolint
database.PushNotificationEvent(&event, true) //nolint
notifier2 := notifier.NewNotifier(database, logger, notifierConfig, notifierMetrics, metricsSourceProvider, map[string]moira.ImageStore{})
sender := mock_moira_alert.NewMockSender(mockCtrl)
sender.EXPECT().Init(senderSettings, logger, location, dateTimeFormat).Return(nil)
notifier2.RegisterSender(senderSettings, sender) //nolint
sender.EXPECT().SendEvents(gomock.Any(), contact, triggerData, gomock.Any(), false).Return(nil).Do(func(arg0, arg1, arg2, arg3, arg4 interface{}) {
fmt.Print("SendEvents called. End test")
close(shutdown)
})

fetchEventsWorker := events.FetchEventsWorker{
Database: database,
Logger: logger,
Metrics: notifierMetrics,
Scheduler: notifier.NewScheduler(database, logger, notifierMetrics),
}

fetchNotificationsWorker := notifications.FetchNotificationsWorker{
Database: database,
Logger: logger,
Notifier: notifier2,
}

fetchEventsWorker.Start()
fetchNotificationsWorker.Start()

waitTestEnd()

fetchEventsWorker.Stop() //nolint
fetchNotificationsWorker.Stop() //nolint
Convey("TestNotifier", t, func() {
database := redis.NewTestDatabase(logger)
metricsSourceProvider := metricSource.CreateMetricSourceProvider(local.Create(database), nil)
err := database.SaveContact(&contact)
So(err, ShouldBeNil)
err = database.SaveSubscription(&subscription)
So(err, ShouldBeNil)
err = database.SaveTrigger(trigger.ID, &trigger)
So(err, ShouldBeNil)
err = database.PushNotificationEvent(&event, true)
So(err, ShouldBeNil)

notifier2 := notifier.NewNotifier(database, logger, notifierConfig, notifierMetrics, metricsSourceProvider, map[string]moira.ImageStore{})
sender := mock_moira_alert.NewMockSender(mockCtrl)
err = notifier2.RegisterSender(senderSettings, sender)
So(err, ShouldBeNil)
sender.EXPECT().SendEvents(gomock.Any(), contact, triggerData, gomock.Any(), false).Return(nil).Do(func(arg0, arg1, arg2, arg3, arg4 interface{}) {
fmt.Print("SendEvents called. End test")
close(shutdown)
})

fetchEventsWorker := events.FetchEventsWorker{
Database: database,
Logger: logger,
Metrics: notifierMetrics,
Scheduler: notifier.NewScheduler(database, logger, notifierMetrics),
}

fetchNotificationsWorker := notifications.FetchNotificationsWorker{
Database: database,
Logger: logger,
Notifier: notifier2,
}

fetchEventsWorker.Start()
fetchNotificationsWorker.Start()

waitTestEnd()

err = fetchEventsWorker.Stop()
So(err, ShouldBeNil)
err = fetchNotificationsWorker.Stop()
So(err, ShouldBeNil)
})
}

func waitTestEnd() {
Expand Down
1 change: 0 additions & 1 deletion interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ type Logger interface {
// Sender interface for implementing specified contact type sender
type Sender interface {
SendEvents(events NotificationEvents, contact ContactData, trigger TriggerData, plot [][]byte, throttled bool) error
Init(senderSettings map[string]string, logger Logger, location *time.Location, dateTimeFormat string) error
}

// ImageStore is the interface for image storage providers
Expand Down
15 changes: 0 additions & 15 deletions mock/moira-alert/sender.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 3 additions & 4 deletions notifier/notifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,10 @@ func configureNotifier(t *testing.T) {
"type": "test",
}

sender.EXPECT().Init(senderSettings, logger, location, "15:04 02.01.2006").Return(nil)

notif.RegisterSender(senderSettings, sender) //nolint

Convey("Should return one sender", t, func() {
err := notif.RegisterSender(senderSettings, sender)
So(err, ShouldBeNil)

So(notif.GetSenders(), ShouldResemble, map[string]bool{"test": true})
})
}
Expand Down
47 changes: 26 additions & 21 deletions notifier/registrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,50 +38,58 @@ const (
msTeamsSender = "msteams"
)

// RegisterSenders watch on senders config and register all configured senders
// RegisterSenders creates all senders and registers them.
func (notifier *StandardNotifier) RegisterSenders(connector moira.Database) error { //nolint
var err error
for _, senderSettings := range notifier.config.Senders {
senderSettings["front_uri"] = notifier.config.FrontURL

var sender moira.Sender

switch senderSettings["type"] {
case mailSender:
err = notifier.RegisterSender(senderSettings, &mail.Sender{})
sender, err = mail.NewSender(senderSettings, notifier.logger, notifier.config.Location, notifier.config.DateTimeFormat)
case pushoverSender:
err = notifier.RegisterSender(senderSettings, &pushover.Sender{})
sender, err = pushover.NewSender(senderSettings, notifier.logger, notifier.config.Location)
case scriptSender:
err = notifier.RegisterSender(senderSettings, &script.Sender{})
sender, err = script.NewSender(senderSettings, notifier.logger)
case discordSender:
err = notifier.RegisterSender(senderSettings, &discord.Sender{DataBase: connector})
sender, err = discord.NewSender(senderSettings, notifier.logger, notifier.config.Location, connector)
case slackSender:
err = notifier.RegisterSender(senderSettings, &slack.Sender{})
sender, err = slack.NewSender(senderSettings, notifier.logger, notifier.config.Location)
case telegramSender:
err = notifier.RegisterSender(senderSettings, &telegram.Sender{DataBase: connector})
sender, err = telegram.NewSender(senderSettings, notifier.logger, notifier.config.Location, connector)
case msTeamsSender:
err = notifier.RegisterSender(senderSettings, &msteams.Sender{})
sender, err = msteams.NewSender(senderSettings, notifier.logger, notifier.config.Location)
case pagerdutySender:
err = notifier.RegisterSender(senderSettings, &pagerduty.Sender{ImageStores: notifier.imageStores})
sender = pagerduty.NewSender(senderSettings, notifier.logger, notifier.config.Location, notifier.imageStores)
case twilioSmsSender, twilioVoiceSender:
err = notifier.RegisterSender(senderSettings, &twilio.Sender{})
sender, err = twilio.NewSender(senderSettings, notifier.logger, notifier.config.Location)
case webhookSender:
err = notifier.RegisterSender(senderSettings, &webhook.Sender{})
sender, err = webhook.NewSender(senderSettings, notifier.logger)
case opsgenieSender:
err = notifier.RegisterSender(senderSettings, &opsgenie.Sender{ImageStores: notifier.imageStores})
sender, err = opsgenie.NewSender(senderSettings, notifier.logger, notifier.config.Location, notifier.imageStores)
case victoropsSender:
err = notifier.RegisterSender(senderSettings, &victorops.Sender{ImageStores: notifier.imageStores})
sender, err = victorops.NewSender(senderSettings, notifier.logger, notifier.config.Location, notifier.imageStores)
// case "email":
// err = notifier.RegisterSender(senderSettings, &kontur.MailSender{})
// sender = kontur.NewMailSender(senderSettings, notifier.logger, notifier.config.Location, notifier.config.DateTimeFormat)
// case "phone":
// err = notifier.RegisterSender(senderSettings, &kontur.SmsSender{})
// sender = kontur.NewSmsSender(senderSettings, notifier.logger, notifier.config.Location)
default:
return fmt.Errorf("unknown sender type [%s]", senderSettings["type"])
}
if err != nil {
return err
return fmt.Errorf("failed to initialize sender [%s], err [%s]", senderSettings["type"], err.Error())
}
err = notifier.RegisterSender(senderSettings, sender)
if err != nil {
return fmt.Errorf("failed to register sender [%s], err [%s]", senderSettings["type"], err.Error())
}
}
if notifier.config.SelfStateEnabled {
selfStateSettings := map[string]string{"type": selfStateSender}
if err = notifier.RegisterSender(selfStateSettings, &selfstate.Sender{Database: connector}); err != nil {
sender := selfstate.NewSender(notifier.logger, connector)
if err = notifier.RegisterSender(selfStateSettings, sender); err != nil {
notifier.logger.Warningf("failed to register selfstate sender: %s", err.Error())
}
}
Expand All @@ -97,10 +105,7 @@ func (notifier *StandardNotifier) RegisterSender(senderSettings map[string]strin
default:
senderIdent = senderSettings["type"]
}
err := sender.Init(senderSettings, notifier.logger, notifier.config.Location, notifier.config.DateTimeFormat)
if err != nil {
return fmt.Errorf("failed to initialize sender [%s], err [%s]", senderIdent, err.Error())
}

eventsChannel := make(chan NotificationPackage)
notifier.senders[senderIdent] = eventsChannel
notifier.metrics.SendersOkMetrics.RegisterMeter(senderIdent, getGraphiteSenderIdent(senderIdent), "sends_ok")
Expand Down
18 changes: 12 additions & 6 deletions senders/discord/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ const (
workerName = "DiscordBot"
)

// Sender implements moira sender interface for discord
// Sender implements moira sender interface for Discord.
// Use NewSender to create instance.
type Sender struct {
DataBase moira.Database
logger moira.Logger
Expand All @@ -26,16 +27,20 @@ type Sender struct {
botUserID string
}

// Init reads the yaml config
func (sender *Sender) Init(senderSettings map[string]string, logger moira.Logger, location *time.Location, dateTimeFormat string) error {
// NewSender creates Sender instance.
func NewSender(senderSettings map[string]string, logger moira.Logger, location *time.Location, db moira.Database) (*Sender, error) {
sender := &Sender{
DataBase: db,
}

var err error
token := senderSettings["token"]
if token == "" {
return fmt.Errorf("cannot read the discord token from the config")
return nil, fmt.Errorf("cannot read the discord token from the config")
}
sender.session, err = discordgo.New("Bot " + token)
if err != nil {
return fmt.Errorf("error creating discord session: %s", err)
return nil, fmt.Errorf("error creating discord session: %s", err)
}
sender.logger = logger
sender.frontURI = senderSettings["front_uri"]
Expand All @@ -56,7 +61,8 @@ func (sender *Sender) Init(senderSettings map[string]string, logger moira.Logger
sender.session.AddHandler(handleMsg)

go sender.runBot()
return nil

return sender, nil
}

func (sender *Sender) runBot() {
Expand Down
14 changes: 7 additions & 7 deletions senders/discord/init_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,30 @@ type MockLock struct {
moira.Lock
}

func (lock *MockLock) Acquire(stop <-chan struct{}) (lost <-chan struct{}, error error) {
func (lock *MockLock) Acquire(<-chan struct{}) (lost <-chan struct{}, error error) {
return lost, nil
}
func (db *MockDB) NewLock(name string, ttl time.Duration) moira.Lock {
func (db *MockDB) NewLock(string, time.Duration) moira.Lock {
return &MockLock{}
}

func TestInit(t *testing.T) {
func TestNewSender(t *testing.T) {
logger, _ := logging.ConfigureLog("stdout", "debug", "test", true)
location, _ := time.LoadLocation("UTC")
Convey("Init tests", t, func() {
sender := Sender{DataBase: &MockDB{}}
Convey("Empty map", func() {
err := sender.Init(map[string]string{}, logger, nil, "")
sender, err := NewSender(map[string]string{}, logger, nil, &MockDB{})
So(err, ShouldResemble, fmt.Errorf("cannot read the discord token from the config"))
So(sender, ShouldResemble, Sender{DataBase: &MockDB{}})
So(sender, ShouldBeNil)
})

Convey("Has settings", func() {
senderSettings := map[string]string{
"token": "123",
"front_uri": "http://moira.uri",
}
sender.Init(senderSettings, logger, location, "15:04") //nolint
sender, err := NewSender(senderSettings, logger, location, &MockDB{})
So(err, ShouldBeNil)
So(sender.frontURI, ShouldResemble, "http://moira.uri")
So(sender.session.Token, ShouldResemble, "Bot 123")
So(sender.logger, ShouldResemble, logger)
Expand Down
19 changes: 13 additions & 6 deletions senders/mail/mail.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import (
"github.com/moira-alert/moira"
)

// Sender implements moira sender interface via pushover
// Sender implements moira sender interface via Email.
// Use NewSender to create instance.
type Sender struct {
From string
SMTPHello string
Expand All @@ -30,18 +31,24 @@ type Sender struct {
dateTimeFormat string
}

// Init read yaml config
func (sender *Sender) Init(senderSettings map[string]string, logger moira.Logger, location *time.Location, dateTimeFormat string) error {
// NewSender creates Sender instance.
func NewSender(senderSettings map[string]string, logger moira.Logger, location *time.Location, dateTimeFormat string) (*Sender, error) {
sender := &Sender{}

err := sender.fillSettings(senderSettings, logger, location, dateTimeFormat)
if err != nil {
return err
return nil, err
}
sender.TemplateName, sender.Template, err = parseTemplate(sender.TemplateFile)
if err != nil {
return err
return nil, err
}
err = sender.tryDial()
return err
if err != nil {
return nil, err
}

return sender, nil
}

func (sender *Sender) fillSettings(senderSettings map[string]string, logger moira.Logger, location *time.Location, dateTimeFormat string) error {
Expand Down
16 changes: 10 additions & 6 deletions senders/msteams/msteams.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ var headers = map[string]string{
"Content-Type": "application/json",
}

// Sender implements moira sender interface via MS Teams
// Sender implements moira sender interface via MS Teams.
// Use NewSender to create instance.
type Sender struct {
frontURI string
maxEvents int
Expand All @@ -44,24 +45,27 @@ type Sender struct {
client *http.Client
}

// Init initialises settings required for full functionality
func (sender *Sender) Init(senderSettings map[string]string, logger moira.Logger, location *time.Location, dateTimeFormat string) error {
// NewSender creates Sender instance.
func NewSender(senderSettings map[string]string, logger moira.Logger, location *time.Location) (*Sender, error) {
sender := &Sender{}

sender.logger = logger
sender.location = location
sender.frontURI = senderSettings["front_uri"]
maxEvents, err := strconv.Atoi(senderSettings["max_events"])
if err != nil {
return fmt.Errorf("max_events should be an integer: %w", err)
return nil, fmt.Errorf("max_events should be an integer: %w", err)
}
sender.maxEvents = maxEvents
sender.client = &http.Client{
Timeout: time.Duration(30) * time.Second, //nolint
}
return nil

return sender, nil
}

// SendEvents implements Sender interface Send
func (sender *Sender) SendEvents(events moira.NotificationEvents, contact moira.ContactData, trigger moira.TriggerData, plots [][]byte, throttled bool) error {
func (sender *Sender) SendEvents(events moira.NotificationEvents, contact moira.ContactData, trigger moira.TriggerData, _ [][]byte, throttled bool) error {
err := sender.isValidWebhookURL(contact.Value)
if err != nil {
return err
Expand Down
Loading

0 comments on commit f7efa24

Please sign in to comment.