github.com/mad-app/mattermost-server@v5.11.1+incompatible/store/storetest/reaction_store.go (about) 1 // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 4 package storetest 5 6 import ( 7 "testing" 8 9 "github.com/mattermost/mattermost-server/model" 10 "github.com/mattermost/mattermost-server/store" 11 ) 12 13 func TestReactionStore(t *testing.T, ss store.Store) { 14 t.Run("ReactionSave", func(t *testing.T) { testReactionSave(t, ss) }) 15 t.Run("ReactionDelete", func(t *testing.T) { testReactionDelete(t, ss) }) 16 t.Run("ReactionGetForPost", func(t *testing.T) { testReactionGetForPost(t, ss) }) 17 t.Run("ReactionDeleteAllWithEmojiName", func(t *testing.T) { testReactionDeleteAllWithEmojiName(t, ss) }) 18 t.Run("PermanentDeleteBatch", func(t *testing.T) { testReactionStorePermanentDeleteBatch(t, ss) }) 19 t.Run("ReactionBulkGetForPosts", func(t *testing.T) { testReactionBulkGetForPosts(t, ss) }) 20 } 21 22 func testReactionSave(t *testing.T, ss store.Store) { 23 post := store.Must(ss.Post().Save(&model.Post{ 24 ChannelId: model.NewId(), 25 UserId: model.NewId(), 26 })).(*model.Post) 27 firstUpdateAt := post.UpdateAt 28 29 reaction1 := &model.Reaction{ 30 UserId: model.NewId(), 31 PostId: post.Id, 32 EmojiName: model.NewId(), 33 } 34 if result := <-ss.Reaction().Save(reaction1); result.Err != nil { 35 t.Fatal(result.Err) 36 } else if saved := result.Data.(*model.Reaction); saved.UserId != reaction1.UserId || 37 saved.PostId != reaction1.PostId || saved.EmojiName != reaction1.EmojiName { 38 t.Fatal("should've saved reaction and returned it") 39 } 40 41 var secondUpdateAt int64 42 if postList := store.Must(ss.Post().Get(reaction1.PostId)).(*model.PostList); !postList.Posts[post.Id].HasReactions { 43 t.Fatal("should've set HasReactions = true on post") 44 } else if postList.Posts[post.Id].UpdateAt == firstUpdateAt { 45 t.Fatal("should've marked post as updated when HasReactions changed") 46 } else { 47 secondUpdateAt = postList.Posts[post.Id].UpdateAt 48 } 49 50 if result := <-ss.Reaction().Save(reaction1); result.Err != nil { 51 t.Log(result.Err) 52 t.Fatal("should've allowed saving a duplicate reaction") 53 } 54 55 // different user 56 reaction2 := &model.Reaction{ 57 UserId: model.NewId(), 58 PostId: reaction1.PostId, 59 EmojiName: reaction1.EmojiName, 60 } 61 if result := <-ss.Reaction().Save(reaction2); result.Err != nil { 62 t.Fatal(result.Err) 63 } 64 65 if postList := store.Must(ss.Post().Get(reaction2.PostId)).(*model.PostList); postList.Posts[post.Id].UpdateAt == secondUpdateAt { 66 t.Fatal("should've marked post as updated even if HasReactions doesn't change") 67 } 68 69 // different post 70 reaction3 := &model.Reaction{ 71 UserId: reaction1.UserId, 72 PostId: model.NewId(), 73 EmojiName: reaction1.EmojiName, 74 } 75 if result := <-ss.Reaction().Save(reaction3); result.Err != nil { 76 t.Fatal(result.Err) 77 } 78 79 // different emoji 80 reaction4 := &model.Reaction{ 81 UserId: reaction1.UserId, 82 PostId: reaction1.PostId, 83 EmojiName: model.NewId(), 84 } 85 if result := <-ss.Reaction().Save(reaction4); result.Err != nil { 86 t.Fatal(result.Err) 87 } 88 89 // invalid reaction 90 reaction5 := &model.Reaction{ 91 UserId: reaction1.UserId, 92 PostId: reaction1.PostId, 93 } 94 if result := <-ss.Reaction().Save(reaction5); result.Err == nil { 95 t.Fatal("should've failed for invalid reaction") 96 } 97 } 98 99 func testReactionDelete(t *testing.T, ss store.Store) { 100 post := store.Must(ss.Post().Save(&model.Post{ 101 ChannelId: model.NewId(), 102 UserId: model.NewId(), 103 })).(*model.Post) 104 105 reaction := &model.Reaction{ 106 UserId: model.NewId(), 107 PostId: post.Id, 108 EmojiName: model.NewId(), 109 } 110 111 store.Must(ss.Reaction().Save(reaction)) 112 firstUpdateAt := store.Must(ss.Post().Get(reaction.PostId)).(*model.PostList).Posts[post.Id].UpdateAt 113 114 if result := <-ss.Reaction().Delete(reaction); result.Err != nil { 115 t.Fatal(result.Err) 116 } 117 118 if result := <-ss.Reaction().GetForPost(post.Id, false); result.Err != nil { 119 t.Fatal(result.Err) 120 } else if len(result.Data.([]*model.Reaction)) != 0 { 121 t.Fatal("should've deleted reaction") 122 } 123 124 if postList := store.Must(ss.Post().Get(post.Id)).(*model.PostList); postList.Posts[post.Id].HasReactions { 125 t.Fatal("should've set HasReactions = false on post") 126 } else if postList.Posts[post.Id].UpdateAt == firstUpdateAt { 127 t.Fatal("should mark post as updated after deleting reactions") 128 } 129 } 130 131 func testReactionGetForPost(t *testing.T, ss store.Store) { 132 postId := model.NewId() 133 134 userId := model.NewId() 135 136 reactions := []*model.Reaction{ 137 { 138 UserId: userId, 139 PostId: postId, 140 EmojiName: "smile", 141 }, 142 { 143 UserId: model.NewId(), 144 PostId: postId, 145 EmojiName: "smile", 146 }, 147 { 148 UserId: userId, 149 PostId: postId, 150 EmojiName: "sad", 151 }, 152 { 153 UserId: userId, 154 PostId: model.NewId(), 155 EmojiName: "angry", 156 }, 157 } 158 159 for _, reaction := range reactions { 160 store.Must(ss.Reaction().Save(reaction)) 161 } 162 163 if result := <-ss.Reaction().GetForPost(postId, false); result.Err != nil { 164 t.Fatal(result.Err) 165 } else if returned := result.Data.([]*model.Reaction); len(returned) != 3 { 166 t.Fatal("should've returned 3 reactions") 167 } else { 168 for _, reaction := range reactions { 169 found := false 170 171 for _, returnedReaction := range returned { 172 if returnedReaction.UserId == reaction.UserId && returnedReaction.PostId == reaction.PostId && 173 returnedReaction.EmojiName == reaction.EmojiName { 174 found = true 175 break 176 } 177 } 178 179 if !found && reaction.PostId == postId { 180 t.Fatalf("should've returned reaction for post %v", reaction) 181 } else if found && reaction.PostId != postId { 182 t.Fatal("shouldn't have returned reaction for another post") 183 } 184 } 185 } 186 187 // Should return cached item 188 if result := <-ss.Reaction().GetForPost(postId, true); result.Err != nil { 189 t.Fatal(result.Err) 190 } else if returned := result.Data.([]*model.Reaction); len(returned) != 3 { 191 t.Fatal("should've returned 3 reactions") 192 } else { 193 for _, reaction := range reactions { 194 found := false 195 196 for _, returnedReaction := range returned { 197 if returnedReaction.UserId == reaction.UserId && returnedReaction.PostId == reaction.PostId && 198 returnedReaction.EmojiName == reaction.EmojiName { 199 found = true 200 break 201 } 202 } 203 204 if !found && reaction.PostId == postId { 205 t.Fatalf("should've returned reaction for post %v", reaction) 206 } else if found && reaction.PostId != postId { 207 t.Fatal("shouldn't have returned reaction for another post") 208 } 209 } 210 } 211 } 212 213 func testReactionDeleteAllWithEmojiName(t *testing.T, ss store.Store) { 214 emojiToDelete := model.NewId() 215 216 post := store.Must(ss.Post().Save(&model.Post{ 217 ChannelId: model.NewId(), 218 UserId: model.NewId(), 219 })).(*model.Post) 220 post2 := store.Must(ss.Post().Save(&model.Post{ 221 ChannelId: model.NewId(), 222 UserId: model.NewId(), 223 })).(*model.Post) 224 post3 := store.Must(ss.Post().Save(&model.Post{ 225 ChannelId: model.NewId(), 226 UserId: model.NewId(), 227 })).(*model.Post) 228 229 userId := model.NewId() 230 231 reactions := []*model.Reaction{ 232 { 233 UserId: userId, 234 PostId: post.Id, 235 EmojiName: emojiToDelete, 236 }, 237 { 238 UserId: model.NewId(), 239 PostId: post.Id, 240 EmojiName: emojiToDelete, 241 }, 242 { 243 UserId: userId, 244 PostId: post.Id, 245 EmojiName: "sad", 246 }, 247 { 248 UserId: userId, 249 PostId: post2.Id, 250 EmojiName: "angry", 251 }, 252 { 253 UserId: userId, 254 PostId: post3.Id, 255 EmojiName: emojiToDelete, 256 }, 257 } 258 259 for _, reaction := range reactions { 260 store.Must(ss.Reaction().Save(reaction)) 261 } 262 263 if result := <-ss.Reaction().DeleteAllWithEmojiName(emojiToDelete); result.Err != nil { 264 t.Fatal(result.Err) 265 } 266 267 // check that the reactions were deleted 268 if returned := store.Must(ss.Reaction().GetForPost(post.Id, false)).([]*model.Reaction); len(returned) != 1 { 269 t.Fatal("should've only removed reactions with emoji name") 270 } else { 271 for _, reaction := range returned { 272 if reaction.EmojiName == "smile" { 273 t.Fatal("should've removed reaction with emoji name") 274 } 275 } 276 } 277 278 if returned := store.Must(ss.Reaction().GetForPost(post2.Id, false)).([]*model.Reaction); len(returned) != 1 { 279 t.Fatal("should've only removed reactions with emoji name") 280 } 281 282 if returned := store.Must(ss.Reaction().GetForPost(post3.Id, false)).([]*model.Reaction); len(returned) != 0 { 283 t.Fatal("should've only removed reactions with emoji name") 284 } 285 286 // check that the posts are updated 287 if postList := store.Must(ss.Post().Get(post.Id)).(*model.PostList); !postList.Posts[post.Id].HasReactions { 288 t.Fatal("post should still have reactions") 289 } 290 291 if postList := store.Must(ss.Post().Get(post2.Id)).(*model.PostList); !postList.Posts[post2.Id].HasReactions { 292 t.Fatal("post should still have reactions") 293 } 294 295 if postList := store.Must(ss.Post().Get(post3.Id)).(*model.PostList); postList.Posts[post3.Id].HasReactions { 296 t.Fatal("post shouldn't have reactions any more") 297 } 298 } 299 300 func testReactionStorePermanentDeleteBatch(t *testing.T, ss store.Store) { 301 post := store.Must(ss.Post().Save(&model.Post{ 302 ChannelId: model.NewId(), 303 UserId: model.NewId(), 304 })).(*model.Post) 305 306 reactions := []*model.Reaction{ 307 { 308 UserId: model.NewId(), 309 PostId: post.Id, 310 EmojiName: "sad", 311 CreateAt: 1000, 312 }, 313 { 314 UserId: model.NewId(), 315 PostId: post.Id, 316 EmojiName: "sad", 317 CreateAt: 1500, 318 }, 319 { 320 UserId: model.NewId(), 321 PostId: post.Id, 322 EmojiName: "sad", 323 CreateAt: 2000, 324 }, 325 { 326 UserId: model.NewId(), 327 PostId: post.Id, 328 EmojiName: "sad", 329 CreateAt: 2000, 330 }, 331 } 332 333 // Need to hang on to a reaction to delete later in order to clear the cache, as "allowFromCache" isn't honoured any more. 334 var lastReaction *model.Reaction 335 for _, reaction := range reactions { 336 lastReaction = store.Must(ss.Reaction().Save(reaction)).(*model.Reaction) 337 } 338 339 if returned := store.Must(ss.Reaction().GetForPost(post.Id, false)).([]*model.Reaction); len(returned) != 4 { 340 t.Fatal("expected 4 reactions") 341 } 342 343 store.Must(ss.Reaction().PermanentDeleteBatch(1800, 1000)) 344 345 // This is to force a clear of the cache. 346 store.Must(ss.Reaction().Delete(lastReaction)) 347 348 if returned := store.Must(ss.Reaction().GetForPost(post.Id, false)).([]*model.Reaction); len(returned) != 1 { 349 t.Fatalf("expected 1 reaction. Got: %v", len(returned)) 350 } 351 } 352 353 func testReactionBulkGetForPosts(t *testing.T, ss store.Store) { 354 postId := model.NewId() 355 post2Id := model.NewId() 356 post3Id := model.NewId() 357 post4Id := model.NewId() 358 359 userId := model.NewId() 360 361 reactions := []*model.Reaction{ 362 { 363 UserId: userId, 364 PostId: postId, 365 EmojiName: "smile", 366 }, 367 { 368 UserId: model.NewId(), 369 PostId: post2Id, 370 EmojiName: "smile", 371 }, 372 { 373 UserId: userId, 374 PostId: post3Id, 375 EmojiName: "sad", 376 }, 377 { 378 UserId: userId, 379 PostId: postId, 380 EmojiName: "angry", 381 }, 382 { 383 UserId: userId, 384 PostId: post2Id, 385 EmojiName: "angry", 386 }, 387 { 388 UserId: userId, 389 PostId: post4Id, 390 EmojiName: "angry", 391 }, 392 } 393 394 for _, reaction := range reactions { 395 store.Must(ss.Reaction().Save(reaction)) 396 } 397 398 postIds := []string{postId, post2Id, post3Id} 399 if result := <-ss.Reaction().BulkGetForPosts(postIds); result.Err != nil { 400 t.Fatal(result.Err) 401 } else if returned := result.Data.([]*model.Reaction); len(returned) != 5 { 402 t.Fatal("should've returned 5 reactions") 403 } else { 404 post4IdFound := false 405 for _, reaction := range returned { 406 if reaction.PostId == post4Id { 407 post4IdFound = true 408 break 409 } 410 } 411 412 if post4IdFound { 413 t.Fatal("Wrong reaction returned") 414 } 415 } 416 417 }