github.com/qichengzx/mattermost-server@v4.5.1-0.20180604164826-2c75247c97d0+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 } 20 21 func testReactionSave(t *testing.T, ss store.Store) { 22 post := store.Must(ss.Post().Save(&model.Post{ 23 ChannelId: model.NewId(), 24 UserId: model.NewId(), 25 })).(*model.Post) 26 firstUpdateAt := post.UpdateAt 27 28 reaction1 := &model.Reaction{ 29 UserId: model.NewId(), 30 PostId: post.Id, 31 EmojiName: model.NewId(), 32 } 33 if result := <-ss.Reaction().Save(reaction1); result.Err != nil { 34 t.Fatal(result.Err) 35 } else if saved := result.Data.(*model.Reaction); saved.UserId != reaction1.UserId || 36 saved.PostId != reaction1.PostId || saved.EmojiName != reaction1.EmojiName { 37 t.Fatal("should've saved reaction and returned it") 38 } 39 40 var secondUpdateAt int64 41 if postList := store.Must(ss.Post().Get(reaction1.PostId)).(*model.PostList); !postList.Posts[post.Id].HasReactions { 42 t.Fatal("should've set HasReactions = true on post") 43 } else if postList.Posts[post.Id].UpdateAt == firstUpdateAt { 44 t.Fatal("should've marked post as updated when HasReactions changed") 45 } else { 46 secondUpdateAt = postList.Posts[post.Id].UpdateAt 47 } 48 49 if result := <-ss.Reaction().Save(reaction1); result.Err != nil { 50 t.Log(result.Err) 51 t.Fatal("should've allowed saving a duplicate reaction") 52 } 53 54 // different user 55 reaction2 := &model.Reaction{ 56 UserId: model.NewId(), 57 PostId: reaction1.PostId, 58 EmojiName: reaction1.EmojiName, 59 } 60 if result := <-ss.Reaction().Save(reaction2); result.Err != nil { 61 t.Fatal(result.Err) 62 } 63 64 if postList := store.Must(ss.Post().Get(reaction2.PostId)).(*model.PostList); postList.Posts[post.Id].UpdateAt != secondUpdateAt { 65 t.Fatal("shouldn't mark as updated when HasReactions hasn't changed") 66 } 67 68 // different post 69 reaction3 := &model.Reaction{ 70 UserId: reaction1.UserId, 71 PostId: model.NewId(), 72 EmojiName: reaction1.EmojiName, 73 } 74 if result := <-ss.Reaction().Save(reaction3); result.Err != nil { 75 t.Fatal(result.Err) 76 } 77 78 // different emoji 79 reaction4 := &model.Reaction{ 80 UserId: reaction1.UserId, 81 PostId: reaction1.PostId, 82 EmojiName: model.NewId(), 83 } 84 if result := <-ss.Reaction().Save(reaction4); result.Err != nil { 85 t.Fatal(result.Err) 86 } 87 88 // invalid reaction 89 reaction5 := &model.Reaction{ 90 UserId: reaction1.UserId, 91 PostId: reaction1.PostId, 92 } 93 if result := <-ss.Reaction().Save(reaction5); result.Err == nil { 94 t.Fatal("should've failed for invalid reaction") 95 } 96 } 97 98 func testReactionDelete(t *testing.T, ss store.Store) { 99 post := store.Must(ss.Post().Save(&model.Post{ 100 ChannelId: model.NewId(), 101 UserId: model.NewId(), 102 })).(*model.Post) 103 104 reaction := &model.Reaction{ 105 UserId: model.NewId(), 106 PostId: post.Id, 107 EmojiName: model.NewId(), 108 } 109 110 store.Must(ss.Reaction().Save(reaction)) 111 firstUpdateAt := store.Must(ss.Post().Get(reaction.PostId)).(*model.PostList).Posts[post.Id].UpdateAt 112 113 if result := <-ss.Reaction().Delete(reaction); result.Err != nil { 114 t.Fatal(result.Err) 115 } 116 117 if result := <-ss.Reaction().GetForPost(post.Id, false); result.Err != nil { 118 t.Fatal(result.Err) 119 } else if len(result.Data.([]*model.Reaction)) != 0 { 120 t.Fatal("should've deleted reaction") 121 } 122 123 if postList := store.Must(ss.Post().Get(post.Id)).(*model.PostList); postList.Posts[post.Id].HasReactions { 124 t.Fatal("should've set HasReactions = false on post") 125 } else if postList.Posts[post.Id].UpdateAt == firstUpdateAt { 126 t.Fatal("shouldn't mark as updated when HasReactions has changed after deleting reactions") 127 } 128 } 129 130 func testReactionGetForPost(t *testing.T, ss store.Store) { 131 postId := model.NewId() 132 133 userId := model.NewId() 134 135 reactions := []*model.Reaction{ 136 { 137 UserId: userId, 138 PostId: postId, 139 EmojiName: "smile", 140 }, 141 { 142 UserId: model.NewId(), 143 PostId: postId, 144 EmojiName: "smile", 145 }, 146 { 147 UserId: userId, 148 PostId: postId, 149 EmojiName: "sad", 150 }, 151 { 152 UserId: userId, 153 PostId: model.NewId(), 154 EmojiName: "angry", 155 }, 156 } 157 158 for _, reaction := range reactions { 159 store.Must(ss.Reaction().Save(reaction)) 160 } 161 162 if result := <-ss.Reaction().GetForPost(postId, false); result.Err != nil { 163 t.Fatal(result.Err) 164 } else if returned := result.Data.([]*model.Reaction); len(returned) != 3 { 165 t.Fatal("should've returned 3 reactions") 166 } else { 167 for _, reaction := range reactions { 168 found := false 169 170 for _, returnedReaction := range returned { 171 if returnedReaction.UserId == reaction.UserId && returnedReaction.PostId == reaction.PostId && 172 returnedReaction.EmojiName == reaction.EmojiName { 173 found = true 174 break 175 } 176 } 177 178 if !found && reaction.PostId == postId { 179 t.Fatalf("should've returned reaction for post %v", reaction) 180 } else if found && reaction.PostId != postId { 181 t.Fatal("shouldn't have returned reaction for another post") 182 } 183 } 184 } 185 186 // Should return cached item 187 if result := <-ss.Reaction().GetForPost(postId, true); result.Err != nil { 188 t.Fatal(result.Err) 189 } else if returned := result.Data.([]*model.Reaction); len(returned) != 3 { 190 t.Fatal("should've returned 3 reactions") 191 } else { 192 for _, reaction := range reactions { 193 found := false 194 195 for _, returnedReaction := range returned { 196 if returnedReaction.UserId == reaction.UserId && returnedReaction.PostId == reaction.PostId && 197 returnedReaction.EmojiName == reaction.EmojiName { 198 found = true 199 break 200 } 201 } 202 203 if !found && reaction.PostId == postId { 204 t.Fatalf("should've returned reaction for post %v", reaction) 205 } else if found && reaction.PostId != postId { 206 t.Fatal("shouldn't have returned reaction for another post") 207 } 208 } 209 } 210 } 211 212 func testReactionDeleteAllWithEmojiName(t *testing.T, ss store.Store) { 213 emojiToDelete := model.NewId() 214 215 post := store.Must(ss.Post().Save(&model.Post{ 216 ChannelId: model.NewId(), 217 UserId: model.NewId(), 218 })).(*model.Post) 219 post2 := store.Must(ss.Post().Save(&model.Post{ 220 ChannelId: model.NewId(), 221 UserId: model.NewId(), 222 })).(*model.Post) 223 post3 := store.Must(ss.Post().Save(&model.Post{ 224 ChannelId: model.NewId(), 225 UserId: model.NewId(), 226 })).(*model.Post) 227 228 userId := model.NewId() 229 230 reactions := []*model.Reaction{ 231 { 232 UserId: userId, 233 PostId: post.Id, 234 EmojiName: emojiToDelete, 235 }, 236 { 237 UserId: model.NewId(), 238 PostId: post.Id, 239 EmojiName: emojiToDelete, 240 }, 241 { 242 UserId: userId, 243 PostId: post.Id, 244 EmojiName: "sad", 245 }, 246 { 247 UserId: userId, 248 PostId: post2.Id, 249 EmojiName: "angry", 250 }, 251 { 252 UserId: userId, 253 PostId: post3.Id, 254 EmojiName: emojiToDelete, 255 }, 256 } 257 258 for _, reaction := range reactions { 259 store.Must(ss.Reaction().Save(reaction)) 260 } 261 262 if result := <-ss.Reaction().DeleteAllWithEmojiName(emojiToDelete); result.Err != nil { 263 t.Fatal(result.Err) 264 } 265 266 // check that the reactions were deleted 267 if returned := store.Must(ss.Reaction().GetForPost(post.Id, false)).([]*model.Reaction); len(returned) != 1 { 268 t.Fatal("should've only removed reactions with emoji name") 269 } else { 270 for _, reaction := range returned { 271 if reaction.EmojiName == "smile" { 272 t.Fatal("should've removed reaction with emoji name") 273 } 274 } 275 } 276 277 if returned := store.Must(ss.Reaction().GetForPost(post2.Id, false)).([]*model.Reaction); len(returned) != 1 { 278 t.Fatal("should've only removed reactions with emoji name") 279 } 280 281 if returned := store.Must(ss.Reaction().GetForPost(post3.Id, false)).([]*model.Reaction); len(returned) != 0 { 282 t.Fatal("should've only removed reactions with emoji name") 283 } 284 285 // check that the posts are updated 286 if postList := store.Must(ss.Post().Get(post.Id)).(*model.PostList); !postList.Posts[post.Id].HasReactions { 287 t.Fatal("post should still have reactions") 288 } 289 290 if postList := store.Must(ss.Post().Get(post2.Id)).(*model.PostList); !postList.Posts[post2.Id].HasReactions { 291 t.Fatal("post should still have reactions") 292 } 293 294 if postList := store.Must(ss.Post().Get(post3.Id)).(*model.PostList); postList.Posts[post3.Id].HasReactions { 295 t.Fatal("post shouldn't have reactions any more") 296 } 297 } 298 299 func testReactionStorePermanentDeleteBatch(t *testing.T, ss store.Store) { 300 post := store.Must(ss.Post().Save(&model.Post{ 301 ChannelId: model.NewId(), 302 UserId: model.NewId(), 303 })).(*model.Post) 304 305 reactions := []*model.Reaction{ 306 { 307 UserId: model.NewId(), 308 PostId: post.Id, 309 EmojiName: "sad", 310 CreateAt: 1000, 311 }, 312 { 313 UserId: model.NewId(), 314 PostId: post.Id, 315 EmojiName: "sad", 316 CreateAt: 1500, 317 }, 318 { 319 UserId: model.NewId(), 320 PostId: post.Id, 321 EmojiName: "sad", 322 CreateAt: 2000, 323 }, 324 { 325 UserId: model.NewId(), 326 PostId: post.Id, 327 EmojiName: "sad", 328 CreateAt: 2000, 329 }, 330 } 331 332 // Need to hang on to a reaction to delete later in order to clear the cache, as "allowFromCache" isn't honoured any more. 333 var lastReaction *model.Reaction 334 for _, reaction := range reactions { 335 lastReaction = store.Must(ss.Reaction().Save(reaction)).(*model.Reaction) 336 } 337 338 if returned := store.Must(ss.Reaction().GetForPost(post.Id, false)).([]*model.Reaction); len(returned) != 4 { 339 t.Fatal("expected 4 reactions") 340 } 341 342 store.Must(ss.Reaction().PermanentDeleteBatch(1800, 1000)) 343 344 // This is to force a clear of the cache. 345 store.Must(ss.Reaction().Delete(lastReaction)) 346 347 if returned := store.Must(ss.Reaction().GetForPost(post.Id, false)).([]*model.Reaction); len(returned) != 1 { 348 t.Fatalf("expected 1 reaction. Got: %v", len(returned)) 349 } 350 }