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  }