Skip to content

Commit

Permalink
chore: refactor - add ReportDispatcher (#86)
Browse files Browse the repository at this point in the history
* chore: refactor - add ReportDispatcher

* chore: added MutesManager.IsEntryMuted

* chore: SendReport -> SendReportEntry

* chore: moved muting to ReportDispatcher

* chore: add tests for ReportDispatcher

* chore: fixed linting

* chore: more tests
  • Loading branch information
freak12techno committed May 12, 2024
1 parent aa15dc7 commit 3338726
Show file tree
Hide file tree
Showing 9 changed files with 327 additions and 99 deletions.
64 changes: 22 additions & 42 deletions pkg/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ import (
)

type App struct {
Logger *zerolog.Logger
Config *types.Config
StateManager *state.Manager
MutesManager *mutes.Manager
ReportGenerator *report.Generator
StateGenerator *state.Generator
Reporters []reportersPkg.Reporter
Logger *zerolog.Logger
Config *types.Config
StateManager *state.Manager
ReportGenerator *report.Generator
StateGenerator *state.Generator
ReportDispatcher *report.Dispatcher
}

func NewApp(configPath string, filesystem fs.FS, version string) *App {
Expand All @@ -47,31 +46,27 @@ func NewApp(configPath string, filesystem fs.FS, version string) *App {

timeZone, _ := time.LoadLocation(config.Timezone)

reporters := []reportersPkg.Reporter{
pagerduty.NewPagerDutyReporter(config.PagerDutyConfig, log),
telegram.NewTelegramReporter(config.TelegramConfig, mutesManager, stateGenerator, dataManager, log, version, timeZone),
}

reportDispatcher := report.NewDispatcher(log, mutesManager, reporters)

return &App{
Logger: log,
Config: config,
StateManager: stateManager,
MutesManager: mutesManager,
ReportGenerator: reportGenerator,
StateGenerator: stateGenerator,
Reporters: []reportersPkg.Reporter{
pagerduty.NewPagerDutyReporter(config.PagerDutyConfig, log),
telegram.NewTelegramReporter(config.TelegramConfig, mutesManager, stateGenerator, dataManager, log, version, timeZone),
},
Logger: log,
Config: config,
StateManager: stateManager,
ReportGenerator: reportGenerator,
StateGenerator: stateGenerator,
ReportDispatcher: reportDispatcher,
}
}

func (a *App) Start() {
a.StateManager.Load()
a.MutesManager.Load()

for _, reporter := range a.Reporters {
if err := reporter.Init(); err != nil {
a.Logger.Fatal().Err(err).Str("name", reporter.Name()).Msg("Error initializing reporter")
}
if reporter.Enabled() {
a.Logger.Info().Str("name", reporter.Name()).Msg("Init reporter")
}
if err := a.ReportDispatcher.Init(); err != nil {
a.Logger.Panic().Err(err).Msg("Error initializing reporters")
}

c := cron.New()
Expand All @@ -89,20 +84,5 @@ func (a *App) Start() {
func (a *App) Report() {
newState := a.StateGenerator.GetState(a.StateManager.State)
generatedReport := a.ReportGenerator.GenerateReport(a.StateManager.State, newState)

if generatedReport.Empty() {
a.Logger.Debug().Msg("Empty report, not sending.")
return
}

a.Logger.Debug().Int("len", len(generatedReport.Entries)).Msg("Got non-empty report")

for _, reporter := range a.Reporters {
if reporter.Enabled() {
a.Logger.Debug().Str("name", reporter.Name()).Msg("Sending report...")
if err := reporter.SendReport(generatedReport); err != nil {
a.Logger.Error().Err(err).Str("name", reporter.Name()).Msg("Failed to send report")
}
}
}
a.ReportDispatcher.SendReport(generatedReport)
}
12 changes: 10 additions & 2 deletions pkg/mutes/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package mutesmanager
import (
"encoding/json"
"main/pkg/fs"
"main/pkg/report/entry"
"main/pkg/utils"

"github.com/rs/zerolog"
Expand Down Expand Up @@ -59,12 +60,19 @@ func (m *Manager) Save() {
}
}

func (m *Manager) IsMuted(chain string, proposalID string) bool {
func (m *Manager) IsEntryMuted(reportEntry entry.ReportEntry) bool {
entryConverted, ok := reportEntry.(entry.ReportEntryNotError)
if !ok {
return false
}

if m.MutesPath == "" {
return false
}

return m.Mutes.IsMuted(chain, proposalID)
chain := entryConverted.GetChain()
proposal := entryConverted.GetProposal()
return m.Mutes.IsMuted(chain.Name, proposal.ID)
}

func (m *Manager) AddMute(mute *Mute) {
Expand Down
31 changes: 28 additions & 3 deletions pkg/mutes/manager_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package mutesmanager

import (
"main/pkg/events"
"main/pkg/fs"
"main/pkg/logger"
"main/pkg/types"
"testing"
"time"

Expand Down Expand Up @@ -110,8 +112,14 @@ func TestMuteManagerAddMuteIsMuted(t *testing.T) {
Expires: time.Now().Add(time.Hour),
})

assert.True(t, manager.IsMuted("chain", "proposal"))
assert.False(t, manager.IsMuted("chain2", "proposal"))
assert.True(t, manager.IsEntryMuted(events.VotedEvent{
Chain: &types.Chain{Name: "chain"},
Proposal: types.Proposal{ID: "proposal"},
}))
assert.False(t, manager.IsEntryMuted(events.VotedEvent{
Chain: &types.Chain{Name: "chain2"},
Proposal: types.Proposal{ID: "proposal"},
}))
}

func TestMuteManagerIsMutedNoPath(t *testing.T) {
Expand All @@ -128,5 +136,22 @@ func TestMuteManagerIsMutedNoPath(t *testing.T) {
Expires: time.Now().Add(time.Hour),
})

assert.False(t, manager.IsMuted("chain", "proposal"))
assert.False(t, manager.IsEntryMuted(events.VotedEvent{
Chain: &types.Chain{Name: "chain"},
Proposal: types.Proposal{ID: "proposal"},
}))
}

func TestMuteManagerIsNotAlert(t *testing.T) {
t.Parallel()

log := logger.GetNopLogger()
filesystem := &fs.TestFS{}

manager := NewMutesManager("", filesystem, log)
manager.Load()

assert.False(t, manager.IsEntryMuted(events.ProposalsQueryErrorEvent{
Chain: &types.Chain{Name: "chain"},
}))
}
83 changes: 83 additions & 0 deletions pkg/report/dispatcher.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package report

import (
mutes "main/pkg/mutes"
reportersPkg "main/pkg/reporters"

"github.com/rs/zerolog"
)

type Dispatcher struct {
Logger zerolog.Logger
MutesManager *mutes.Manager
Reporters []reportersPkg.Reporter
}

func NewDispatcher(
logger *zerolog.Logger,
mutesManager *mutes.Manager,
reporters []reportersPkg.Reporter,
) *Dispatcher {
return &Dispatcher{
Logger: logger.With().Str("component", "report_dispatcher").Logger(),
MutesManager: mutesManager,
Reporters: reporters,
}
}

func (d *Dispatcher) Init() error {
d.MutesManager.Load()

for _, reporter := range d.Reporters {
if err := reporter.Init(); err != nil {
d.Logger.Error().Err(err).
Str("name", reporter.Name()).
Msg("Error initializing reporter")
return err
}
if reporter.Enabled() {
d.Logger.Info().Str("name", reporter.Name()).Msg("Init reporter")
}
}

return nil
}

func (d *Dispatcher) SendReport(report reportersPkg.Report) {
if report.Empty() {
d.Logger.Debug().Msg("Empty report, not sending.")
return
}

d.Logger.Debug().Int("len", len(report.Entries)).Msg("Got non-empty report")

for _, reporter := range d.Reporters {
if !reporter.Enabled() {
d.Logger.Debug().
Str("name", reporter.Name()).
Msg("Reporter is disabled, not sending report")
continue
}

d.Logger.Debug().
Str("name", reporter.Name()).
Msg("Sending report...")

for _, reportEntry := range report.Entries {
if d.MutesManager.IsEntryMuted(reportEntry) {
d.Logger.Debug().
Str("entry", reportEntry.Name()).
Msg("Notifications are muted, not sending.")
continue
}

if err := reporter.SendReportEntry(reportEntry); err != nil {
d.Logger.Error().
Err(err).
Str("name", reporter.Name()).
Str("entry", reportEntry.Name()).
Msg("Failed to send report entry")
}
}
}
}
122 changes: 122 additions & 0 deletions pkg/report/dispatcher_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
package report

import (
"main/pkg/events"
"main/pkg/fs"
"main/pkg/logger"
mutes "main/pkg/mutes"
"main/pkg/report/entry"
reportersPkg "main/pkg/reporters"
"main/pkg/types"
"testing"
"time"

"github.com/stretchr/testify/require"
)

func TestReportDispatcherInitFail(t *testing.T) {
t.Parallel()

mutesManager := mutes.NewMutesManager("./state.json", &fs.TestFS{}, logger.GetNopLogger())
dispatcher := NewDispatcher(logger.GetNopLogger(), mutesManager, []reportersPkg.Reporter{
&reportersPkg.TestReporter{WithInitFail: true},
})

err := dispatcher.Init()
require.Error(t, err)
}

func TestReportDispatcherInitOk(t *testing.T) {
t.Parallel()

mutesManager := mutes.NewMutesManager("./state.json", &fs.TestFS{}, logger.GetNopLogger())
dispatcher := NewDispatcher(logger.GetNopLogger(), mutesManager, []reportersPkg.Reporter{
&reportersPkg.TestReporter{},
})

err := dispatcher.Init()
require.NoError(t, err)
}

func TestReportDispatcherSendEmptyReport(t *testing.T) {
t.Parallel()

mutesManager := mutes.NewMutesManager("./state.json", &fs.TestFS{}, logger.GetNopLogger())
dispatcher := NewDispatcher(logger.GetNopLogger(), mutesManager, []reportersPkg.Reporter{
&reportersPkg.TestReporter{},
})

err := dispatcher.Init()
require.NoError(t, err)

dispatcher.SendReport(reportersPkg.Report{Entries: make([]entry.ReportEntry, 0)})
}

func TestReportDispatcherSendReportDisabledReporter(t *testing.T) {
t.Parallel()

mutesManager := mutes.NewMutesManager("./state.json", &fs.TestFS{}, logger.GetNopLogger())
dispatcher := NewDispatcher(logger.GetNopLogger(), mutesManager, []reportersPkg.Reporter{
&reportersPkg.TestReporter{WithDisabled: true},
})

err := dispatcher.Init()
require.NoError(t, err)

dispatcher.SendReport(reportersPkg.Report{Entries: []entry.ReportEntry{
events.ProposalsQueryErrorEvent{},
}})
}

func TestReportDispatcherSendReportMuted(t *testing.T) {
t.Parallel()

mutesManager := mutes.NewMutesManager("./state.json", &fs.TestFS{}, logger.GetNopLogger())
dispatcher := NewDispatcher(logger.GetNopLogger(), mutesManager, []reportersPkg.Reporter{
&reportersPkg.TestReporter{},
})

err := dispatcher.Init()
require.NoError(t, err)

mutesManager.AddMute(&mutes.Mute{Expires: time.Now().Add(time.Minute)})

dispatcher.SendReport(reportersPkg.Report{Entries: []entry.ReportEntry{
events.NotVotedEvent{
Chain: &types.Chain{Name: "chain"},
Proposal: types.Proposal{ID: "proposal"},
},
}})
}

func TestReportDispatcherSendReportErrorSending(t *testing.T) {
t.Parallel()

mutesManager := mutes.NewMutesManager("./state.json", &fs.TestFS{}, logger.GetNopLogger())
dispatcher := NewDispatcher(logger.GetNopLogger(), mutesManager, []reportersPkg.Reporter{
&reportersPkg.TestReporter{WithErrorSending: true},
})

err := dispatcher.Init()
require.NoError(t, err)

dispatcher.SendReport(reportersPkg.Report{Entries: []entry.ReportEntry{
events.ProposalsQueryErrorEvent{},
}})
}

func TestReportDispatcherSendReportOk(t *testing.T) {
t.Parallel()

mutesManager := mutes.NewMutesManager("./state.json", &fs.TestFS{}, logger.GetNopLogger())
dispatcher := NewDispatcher(logger.GetNopLogger(), mutesManager, []reportersPkg.Reporter{
&reportersPkg.TestReporter{},
})

err := dispatcher.Init()
require.NoError(t, err)

dispatcher.SendReport(reportersPkg.Report{Entries: []entry.ReportEntry{
events.ProposalsQueryErrorEvent{},
}})
}
Loading

0 comments on commit 3338726

Please sign in to comment.