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