MM - 60506 - notify user failed scheduled msgs (#29208)

* MM-60506 - notify user for failed scheduled messages

* add unit tests for handleFailedScheduledMessages and send system-bot message

* fix vet issues

* adjust test for vet report

* make sure to send the message to every user there was a failed message

---------

Co-authored-by: Harshil Sharma <harshil.sharma@mattermost.com>
Этот коммит содержится в:
Pablo Vélez
2024-11-12 11:33:29 +01:00
коммит произвёл GitHub
родитель 5eef415a39
Коммит 4e0fc5734c
4 изменённых файлов: 248 добавлений и 0 удалений

Просмотреть файл

@@ -8,6 +8,7 @@ import (
"time"
"github.com/mattermost/mattermost/server/public/model"
"github.com/mattermost/mattermost/server/public/shared/i18n"
"github.com/stretchr/testify/assert"
)
@@ -262,3 +263,132 @@ func TestProcessScheduledPosts(t *testing.T) {
assert.Greater(t, scheduledPosts[1].ProcessedAt, int64(0))
})
}
func TestHandleFailedScheduledPosts(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
t.Run("should handle failed scheduled posts correctly and notify users about failure via system-bot", func(t *testing.T) {
rctx := th.Context
var err error
var appErr *model.AppError
var systemBot *model.Bot
systemBot, appErr = th.App.GetSystemBot(rctx)
assert.True(t, appErr == nil)
assert.NotNil(t, systemBot)
user1 := th.BasicUser
user2 := th.BasicUser2
// Create failed scheduled posts: 1 for user1 and 2 for user2
failedScheduledPosts := []*model.ScheduledPost{
{
Id: model.NewId(),
Draft: model.Draft{
CreateAt: model.GetMillis(),
UserId: user1.Id,
ChannelId: th.BasicChannel.Id,
Message: "Failed scheduled post for user 1",
},
ErrorCode: model.ScheduledPostErrorUnknownError,
},
{
Id: model.NewId(),
Draft: model.Draft{
CreateAt: model.GetMillis(),
UserId: user2.Id,
ChannelId: th.BasicChannel.Id,
Message: "Failed scheduled post 1 for user 2",
},
ErrorCode: model.ScheduledPostErrorCodeNoChannelPermission,
},
{
Id: model.NewId(),
Draft: model.Draft{
CreateAt: model.GetMillis(),
UserId: user2.Id,
ChannelId: th.BasicChannel.Id,
Message: "Failed scheduled post 2 for user 2",
},
ErrorCode: model.ScheduledPostErrorNoChannelMember,
},
}
// Save the failed scheduled posts in the store
for _, sp := range failedScheduledPosts {
_, err = th.Server.Store().ScheduledPost().CreateScheduledPost(sp)
assert.NoError(t, err)
}
// Mock WebSocket channels for both of the two users
messagesUser1, closeWSUser1 := connectFakeWebSocket(t, th, user1.Id, "", []model.WebsocketEventType{model.WebsocketScheduledPostUpdated})
defer closeWSUser1()
messagesUser2, closeWSUser2 := connectFakeWebSocket(t, th, user2.Id, "", []model.WebsocketEventType{model.WebsocketScheduledPostUpdated})
defer closeWSUser2()
th.App.handleFailedScheduledPosts(rctx, failedScheduledPosts)
// Validate that the WebSocket events for both users are sent and received correctly
for i := 0; i < len(failedScheduledPosts); i++ {
var received *model.WebSocketEvent
select {
case received = <-messagesUser1:
if received.GetBroadcast().UserId == user1.Id {
assert.Equal(t, model.WebsocketScheduledPostUpdated, received.EventType())
}
case received = <-messagesUser2:
if received.GetBroadcast().UserId == user2.Id {
assert.Equal(t, model.WebsocketScheduledPostUpdated, received.EventType())
}
case <-time.After(1 * time.Second):
t.Errorf("Timeout while waiting for a WebSocket event for scheduled post %d", i+1)
}
}
// Helper function to check notifications for a specific user
checkUserNotification := func(user *model.User, expectedCount int) {
// Wait time for notifications to be sent (adding 2 secs because it is run in a separate rountine)
var timeout = 2 * time.Second
begin := time.Now()
channel, appErr := th.App.GetOrCreateDirectChannel(rctx, user.Id, systemBot.UserId)
assert.True(t, appErr == nil)
var posts *model.PostList
// wait for the notification to be sent into the channel.
// idea is to get the channel and try to find posts, if not, wait 100ms and try again until timout or there is posts lengh
for {
if time.Since(begin) > timeout {
break
}
posts, appErr = th.App.GetPosts(channel.Id, 0, 10)
assert.True(t, appErr == nil)
if len(posts.Posts) > 0 {
break
}
time.Sleep(100 * time.Millisecond)
}
assert.NotEmpty(t, posts.Posts, "Expected notification for user %s to have been sent", user.Id)
// Validate the actual content of the notification posted (to include count verification)
T := i18n.GetUserTranslations(user.Locale)
messageContent := T("app.scheduled_post.failed_messages", map[string]interface{}{
"Count": expectedCount,
})
found := false
for _, post := range posts.Posts {
if post.UserId == systemBot.UserId && post.Message == messageContent {
found = true
break
}
}
assert.True(t, found, "Notification post not found for user %s with expected count %d", user.Id, expectedCount)
}
// Check notifications sent for failed messages for both users
checkUserNotification(user1, 1)
checkUserNotification(user2, 2)
})
}