diff --git a/mock/notifier/mattermost/client.go b/mock/notifier/mattermost/client.go index 8b066cd49..3407b00bd 100644 --- a/mock/notifier/mattermost/client.go +++ b/mock/notifier/mattermost/client.go @@ -61,3 +61,19 @@ func (mr *MockClientMockRecorder) SetToken(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetToken", reflect.TypeOf((*MockClient)(nil).SetToken), arg0) } + +// UploadFile mocks base method. +func (m *MockClient) UploadFile(arg0 []byte, arg1, arg2 string) (*model.FileUploadResponse, *model.Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UploadFile", arg0, arg1, arg2) + ret0, _ := ret[0].(*model.FileUploadResponse) + ret1, _ := ret[1].(*model.Response) + ret2, _ := ret[2].(error) + return ret0, ret1, ret2 +} + +// UploadFile indicates an expected call of UploadFile. +func (mr *MockClientMockRecorder) UploadFile(arg0, arg1, arg2 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UploadFile", reflect.TypeOf((*MockClient)(nil).UploadFile), arg0, arg1, arg2) +} diff --git a/senders/mattermost/client.go b/senders/mattermost/client.go index 60a0b4e74..b91163b15 100644 --- a/senders/mattermost/client.go +++ b/senders/mattermost/client.go @@ -6,4 +6,5 @@ import "github.com/mattermost/mattermost-server/v6/model" type Client interface { SetToken(token string) CreatePost(post *model.Post) (*model.Post, *model.Response, error) + UploadFile(data []byte, channelId string, filename string) (*model.FileUploadResponse, *model.Response, error) } diff --git a/senders/mattermost/sender.go b/senders/mattermost/sender.go index e4079daa7..52ec2e25e 100644 --- a/senders/mattermost/sender.go +++ b/senders/mattermost/sender.go @@ -28,6 +28,7 @@ type mattermost struct { // You must call Init method before SendEvents method. type Sender struct { frontURI string + logger moira.Logger location *time.Location client Client } @@ -70,17 +71,28 @@ func (sender *Sender) Init(senderSettings interface{}, logger moira.Logger, loca } sender.frontURI = frontURI sender.location = location + sender.logger = logger return nil } // SendEvents implements moira.Sender interface. -func (sender *Sender) SendEvents(events moira.NotificationEvents, contact moira.ContactData, trigger moira.TriggerData, _ [][]byte, throttled bool) error { +func (sender *Sender) SendEvents(events moira.NotificationEvents, contact moira.ContactData, trigger moira.TriggerData, plots [][]byte, throttled bool) error { message := sender.buildMessage(events, trigger, throttled) - err := sender.sendMessage(message, contact.Value, trigger.ID) + post, err := sender.sendMessage(message, contact.Value, trigger.ID) if err != nil { return err } + if len(plots) > 0 { + err = sender.sendPlots(plots, contact.Value, post.Id, trigger.ID) + if err != nil { + sender.logger.Warning(). + String("trigger_id", trigger.ID). + String("contact_value", contact.Value). + String("contact_type", contact.Type). + Error(err) + } + } return nil } @@ -187,15 +199,45 @@ func (sender *Sender) buildEventsString(events moira.NotificationEvents, charsFo return eventsString } -func (sender *Sender) sendMessage(message string, contact string, triggerID string) error { +func (sender *Sender) sendMessage(message string, contact string, triggerID string) (*model.Post, error) { post := model.Post{ ChannelId: contact, Message: message, } - _, _, err := sender.client.CreatePost(&post) + sentPost, _, err := sender.client.CreatePost(&post) if err != nil { - return fmt.Errorf("failed to send %s event message to Mattermost [%s]: %s", triggerID, contact, err) + return nil, fmt.Errorf("failed to send %s event message to Mattermost [%s]: %s", triggerID, contact, err) + } + + return sentPost, nil +} + +func (sender *Sender) sendPlots(plots [][]byte, channelID, postID, triggerID string) error { + var filesID []string + + filename := fmt.Sprintf("%s.png", triggerID) + for _, plot := range plots { + file, _, err := sender.client.UploadFile(plot, channelID, filename) + if err != nil { + return err + } + for _, info := range file.FileInfos { + filesID = append(filesID, info.Id) + } + } + + if len(filesID) > 0 { + _, _, err := sender.client.CreatePost( + &model.Post{ + ChannelId: channelID, + RootId: postID, + FileIds: filesID, + }, + ) + if err != nil { + return err + } } return nil diff --git a/senders/mattermost/sender_internal_test.go b/senders/mattermost/sender_internal_test.go index 81dfcfa47..18b5950df 100644 --- a/senders/mattermost/sender_internal_test.go +++ b/senders/mattermost/sender_internal_test.go @@ -6,6 +6,8 @@ import ( "testing" "time" + "github.com/mattermost/mattermost-server/v6/model" + "github.com/moira-alert/moira" "github.com/golang/mock/gomock" @@ -39,16 +41,34 @@ func TestSendEvents(t *testing.T) { So(err, ShouldNotBeNil) }) - Convey("When client CreatePost is success, SendEvents should not return error", func() { + Convey("When client CreatePost is success and no plots, SendEvents should not return error", func() { ctrl := gomock.NewController(t) client := mock.NewMockClient(ctrl) - client.EXPECT().CreatePost(gomock.Any()).Return(nil, nil, nil) + client.EXPECT().CreatePost(gomock.Any()).Return(&model.Post{Id: "postID"}, nil, nil) sender.client = client events, contact, trigger, plots, throttled := moira.NotificationEvents{}, moira.ContactData{}, moira.TriggerData{}, make([][]byte, 0), false err = sender.SendEvents(events, contact, trigger, plots, throttled) So(err, ShouldBeNil) }) + + Convey("When client CreatePost is success and have succeeded sent plots, SendEvents should not return error", func() { + ctrl := gomock.NewController(t) + client := mock.NewMockClient(ctrl) + client.EXPECT().CreatePost(gomock.Any()).Return(&model.Post{Id: "postID"}, nil, nil).Times(2) + client.EXPECT().UploadFile(gomock.Any(), "contactDataID", "triggerID.png"). + Return( + &model.FileUploadResponse{ + FileInfos: []*model.FileInfo{{Id: "fileID"}}, + }, nil, nil) + sender.client = client + + plots := make([][]byte, 0) + plots = append(plots, []byte("my_awesome_plot")) + events, contact, trigger, throttled := moira.NotificationEvents{}, moira.ContactData{Value: "contactDataID"}, moira.TriggerData{ID: "triggerID"}, false + err = sender.SendEvents(events, contact, trigger, plots, throttled) + So(err, ShouldBeNil) + }) }) }