github.com/jlevesy/mattermost-server@v5.3.2-0.20181003190404-7468f35cb0c8+incompatible/app/email_batching_test.go (about) 1 // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package app 5 6 import ( 7 "strings" 8 "testing" 9 "time" 10 11 "github.com/mattermost/mattermost-server/model" 12 "github.com/mattermost/mattermost-server/store" 13 ) 14 15 func TestHandleNewNotifications(t *testing.T) { 16 th := Setup() 17 defer th.TearDown() 18 19 id1 := model.NewId() 20 id2 := model.NewId() 21 id3 := model.NewId() 22 23 // test queueing of received posts by user 24 job := NewEmailBatchingJob(th.App, 128) 25 26 job.handleNewNotifications() 27 28 if len(job.pendingNotifications) != 0 { 29 t.Fatal("shouldn't have added any pending notifications") 30 } 31 32 job.Add(&model.User{Id: id1}, &model.Post{UserId: id1, Message: "test"}, &model.Team{Name: "team"}) 33 if len(job.pendingNotifications) != 0 { 34 t.Fatal("shouldn't have added any pending notifications") 35 } 36 37 job.handleNewNotifications() 38 if len(job.pendingNotifications) != 1 { 39 t.Fatal("should have received posts for 1 user") 40 } else if len(job.pendingNotifications[id1]) != 1 { 41 t.Fatal("should have received 1 post for user") 42 } 43 44 job.Add(&model.User{Id: id1}, &model.Post{UserId: id1, Message: "test"}, &model.Team{Name: "team"}) 45 job.handleNewNotifications() 46 if len(job.pendingNotifications) != 1 { 47 t.Fatal("should have received posts for 1 user") 48 } else if len(job.pendingNotifications[id1]) != 2 { 49 t.Fatal("should have received 2 posts for user1", job.pendingNotifications[id1]) 50 } 51 52 job.Add(&model.User{Id: id2}, &model.Post{UserId: id1, Message: "test"}, &model.Team{Name: "team"}) 53 job.handleNewNotifications() 54 if len(job.pendingNotifications) != 2 { 55 t.Fatal("should have received posts for 2 users") 56 } else if len(job.pendingNotifications[id1]) != 2 { 57 t.Fatal("should have received 2 posts for user1") 58 } else if len(job.pendingNotifications[id2]) != 1 { 59 t.Fatal("should have received 1 post for user2") 60 } 61 62 job.Add(&model.User{Id: id2}, &model.Post{UserId: id2, Message: "test"}, &model.Team{Name: "team"}) 63 job.Add(&model.User{Id: id1}, &model.Post{UserId: id3, Message: "test"}, &model.Team{Name: "team"}) 64 job.Add(&model.User{Id: id3}, &model.Post{UserId: id3, Message: "test"}, &model.Team{Name: "team"}) 65 job.Add(&model.User{Id: id2}, &model.Post{UserId: id2, Message: "test"}, &model.Team{Name: "team"}) 66 job.handleNewNotifications() 67 if len(job.pendingNotifications) != 3 { 68 t.Fatal("should have received posts for 3 users") 69 } else if len(job.pendingNotifications[id1]) != 3 { 70 t.Fatal("should have received 3 posts for user1") 71 } else if len(job.pendingNotifications[id2]) != 3 { 72 t.Fatal("should have received 3 posts for user2") 73 } else if len(job.pendingNotifications[id3]) != 1 { 74 t.Fatal("should have received 1 post for user3") 75 } 76 77 // test ordering of received posts 78 job = NewEmailBatchingJob(th.App, 128) 79 80 job.Add(&model.User{Id: id1}, &model.Post{UserId: id1, Message: "test1"}, &model.Team{Name: "team"}) 81 job.Add(&model.User{Id: id1}, &model.Post{UserId: id1, Message: "test2"}, &model.Team{Name: "team"}) 82 job.Add(&model.User{Id: id2}, &model.Post{UserId: id1, Message: "test3"}, &model.Team{Name: "team"}) 83 job.Add(&model.User{Id: id1}, &model.Post{UserId: id1, Message: "test4"}, &model.Team{Name: "team"}) 84 job.Add(&model.User{Id: id2}, &model.Post{UserId: id1, Message: "test5"}, &model.Team{Name: "team"}) 85 job.handleNewNotifications() 86 if job.pendingNotifications[id1][0].post.Message != "test1" || 87 job.pendingNotifications[id1][1].post.Message != "test2" || 88 job.pendingNotifications[id1][2].post.Message != "test4" { 89 t.Fatal("incorrect order of received posts for user1") 90 } else if job.pendingNotifications[id2][0].post.Message != "test3" || 91 job.pendingNotifications[id2][1].post.Message != "test5" { 92 t.Fatal("incorrect order of received posts for user2") 93 } 94 } 95 96 func TestCheckPendingNotifications(t *testing.T) { 97 th := Setup().InitBasic() 98 defer th.TearDown() 99 100 job := NewEmailBatchingJob(th.App, 128) 101 job.pendingNotifications[th.BasicUser.Id] = []*batchedNotification{ 102 { 103 post: &model.Post{ 104 UserId: th.BasicUser.Id, 105 ChannelId: th.BasicChannel.Id, 106 CreateAt: 10000000, 107 }, 108 teamName: th.BasicTeam.Name, 109 }, 110 } 111 112 channelMember := store.Must(th.App.Srv.Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)).(*model.ChannelMember) 113 channelMember.LastViewedAt = 9999999 114 store.Must(th.App.Srv.Store.Channel().UpdateMember(channelMember)) 115 116 store.Must(th.App.Srv.Store.Preference().Save(&model.Preferences{{ 117 UserId: th.BasicUser.Id, 118 Category: model.PREFERENCE_CATEGORY_NOTIFICATIONS, 119 Name: model.PREFERENCE_NAME_EMAIL_INTERVAL, 120 Value: "60", 121 }})) 122 123 // test that notifications aren't sent before interval 124 job.checkPendingNotifications(time.Unix(10001, 0), func(string, []*batchedNotification) {}) 125 126 if job.pendingNotifications[th.BasicUser.Id] == nil || len(job.pendingNotifications[th.BasicUser.Id]) != 1 { 127 t.Fatal("shouldn't have sent queued post") 128 } 129 130 // test that notifications are cleared if the user has acted 131 channelMember = store.Must(th.App.Srv.Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)).(*model.ChannelMember) 132 channelMember.LastViewedAt = 10001000 133 store.Must(th.App.Srv.Store.Channel().UpdateMember(channelMember)) 134 135 job.checkPendingNotifications(time.Unix(10002, 0), func(string, []*batchedNotification) {}) 136 137 if job.pendingNotifications[th.BasicUser.Id] != nil && len(job.pendingNotifications[th.BasicUser.Id]) != 0 { 138 t.Fatal("should've remove queued post since user acted") 139 } 140 141 // test that notifications are sent if enough time passes since the first message 142 job.pendingNotifications[th.BasicUser.Id] = []*batchedNotification{ 143 { 144 post: &model.Post{ 145 UserId: th.BasicUser.Id, 146 ChannelId: th.BasicChannel.Id, 147 CreateAt: 10060000, 148 Message: "post1", 149 }, 150 teamName: th.BasicTeam.Name, 151 }, 152 { 153 post: &model.Post{ 154 UserId: th.BasicUser.Id, 155 ChannelId: th.BasicChannel.Id, 156 CreateAt: 10090000, 157 Message: "post2", 158 }, 159 teamName: th.BasicTeam.Name, 160 }, 161 } 162 163 received := make(chan *model.Post, 2) 164 timeout := make(chan bool) 165 166 job.checkPendingNotifications(time.Unix(10130, 0), func(s string, notifications []*batchedNotification) { 167 for _, notification := range notifications { 168 received <- notification.post 169 } 170 }) 171 172 go func() { 173 // start a timeout to make sure that we don't get stuck here on a failed test 174 time.Sleep(5 * time.Second) 175 timeout <- true 176 }() 177 178 if job.pendingNotifications[th.BasicUser.Id] != nil && len(job.pendingNotifications[th.BasicUser.Id]) != 0 { 179 t.Fatal("should've remove queued posts when sending messages") 180 } 181 182 select { 183 case post := <-received: 184 if post.Message != "post1" { 185 t.Fatal("should've received post1 first") 186 } 187 case <-timeout: 188 t.Fatal("timed out waiting for first post notification") 189 } 190 191 select { 192 case post := <-received: 193 if post.Message != "post2" { 194 t.Fatal("should've received post2 second") 195 } 196 case <-timeout: 197 t.Fatal("timed out waiting for second post notification") 198 } 199 } 200 201 /** 202 * Ensures that email batch interval defaults to 15 minutes for users that haven't explicitly set this preference 203 */ 204 func TestCheckPendingNotificationsDefaultInterval(t *testing.T) { 205 th := Setup().InitBasic() 206 defer th.TearDown() 207 208 job := NewEmailBatchingJob(th.App, 128) 209 210 // bypasses recent user activity check 211 channelMember := store.Must(th.App.Srv.Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)).(*model.ChannelMember) 212 channelMember.LastViewedAt = 9999000 213 store.Must(th.App.Srv.Store.Channel().UpdateMember(channelMember)) 214 215 job.pendingNotifications[th.BasicUser.Id] = []*batchedNotification{ 216 { 217 post: &model.Post{ 218 UserId: th.BasicUser.Id, 219 ChannelId: th.BasicChannel.Id, 220 CreateAt: 10000000, 221 }, 222 teamName: th.BasicTeam.Name, 223 }, 224 } 225 226 // notifications should not be sent 1s after post was created, because default batch interval is 15mins 227 job.checkPendingNotifications(time.Unix(10001, 0), func(string, []*batchedNotification) {}) 228 if job.pendingNotifications[th.BasicUser.Id] == nil || len(job.pendingNotifications[th.BasicUser.Id]) != 1 { 229 t.Fatal("shouldn't have sent queued post") 230 } 231 232 // notifications should be sent 901s after post was created, because default batch interval is 15mins 233 job.checkPendingNotifications(time.Unix(10901, 0), func(string, []*batchedNotification) {}) 234 if job.pendingNotifications[th.BasicUser.Id] != nil || len(job.pendingNotifications[th.BasicUser.Id]) != 0 { 235 t.Fatal("should have sent queued post") 236 } 237 } 238 239 /** 240 * Ensures that email batch interval defaults to 15 minutes if user preference is invalid 241 */ 242 func TestCheckPendingNotificationsCantParseInterval(t *testing.T) { 243 th := Setup().InitBasic() 244 defer th.TearDown() 245 246 job := NewEmailBatchingJob(th.App, 128) 247 248 // bypasses recent user activity check 249 channelMember := store.Must(th.App.Srv.Store.Channel().GetMember(th.BasicChannel.Id, th.BasicUser.Id)).(*model.ChannelMember) 250 channelMember.LastViewedAt = 9999000 251 store.Must(th.App.Srv.Store.Channel().UpdateMember(channelMember)) 252 253 // preference value is not an integer, so we'll fall back to the default 15min value 254 store.Must(th.App.Srv.Store.Preference().Save(&model.Preferences{{ 255 UserId: th.BasicUser.Id, 256 Category: model.PREFERENCE_CATEGORY_NOTIFICATIONS, 257 Name: model.PREFERENCE_NAME_EMAIL_INTERVAL, 258 Value: "notAnIntegerValue", 259 }})) 260 261 job.pendingNotifications[th.BasicUser.Id] = []*batchedNotification{ 262 { 263 post: &model.Post{ 264 UserId: th.BasicUser.Id, 265 ChannelId: th.BasicChannel.Id, 266 CreateAt: 10000000, 267 }, 268 teamName: th.BasicTeam.Name, 269 }, 270 } 271 272 // notifications should not be sent 1s after post was created, because default batch interval is 15mins 273 job.checkPendingNotifications(time.Unix(10001, 0), func(string, []*batchedNotification) {}) 274 if job.pendingNotifications[th.BasicUser.Id] == nil || len(job.pendingNotifications[th.BasicUser.Id]) != 1 { 275 t.Fatal("shouldn't have sent queued post") 276 } 277 278 // notifications should be sent 901s after post was created, because default batch interval is 15mins 279 job.checkPendingNotifications(time.Unix(10901, 0), func(string, []*batchedNotification) {}) 280 if job.pendingNotifications[th.BasicUser.Id] != nil || len(job.pendingNotifications[th.BasicUser.Id]) != 0 { 281 t.Fatal("should have sent queued post") 282 } 283 } 284 285 /* 286 * Ensures that post contents are not included in notification email when email notification content type is set to generic 287 */ 288 func TestRenderBatchedPostGeneric(t *testing.T) { 289 th := Setup() 290 defer th.TearDown() 291 292 var post = &model.Post{} 293 post.Message = "This is the message" 294 var notification = &batchedNotification{} 295 notification.post = post 296 var channel = &model.Channel{} 297 channel.DisplayName = "Some Test Channel" 298 var sender = &model.User{} 299 sender.Email = "sender@test.com" 300 301 translateFunc := func(translationID string, args ...interface{}) string { 302 // mock translateFunc just returns the translation id - this is good enough for our purposes 303 return translationID 304 } 305 306 var rendered = th.App.renderBatchedPost(notification, channel, sender, "http://localhost:8065", "", translateFunc, "en", model.EMAIL_NOTIFICATION_CONTENTS_GENERIC) 307 if strings.Contains(rendered, post.Message) { 308 t.Fatal("Rendered email should not contain post contents when email notification contents type is set to Generic.") 309 } 310 } 311 312 /* 313 * Ensures that post contents included in notification email when email notification content type is set to full 314 */ 315 func TestRenderBatchedPostFull(t *testing.T) { 316 th := Setup() 317 defer th.TearDown() 318 319 var post = &model.Post{} 320 post.Message = "This is the message" 321 var notification = &batchedNotification{} 322 notification.post = post 323 var channel = &model.Channel{} 324 channel.DisplayName = "Some Test Channel" 325 var sender = &model.User{} 326 sender.Email = "sender@test.com" 327 328 translateFunc := func(translationID string, args ...interface{}) string { 329 // mock translateFunc just returns the translation id - this is good enough for our purposes 330 return translationID 331 } 332 333 var rendered = th.App.renderBatchedPost(notification, channel, sender, "http://localhost:8065", "", translateFunc, "en", model.EMAIL_NOTIFICATION_CONTENTS_FULL) 334 if !strings.Contains(rendered, post.Message) { 335 t.Fatal("Rendered email should contain post contents when email notification contents type is set to Full.") 336 } 337 }