github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/store/searchtest/post_layer.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package searchtest
     5  
     6  import (
     7  	"testing"
     8  	"time"
     9  
    10  	"github.com/mattermost/mattermost-server/v5/model"
    11  	"github.com/mattermost/mattermost-server/v5/store"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  var searchPostStoreTests = []searchTest{
    16  	{
    17  		Name: "Should be able to search posts including results from DMs",
    18  		Fn:   testSearchPostsIncludingDMs,
    19  		Tags: []string{ENGINE_ALL},
    20  	},
    21  	{
    22  		Name: "Should be able to search posts using pagination",
    23  		Fn:   testSearchPostsWithPagination,
    24  		Tags: []string{ENGINE_ELASTICSEARCH, ENGINE_BLEVE},
    25  	},
    26  	{
    27  		Name: "Should return pinned and unpinned posts",
    28  		Fn:   testSearchReturnPinnedAndUnpinned,
    29  		Tags: []string{ENGINE_ALL},
    30  	},
    31  	{
    32  		Name: "Should be able to search for exact phrases in quotes",
    33  		Fn:   testSearchExactPhraseInQuotes,
    34  		Tags: []string{ENGINE_POSTGRES, ENGINE_MYSQL, ENGINE_ELASTICSEARCH},
    35  	},
    36  	{
    37  		Name: "Should be able to search for email addresses with or without quotes",
    38  		Fn:   testSearchEmailAddresses,
    39  		Tags: []string{ENGINE_ELASTICSEARCH},
    40  	},
    41  	{
    42  		Name: "Should be able to search when markdown underscores are applied",
    43  		Fn:   testSearchMarkdownUnderscores,
    44  		Tags: []string{ENGINE_POSTGRES, ENGINE_ELASTICSEARCH},
    45  	},
    46  	{
    47  		Name: "Should be able to search for non-latin words",
    48  		Fn:   testSearchNonLatinWords,
    49  		Tags: []string{ENGINE_ELASTICSEARCH},
    50  	},
    51  	{
    52  		Name: "Should be able to search for alternative spellings of words",
    53  		Fn:   testSearchAlternativeSpellings,
    54  		Tags: []string{ENGINE_ELASTICSEARCH},
    55  	},
    56  	{
    57  		Name: "Should be able to search for alternative spellings of words with and without accents",
    58  		Fn:   testSearchAlternativeSpellingsAccents,
    59  		Tags: []string{ENGINE_ELASTICSEARCH},
    60  	},
    61  	{
    62  		Name: "Should be able to search or exclude messages written by a specific user",
    63  		Fn:   testSearchOrExcludePostsBySpecificUser,
    64  		Tags: []string{ENGINE_ALL},
    65  	},
    66  	{
    67  		Name: "Should be able to search or exclude messages written in a specific channel",
    68  		Fn:   testSearchOrExcludePostsInChannel,
    69  		Tags: []string{ENGINE_ALL},
    70  	},
    71  	{
    72  		Name: "Should be able to search or exclude messages written in a DM or GM",
    73  		Fn:   testSearchOrExcludePostsInDMGM,
    74  		Tags: []string{ENGINE_ALL},
    75  	},
    76  	{
    77  		Name: "Should be able to filter messages written after a specific date",
    78  		Fn:   testFilterMessagesAfterSpecificDate,
    79  		Tags: []string{ENGINE_ALL},
    80  	},
    81  	{
    82  		Name: "Should be able to filter messages written before a specific date",
    83  		Fn:   testFilterMessagesBeforeSpecificDate,
    84  		Tags: []string{ENGINE_ALL},
    85  	},
    86  	{
    87  		Name: "Should be able to filter messages written on a specific date",
    88  		Fn:   testFilterMessagesInSpecificDate,
    89  		Tags: []string{ENGINE_ALL},
    90  	},
    91  	{
    92  		Name: "Should be able to exclude messages that contain a serch term",
    93  		Fn:   testFilterMessagesWithATerm,
    94  		Tags: []string{ENGINE_MYSQL, ENGINE_POSTGRES},
    95  	},
    96  	{
    97  		Name: "Should be able to search using boolean operators",
    98  		Fn:   testSearchUsingBooleanOperators,
    99  		Tags: []string{ENGINE_ELASTICSEARCH},
   100  	},
   101  	{
   102  		Name: "Should be able to search with combined filters",
   103  		Fn:   testSearchUsingCombinedFilters,
   104  		Tags: []string{ENGINE_ALL},
   105  	},
   106  	{
   107  		Name: "Should be able to ignore stop words",
   108  		Fn:   testSearchIgnoringStopWords,
   109  		Tags: []string{ENGINE_ELASTICSEARCH},
   110  	},
   111  	{
   112  		Name: "Should support search stemming",
   113  		Fn:   testSupportStemming,
   114  		Tags: []string{ENGINE_POSTGRES, ENGINE_ELASTICSEARCH},
   115  	},
   116  	{
   117  		Name: "Should support search with wildcards",
   118  		Fn:   testSupportWildcards,
   119  		Tags: []string{ENGINE_POSTGRES, ENGINE_MYSQL, ENGINE_ELASTICSEARCH},
   120  	},
   121  	{
   122  		Name: "Should not support search with preceding wildcards",
   123  		Fn:   testNotSupportPrecedingWildcards,
   124  		Tags: []string{ENGINE_ALL},
   125  	},
   126  	{
   127  		Name: "Should discard a wildcard if it's not placed immediately by text",
   128  		Fn:   testSearchDiscardWildcardAlone,
   129  		Tags: []string{ENGINE_POSTGRES, ENGINE_MYSQL, ENGINE_ELASTICSEARCH},
   130  	},
   131  	{
   132  		Name: "Should support terms with dash",
   133  		Fn:   testSupportTermsWithDash,
   134  		Tags: []string{ENGINE_ALL},
   135  		Skip: true,
   136  	},
   137  	{
   138  		Name: "Should support terms with underscore",
   139  		Fn:   testSupportTermsWithUnderscore,
   140  		Tags: []string{ENGINE_MYSQL, ENGINE_ELASTICSEARCH},
   141  	},
   142  	{
   143  		Name: "Should search or exclude post using hashtags",
   144  		Fn:   testSearchOrExcludePostsWithHashtags,
   145  		Tags: []string{ENGINE_ALL},
   146  	},
   147  	{
   148  		Name: "Should support searching for hashtags surrounded by markdown",
   149  		Fn:   testSearchHashtagWithMarkdown,
   150  		Tags: []string{ENGINE_ALL},
   151  	},
   152  	{
   153  		Name: "Should support searching for multiple hashtags",
   154  		Fn:   testSearcWithMultipleHashtags,
   155  		Tags: []string{ENGINE_ELASTICSEARCH},
   156  	},
   157  	{
   158  		Name: "Should support searching hashtags with dots",
   159  		Fn:   testSearchPostsWithDotsInHashtags,
   160  		Tags: []string{ENGINE_ALL},
   161  	},
   162  	{
   163  		Name: "Should be able to search or exclude messages with hashtags in a case insensitive manner",
   164  		Fn:   testSearchHashtagCaseInsensitive,
   165  		Tags: []string{ENGINE_ALL},
   166  	},
   167  	{
   168  		Name: "Should be able to search by hashtags with dashes",
   169  		Fn:   testSearchHashtagWithDash,
   170  		Tags: []string{ENGINE_ALL},
   171  	},
   172  	{
   173  		Name: "Should be able to search by hashtags with numbers",
   174  		Fn:   testSearchHashtagWithNumbers,
   175  		Tags: []string{ENGINE_ALL},
   176  	},
   177  	{
   178  		Name: "Should be able to search by hashtags with dots",
   179  		Fn:   testSearchHashtagWithDots,
   180  		Tags: []string{ENGINE_ALL},
   181  	},
   182  	{
   183  		Name: "Should be able to search by hashtags with underscores",
   184  		Fn:   testSearchHashtagWithUnderscores,
   185  		Tags: []string{ENGINE_ALL},
   186  	},
   187  	{
   188  		Name: "Should not return system messages",
   189  		Fn:   testSearchShouldExcludeSytemMessages,
   190  		Tags: []string{ENGINE_ALL},
   191  	},
   192  	{
   193  		Name: "Should be able to search matching by mentions",
   194  		Fn:   testSearchShouldBeAbleToMatchByMentions,
   195  		Tags: []string{ENGINE_ALL},
   196  	},
   197  	{
   198  		Name:        "Should be able to search in deleted/archived channels",
   199  		Fn:          testSearchInDeletedOrArchivedChannels,
   200  		Tags:        []string{ENGINE_ALL},
   201  		Skip:        true,
   202  		SkipMessage: "Not working",
   203  	},
   204  	{
   205  		Name:        "Should be able to search terms with dashes",
   206  		Fn:          testSearchTermsWithDashes,
   207  		Tags:        []string{ENGINE_ALL},
   208  		Skip:        true,
   209  		SkipMessage: "Not working",
   210  	},
   211  	{
   212  		Name: "Should be able to search terms with dots",
   213  		Fn:   testSearchTermsWithDots,
   214  		Tags: []string{ENGINE_ELASTICSEARCH},
   215  	},
   216  	{
   217  		Name: "Should be able to search terms with underscores",
   218  		Fn:   testSearchTermsWithUnderscores,
   219  		Tags: []string{ENGINE_ELASTICSEARCH},
   220  	},
   221  	{
   222  		Name: "Should be able to search posts made by bot accounts",
   223  		Fn:   testSearchBotAccountsPosts,
   224  		Tags: []string{ENGINE_ALL},
   225  	},
   226  	{
   227  		Name: "Should be able to combine stemming and wildcards",
   228  		Fn:   testSupportStemmingAndWildcards,
   229  		Tags: []string{ENGINE_ELASTICSEARCH},
   230  	},
   231  	{
   232  		Name: "Should support wildcard outside quotes",
   233  		Fn:   testSupportWildcardOutsideQuotes,
   234  		Tags: []string{ENGINE_ELASTICSEARCH},
   235  	},
   236  	{
   237  		Name: "Should support hashtags with 3 or more characters",
   238  		Fn:   testHashtagSearchShouldSupportThreeOrMoreCharacters,
   239  		Tags: []string{ENGINE_ALL},
   240  	},
   241  	{
   242  		Name: "Should not support slash as character separator",
   243  		Fn:   testSlashShouldNotBeCharSeparator,
   244  		Tags: []string{ENGINE_MYSQL, ENGINE_ELASTICSEARCH},
   245  	},
   246  	{
   247  		Name: "Should be able to search emails without quoting them",
   248  		Fn:   testSearchEmailsWithoutQuotes,
   249  		Tags: []string{ENGINE_ELASTICSEARCH},
   250  	},
   251  	{
   252  		Name: "Should be able to search in comments",
   253  		Fn:   testSupportSearchInComments,
   254  		Tags: []string{ENGINE_ALL},
   255  	},
   256  	{
   257  		Name: "Should be able to search terms within links",
   258  		Fn:   testSupportSearchTermsWithinLinks,
   259  		Tags: []string{ENGINE_MYSQL, ENGINE_ELASTICSEARCH},
   260  	},
   261  	{
   262  		Name: "Should not return links that are embedded in markdown",
   263  		Fn:   testShouldNotReturnLinksEmbeddedInMarkdown,
   264  		Tags: []string{ENGINE_POSTGRES, ENGINE_ELASTICSEARCH},
   265  	},
   266  }
   267  
   268  func TestSearchPostStore(t *testing.T, s store.Store, testEngine *SearchTestEngine) {
   269  	th := &SearchTestHelper{
   270  		Store: s,
   271  	}
   272  	err := th.SetupBasicFixtures()
   273  	require.Nil(t, err)
   274  	defer th.CleanFixtures()
   275  
   276  	runTestSearch(t, testEngine, searchPostStoreTests, th)
   277  }
   278  
   279  func testSearchPostsIncludingDMs(t *testing.T, th *SearchTestHelper) {
   280  	direct, err := th.createDirectChannel(th.Team.Id, "direct", "direct", []*model.User{th.User, th.User2})
   281  	require.Nil(t, err)
   282  	defer th.deleteChannel(direct)
   283  
   284  	p1, err := th.createPost(th.User.Id, direct.Id, "dm test", "", model.POST_DEFAULT, 0, false)
   285  	require.Nil(t, err)
   286  	_, err = th.createPost(th.User.Id, direct.Id, "dm other", "", model.POST_DEFAULT, 0, false)
   287  	require.Nil(t, err)
   288  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "channel test", "", model.POST_DEFAULT, 0, false)
   289  	require.Nil(t, err)
   290  	defer th.deleteUserPosts(th.User.Id)
   291  
   292  	params := &model.SearchParams{Terms: "test"}
   293  	results, err := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   294  	require.Nil(t, err)
   295  
   296  	require.Len(t, results.Posts, 2)
   297  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
   298  	th.checkPostInSearchResults(t, p2.Id, results.Posts)
   299  }
   300  
   301  func testSearchPostsWithPagination(t *testing.T, th *SearchTestHelper) {
   302  	direct, err := th.createDirectChannel(th.Team.Id, "direct", "direct", []*model.User{th.User, th.User2})
   303  	require.Nil(t, err)
   304  	defer th.deleteChannel(direct)
   305  
   306  	p1, err := th.createPost(th.User.Id, direct.Id, "dm test", "", model.POST_DEFAULT, 10000, false)
   307  	require.Nil(t, err)
   308  	_, err = th.createPost(th.User.Id, direct.Id, "dm other", "", model.POST_DEFAULT, 20000, false)
   309  	require.Nil(t, err)
   310  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "channel test", "", model.POST_DEFAULT, 0, false)
   311  	require.Nil(t, err)
   312  	defer th.deleteUserPosts(th.User.Id)
   313  
   314  	params := &model.SearchParams{Terms: "test"}
   315  	results, err := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 1)
   316  	require.Nil(t, err)
   317  
   318  	require.Len(t, results.Posts, 1)
   319  	th.checkPostInSearchResults(t, p2.Id, results.Posts)
   320  
   321  	results, err = th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 1, 1)
   322  	require.Nil(t, err)
   323  
   324  	require.Len(t, results.Posts, 1)
   325  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
   326  }
   327  
   328  func testSearchReturnPinnedAndUnpinned(t *testing.T, th *SearchTestHelper) {
   329  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "channel test unpinned", "", model.POST_DEFAULT, 0, false)
   330  	require.Nil(t, err)
   331  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "channel test pinned", "", model.POST_DEFAULT, 0, true)
   332  	require.Nil(t, err)
   333  	defer th.deleteUserPosts(th.User.Id)
   334  
   335  	params := &model.SearchParams{Terms: "test"}
   336  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   337  	require.Nil(t, apperr)
   338  
   339  	require.Len(t, results.Posts, 2)
   340  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
   341  	th.checkPostInSearchResults(t, p2.Id, results.Posts)
   342  }
   343  
   344  func testSearchExactPhraseInQuotes(t *testing.T, th *SearchTestHelper) {
   345  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "channel test 1 2 3", "", model.POST_DEFAULT, 0, false)
   346  	require.Nil(t, err)
   347  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "channel test 123", "", model.POST_DEFAULT, 0, false)
   348  	require.Nil(t, err)
   349  	defer th.deleteUserPosts(th.User.Id)
   350  
   351  	params := &model.SearchParams{Terms: "\"channel test 1 2 3\""}
   352  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   353  	require.Nil(t, apperr)
   354  
   355  	require.Len(t, results.Posts, 1)
   356  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
   357  }
   358  
   359  func testSearchEmailAddresses(t *testing.T, th *SearchTestHelper) {
   360  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "test email test@test.com", "", model.POST_DEFAULT, 0, false)
   361  	require.Nil(t, err)
   362  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "test email test2@test.com", "", model.POST_DEFAULT, 0, false)
   363  	require.Nil(t, err)
   364  	defer th.deleteUserPosts(th.User.Id)
   365  
   366  	t.Run("Should search email addresses enclosed by quotes", func(t *testing.T) {
   367  		params := &model.SearchParams{Terms: "\"test@test.com\""}
   368  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   369  		require.Nil(t, apperr)
   370  
   371  		require.Len(t, results.Posts, 1)
   372  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   373  	})
   374  
   375  	t.Run("Should search email addresses without quotes", func(t *testing.T) {
   376  		params := &model.SearchParams{Terms: "test@test.com"}
   377  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   378  		require.Nil(t, apperr)
   379  
   380  		require.Len(t, results.Posts, 1)
   381  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   382  	})
   383  }
   384  
   385  func testSearchMarkdownUnderscores(t *testing.T, th *SearchTestHelper) {
   386  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "_start middle end_ _another_", "", model.POST_DEFAULT, 0, false)
   387  	require.Nil(t, err)
   388  	defer th.deleteUserPosts(th.User.Id)
   389  
   390  	t.Run("Should search the start inside the markdown underscore", func(t *testing.T) {
   391  		params := &model.SearchParams{Terms: "start"}
   392  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   393  		require.Nil(t, apperr)
   394  
   395  		require.Len(t, results.Posts, 1)
   396  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   397  	})
   398  
   399  	t.Run("Should search a word in the middle of the markdown underscore", func(t *testing.T) {
   400  		params := &model.SearchParams{Terms: "middle"}
   401  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   402  		require.Nil(t, apperr)
   403  
   404  		require.Len(t, results.Posts, 1)
   405  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   406  	})
   407  
   408  	t.Run("Should search in the end of the markdown underscore", func(t *testing.T) {
   409  		params := &model.SearchParams{Terms: "end"}
   410  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   411  		require.Nil(t, apperr)
   412  
   413  		require.Len(t, results.Posts, 1)
   414  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   415  	})
   416  
   417  	t.Run("Should search inside markdown underscore", func(t *testing.T) {
   418  		params := &model.SearchParams{Terms: "another"}
   419  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   420  		require.Nil(t, apperr)
   421  
   422  		require.Len(t, results.Posts, 1)
   423  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   424  	})
   425  }
   426  
   427  func testSearchNonLatinWords(t *testing.T, th *SearchTestHelper) {
   428  	t.Run("Should be able to search chinese words", func(t *testing.T) {
   429  		p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "你好", "", model.POST_DEFAULT, 0, false)
   430  		require.Nil(t, err)
   431  		p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "你", "", model.POST_DEFAULT, 0, false)
   432  		require.Nil(t, err)
   433  		defer th.deleteUserPosts(th.User.Id)
   434  
   435  		t.Run("Should search one word", func(t *testing.T) {
   436  			params := &model.SearchParams{Terms: "你"}
   437  			results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   438  			require.Nil(t, apperr)
   439  
   440  			require.Len(t, results.Posts, 1)
   441  			th.checkPostInSearchResults(t, p2.Id, results.Posts)
   442  		})
   443  		t.Run("Should search two words", func(t *testing.T) {
   444  			params := &model.SearchParams{Terms: "你好"}
   445  			results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   446  			require.Nil(t, apperr)
   447  
   448  			require.Len(t, results.Posts, 1)
   449  			th.checkPostInSearchResults(t, p1.Id, results.Posts)
   450  		})
   451  		t.Run("Should search with wildcard", func(t *testing.T) {
   452  			params := &model.SearchParams{Terms: "你*"}
   453  			results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   454  			require.Nil(t, apperr)
   455  
   456  			require.Len(t, results.Posts, 2)
   457  			th.checkPostInSearchResults(t, p1.Id, results.Posts)
   458  			th.checkPostInSearchResults(t, p2.Id, results.Posts)
   459  		})
   460  	})
   461  	t.Run("Should be able to search cyrillic words", func(t *testing.T) {
   462  		p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "слово test", "", model.POST_DEFAULT, 0, false)
   463  		require.Nil(t, err)
   464  		defer th.deleteUserPosts(th.User.Id)
   465  
   466  		t.Run("Should search one word", func(t *testing.T) {
   467  			params := &model.SearchParams{Terms: "слово"}
   468  			results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   469  			require.Nil(t, apperr)
   470  
   471  			require.Len(t, results.Posts, 1)
   472  			th.checkPostInSearchResults(t, p1.Id, results.Posts)
   473  		})
   474  		t.Run("Should search using wildcard", func(t *testing.T) {
   475  			params := &model.SearchParams{Terms: "слов*"}
   476  			results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   477  			require.Nil(t, apperr)
   478  
   479  			require.Len(t, results.Posts, 1)
   480  			th.checkPostInSearchResults(t, p1.Id, results.Posts)
   481  		})
   482  	})
   483  
   484  	t.Run("Should be able to search japanese words", func(t *testing.T) {
   485  		p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "本", "", model.POST_DEFAULT, 0, false)
   486  		require.Nil(t, err)
   487  		p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "本木", "", model.POST_DEFAULT, 0, false)
   488  		require.Nil(t, err)
   489  		defer th.deleteUserPosts(th.User.Id)
   490  
   491  		t.Run("Should search one word", func(t *testing.T) {
   492  			params := &model.SearchParams{Terms: "本"}
   493  			results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   494  			require.Nil(t, apperr)
   495  
   496  			require.Len(t, results.Posts, 2)
   497  			th.checkPostInSearchResults(t, p1.Id, results.Posts)
   498  			th.checkPostInSearchResults(t, p2.Id, results.Posts)
   499  		})
   500  		t.Run("Should search two words", func(t *testing.T) {
   501  			params := &model.SearchParams{Terms: "本木"}
   502  			results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   503  			require.Nil(t, apperr)
   504  
   505  			require.Len(t, results.Posts, 1)
   506  			th.checkPostInSearchResults(t, p2.Id, results.Posts)
   507  		})
   508  		t.Run("Should search with wildcard", func(t *testing.T) {
   509  			params := &model.SearchParams{Terms: "本*"}
   510  			results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   511  			require.Nil(t, apperr)
   512  
   513  			require.Len(t, results.Posts, 2)
   514  			th.checkPostInSearchResults(t, p1.Id, results.Posts)
   515  			th.checkPostInSearchResults(t, p2.Id, results.Posts)
   516  		})
   517  	})
   518  
   519  	t.Run("Should be able to search korean words", func(t *testing.T) {
   520  		p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "불", "", model.POST_DEFAULT, 0, false)
   521  		require.Nil(t, err)
   522  		p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "불다", "", model.POST_DEFAULT, 0, false)
   523  		require.Nil(t, err)
   524  		defer th.deleteUserPosts(th.User.Id)
   525  
   526  		t.Run("Should search one word", func(t *testing.T) {
   527  			params := &model.SearchParams{Terms: "불"}
   528  			results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   529  			require.Nil(t, apperr)
   530  
   531  			require.Len(t, results.Posts, 1)
   532  			th.checkPostInSearchResults(t, p1.Id, results.Posts)
   533  		})
   534  		t.Run("Should search two words", func(t *testing.T) {
   535  			params := &model.SearchParams{Terms: "불다"}
   536  			results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   537  			require.Nil(t, apperr)
   538  
   539  			require.Len(t, results.Posts, 1)
   540  			th.checkPostInSearchResults(t, p2.Id, results.Posts)
   541  		})
   542  		t.Run("Should search with wildcard", func(t *testing.T) {
   543  			params := &model.SearchParams{Terms: "불*"}
   544  			results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   545  			require.Nil(t, apperr)
   546  
   547  			require.Len(t, results.Posts, 2)
   548  			th.checkPostInSearchResults(t, p1.Id, results.Posts)
   549  			th.checkPostInSearchResults(t, p2.Id, results.Posts)
   550  		})
   551  	})
   552  }
   553  
   554  func testSearchAlternativeSpellings(t *testing.T, th *SearchTestHelper) {
   555  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "Straße test", "", model.POST_DEFAULT, 0, false)
   556  	require.Nil(t, err)
   557  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "Strasse test", "", model.POST_DEFAULT, 0, false)
   558  	require.Nil(t, err)
   559  	defer th.deleteUserPosts(th.User.Id)
   560  
   561  	params := &model.SearchParams{Terms: "Straße"}
   562  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   563  	require.Nil(t, apperr)
   564  
   565  	require.Len(t, results.Posts, 2)
   566  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
   567  	th.checkPostInSearchResults(t, p2.Id, results.Posts)
   568  
   569  	params = &model.SearchParams{Terms: "Strasse"}
   570  	results, apperr = th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   571  	require.Nil(t, apperr)
   572  
   573  	require.Len(t, results.Posts, 2)
   574  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
   575  	th.checkPostInSearchResults(t, p2.Id, results.Posts)
   576  }
   577  
   578  func testSearchAlternativeSpellingsAccents(t *testing.T, th *SearchTestHelper) {
   579  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "café", "", model.POST_DEFAULT, 0, false)
   580  	require.Nil(t, err)
   581  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "café", "", model.POST_DEFAULT, 0, false)
   582  	require.Nil(t, err)
   583  	defer th.deleteUserPosts(th.User.Id)
   584  
   585  	params := &model.SearchParams{Terms: "café"}
   586  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   587  	require.Nil(t, apperr)
   588  
   589  	require.Len(t, results.Posts, 2)
   590  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
   591  	th.checkPostInSearchResults(t, p2.Id, results.Posts)
   592  
   593  	params = &model.SearchParams{Terms: "café"}
   594  	results, apperr = th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   595  	require.Nil(t, apperr)
   596  
   597  	require.Len(t, results.Posts, 2)
   598  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
   599  	th.checkPostInSearchResults(t, p2.Id, results.Posts)
   600  
   601  	params = &model.SearchParams{Terms: "cafe"}
   602  	results, apperr = th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   603  	require.Nil(t, apperr)
   604  
   605  	require.Len(t, results.Posts, 0)
   606  }
   607  
   608  func testSearchOrExcludePostsBySpecificUser(t *testing.T, th *SearchTestHelper) {
   609  	p1, err := th.createPost(th.User.Id, th.ChannelPrivate.Id, "test fromuser", "", model.POST_DEFAULT, 0, false)
   610  	require.Nil(t, err)
   611  	_, err = th.createPost(th.User2.Id, th.ChannelPrivate.Id, "test fromuser 2", "", model.POST_DEFAULT, 0, false)
   612  	require.Nil(t, err)
   613  	defer th.deleteUserPosts(th.User.Id)
   614  	defer th.deleteUserPosts(th.User2.Id)
   615  
   616  	params := &model.SearchParams{
   617  		Terms:     "fromuser",
   618  		FromUsers: []string{th.User.Id},
   619  	}
   620  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   621  	require.Nil(t, apperr)
   622  
   623  	require.Len(t, results.Posts, 1)
   624  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
   625  }
   626  
   627  func testSearchOrExcludePostsInChannel(t *testing.T, th *SearchTestHelper) {
   628  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "test fromuser", "", model.POST_DEFAULT, 0, false)
   629  	require.Nil(t, err)
   630  	_, err = th.createPost(th.User2.Id, th.ChannelPrivate.Id, "test fromuser 2", "", model.POST_DEFAULT, 0, false)
   631  	require.Nil(t, err)
   632  	defer th.deleteUserPosts(th.User.Id)
   633  	defer th.deleteUserPosts(th.User2.Id)
   634  
   635  	params := &model.SearchParams{
   636  		Terms:      "fromuser",
   637  		InChannels: []string{th.ChannelBasic.Id},
   638  	}
   639  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   640  	require.Nil(t, apperr)
   641  
   642  	require.Len(t, results.Posts, 1)
   643  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
   644  }
   645  
   646  func testSearchOrExcludePostsInDMGM(t *testing.T, th *SearchTestHelper) {
   647  	direct, err := th.createDirectChannel(th.Team.Id, "direct", "direct", []*model.User{th.User, th.User2})
   648  	require.Nil(t, err)
   649  	defer th.deleteChannel(direct)
   650  
   651  	group, err := th.createGroupChannel(th.Team.Id, "test group", []*model.User{th.User, th.User2})
   652  	require.Nil(t, err)
   653  	defer th.deleteChannel(group)
   654  
   655  	p1, err := th.createPost(th.User.Id, direct.Id, "test fromuser", "", model.POST_DEFAULT, 0, false)
   656  	require.Nil(t, err)
   657  	p2, err := th.createPost(th.User2.Id, group.Id, "test fromuser 2", "", model.POST_DEFAULT, 0, false)
   658  	require.Nil(t, err)
   659  	defer th.deleteUserPosts(th.User.Id)
   660  	defer th.deleteUserPosts(th.User2.Id)
   661  
   662  	t.Run("Should be able to search in both DM and GM channels", func(t *testing.T) {
   663  		params := &model.SearchParams{
   664  			Terms:      "fromuser",
   665  			InChannels: []string{direct.Id, group.Id},
   666  		}
   667  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   668  		require.Nil(t, apperr)
   669  
   670  		require.Len(t, results.Posts, 2)
   671  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   672  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
   673  	})
   674  
   675  	t.Run("Should be able to search only in DM channel", func(t *testing.T) {
   676  		params := &model.SearchParams{
   677  			Terms:      "fromuser",
   678  			InChannels: []string{direct.Id},
   679  		}
   680  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   681  		require.Nil(t, apperr)
   682  
   683  		require.Len(t, results.Posts, 1)
   684  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   685  	})
   686  
   687  	t.Run("Should be able to search only in GM channel", func(t *testing.T) {
   688  		params := &model.SearchParams{
   689  			Terms:      "fromuser",
   690  			InChannels: []string{group.Id},
   691  		}
   692  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   693  		require.Nil(t, apperr)
   694  
   695  		require.Len(t, results.Posts, 1)
   696  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
   697  	})
   698  }
   699  
   700  func testFilterMessagesInSpecificDate(t *testing.T, th *SearchTestHelper) {
   701  	creationDate := model.GetMillisForTime(time.Date(2020, 03, 22, 12, 0, 0, 0, time.UTC))
   702  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "test in specific date", "", model.POST_DEFAULT, creationDate, false)
   703  	require.Nil(t, err)
   704  	creationDate2 := model.GetMillisForTime(time.Date(2020, 03, 23, 0, 0, 0, 0, time.UTC))
   705  	p2, err := th.createPost(th.User.Id, th.ChannelPrivate.Id, "test in the present", "", model.POST_DEFAULT, creationDate2, false)
   706  	require.Nil(t, err)
   707  	creationDate3 := model.GetMillisForTime(time.Date(2020, 03, 21, 23, 59, 59, 0, time.UTC))
   708  	p3, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "test in the present", "", model.POST_DEFAULT, creationDate3, false)
   709  	require.Nil(t, err)
   710  	defer th.deleteUserPosts(th.User.Id)
   711  
   712  	t.Run("Should be able to search posts on date", func(t *testing.T) {
   713  		params := &model.SearchParams{
   714  			Terms:  "test",
   715  			OnDate: "2020-03-22",
   716  		}
   717  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   718  		require.Nil(t, apperr)
   719  
   720  		require.Len(t, results.Posts, 1)
   721  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   722  	})
   723  	t.Run("Should be able to exclude posts on date", func(t *testing.T) {
   724  		params := &model.SearchParams{
   725  			Terms:        "test",
   726  			ExcludedDate: "2020-03-22",
   727  		}
   728  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   729  		require.Nil(t, apperr)
   730  
   731  		require.Len(t, results.Posts, 2)
   732  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
   733  		th.checkPostInSearchResults(t, p3.Id, results.Posts)
   734  	})
   735  }
   736  
   737  func testFilterMessagesBeforeSpecificDate(t *testing.T, th *SearchTestHelper) {
   738  	creationDate := model.GetMillisForTime(time.Date(2020, 03, 01, 12, 0, 0, 0, time.UTC))
   739  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "test in specific date", "", model.POST_DEFAULT, creationDate, false)
   740  	require.Nil(t, err)
   741  	creationDate2 := model.GetMillisForTime(time.Date(2020, 03, 22, 23, 59, 59, 0, time.UTC))
   742  	p2, err := th.createPost(th.User.Id, th.ChannelPrivate.Id, "test in specific date 2", "", model.POST_DEFAULT, creationDate2, false)
   743  	require.Nil(t, err)
   744  	creationDate3 := model.GetMillisForTime(time.Date(2020, 03, 26, 16, 55, 0, 0, time.UTC))
   745  	p3, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "test in the present", "", model.POST_DEFAULT, creationDate3, false)
   746  	require.Nil(t, err)
   747  	defer th.deleteUserPosts(th.User.Id)
   748  
   749  	t.Run("Should be able to search posts before a date", func(t *testing.T) {
   750  		params := &model.SearchParams{
   751  			Terms:      "test",
   752  			BeforeDate: "2020-03-23",
   753  		}
   754  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   755  		require.Nil(t, apperr)
   756  
   757  		require.Len(t, results.Posts, 2)
   758  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   759  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
   760  	})
   761  
   762  	t.Run("Should be able to exclude posts before a date", func(t *testing.T) {
   763  		params := &model.SearchParams{
   764  			Terms:              "test",
   765  			ExcludedBeforeDate: "2020-03-23",
   766  		}
   767  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   768  		require.Nil(t, apperr)
   769  
   770  		require.Len(t, results.Posts, 1)
   771  		th.checkPostInSearchResults(t, p3.Id, results.Posts)
   772  	})
   773  }
   774  
   775  func testFilterMessagesAfterSpecificDate(t *testing.T, th *SearchTestHelper) {
   776  	creationDate := model.GetMillisForTime(time.Date(2020, 03, 01, 12, 0, 0, 0, time.UTC))
   777  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "test in specific date", "", model.POST_DEFAULT, creationDate, false)
   778  	require.Nil(t, err)
   779  	creationDate2 := model.GetMillisForTime(time.Date(2020, 03, 22, 23, 59, 59, 0, time.UTC))
   780  	p2, err := th.createPost(th.User.Id, th.ChannelPrivate.Id, "test in specific date 2", "", model.POST_DEFAULT, creationDate2, false)
   781  	require.Nil(t, err)
   782  	creationDate3 := model.GetMillisForTime(time.Date(2020, 03, 26, 16, 55, 0, 0, time.UTC))
   783  	p3, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "test in the present", "", model.POST_DEFAULT, creationDate3, false)
   784  	require.Nil(t, err)
   785  	defer th.deleteUserPosts(th.User.Id)
   786  
   787  	t.Run("Should be able to search posts after a date", func(t *testing.T) {
   788  		params := &model.SearchParams{
   789  			Terms:     "test",
   790  			AfterDate: "2020-03-23",
   791  		}
   792  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   793  		require.Nil(t, apperr)
   794  
   795  		require.Len(t, results.Posts, 1)
   796  		th.checkPostInSearchResults(t, p3.Id, results.Posts)
   797  	})
   798  
   799  	t.Run("Should be able to exclude posts after a date", func(t *testing.T) {
   800  		params := &model.SearchParams{
   801  			Terms:             "test",
   802  			ExcludedAfterDate: "2020-03-23",
   803  		}
   804  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   805  		require.Nil(t, apperr)
   806  
   807  		require.Len(t, results.Posts, 2)
   808  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   809  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
   810  	})
   811  }
   812  
   813  func testFilterMessagesWithATerm(t *testing.T, th *SearchTestHelper) {
   814  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "one two three", "", model.POST_DEFAULT, 0, false)
   815  	require.Nil(t, err)
   816  	p2, err := th.createPost(th.User.Id, th.ChannelPrivate.Id, "one four five six", "", model.POST_DEFAULT, 0, false)
   817  	require.Nil(t, err)
   818  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "one seven eight nine", "", model.POST_DEFAULT, 0, false)
   819  	require.Nil(t, err)
   820  	defer th.deleteUserPosts(th.User.Id)
   821  
   822  	t.Run("Should exclude terms", func(t *testing.T) {
   823  		params := &model.SearchParams{
   824  			Terms:         "one",
   825  			ExcludedTerms: "five eight",
   826  		}
   827  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   828  		require.Nil(t, apperr)
   829  
   830  		require.Len(t, results.Posts, 1)
   831  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   832  	})
   833  
   834  	t.Run("Should exclude quoted terms", func(t *testing.T) {
   835  		params := &model.SearchParams{
   836  			Terms:         "one",
   837  			ExcludedTerms: "\"eight nine\"",
   838  		}
   839  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   840  		require.Nil(t, apperr)
   841  
   842  		require.Len(t, results.Posts, 2)
   843  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   844  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
   845  	})
   846  }
   847  
   848  func testSearchUsingBooleanOperators(t *testing.T, th *SearchTestHelper) {
   849  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "one two three message", "", model.POST_DEFAULT, 0, false)
   850  	require.Nil(t, err)
   851  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "two messages", "", model.POST_DEFAULT, 0, false)
   852  	require.Nil(t, err)
   853  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "another message", "", model.POST_DEFAULT, 0, false)
   854  	require.Nil(t, err)
   855  	defer th.deleteUserPosts(th.User.Id)
   856  
   857  	t.Run("Should search posts using OR operator", func(t *testing.T) {
   858  		params := &model.SearchParams{
   859  			Terms:   "one two",
   860  			OrTerms: true,
   861  		}
   862  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   863  		require.Nil(t, apperr)
   864  
   865  		require.Len(t, results.Posts, 2)
   866  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   867  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
   868  	})
   869  
   870  	t.Run("Should search posts using AND operator", func(t *testing.T) {
   871  		params := &model.SearchParams{
   872  			Terms:   "one two",
   873  			OrTerms: false,
   874  		}
   875  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   876  		require.Nil(t, apperr)
   877  
   878  		require.Len(t, results.Posts, 1)
   879  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   880  	})
   881  }
   882  
   883  func testSearchUsingCombinedFilters(t *testing.T, th *SearchTestHelper) {
   884  	creationDate := model.GetMillisForTime(time.Date(2020, 03, 01, 12, 0, 0, 0, time.UTC))
   885  	p1, err := th.createPost(th.User.Id, th.ChannelPrivate.Id, "one two three message", "", model.POST_DEFAULT, creationDate, false)
   886  	require.Nil(t, err)
   887  	creationDate2 := model.GetMillisForTime(time.Date(2020, 03, 10, 12, 0, 0, 0, time.UTC))
   888  	p2, err := th.createPost(th.User2.Id, th.ChannelPrivate.Id, "two messages", "", model.POST_DEFAULT, creationDate2, false)
   889  	require.Nil(t, err)
   890  	creationDate3 := model.GetMillisForTime(time.Date(2020, 03, 20, 12, 0, 0, 0, time.UTC))
   891  	p3, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "two another message", "", model.POST_DEFAULT, creationDate3, false)
   892  	require.Nil(t, err)
   893  	defer th.deleteUserPosts(th.User.Id)
   894  	defer th.deleteUserPosts(th.User2.Id)
   895  
   896  	t.Run("Should search combining from user and in channel filters", func(t *testing.T) {
   897  		params := &model.SearchParams{
   898  			Terms:      "two",
   899  			FromUsers:  []string{th.User2.Id},
   900  			InChannels: []string{th.ChannelPrivate.Id},
   901  		}
   902  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   903  		require.Nil(t, apperr)
   904  
   905  		require.Len(t, results.Posts, 1)
   906  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
   907  	})
   908  
   909  	t.Run("Should search combining excluding users and in channel filters", func(t *testing.T) {
   910  		params := &model.SearchParams{
   911  			Terms:         "two",
   912  			ExcludedUsers: []string{th.User2.Id},
   913  			InChannels:    []string{th.ChannelPrivate.Id},
   914  		}
   915  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   916  		require.Nil(t, apperr)
   917  
   918  		require.Len(t, results.Posts, 1)
   919  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   920  	})
   921  
   922  	t.Run("Should search combining excluding dates and in channel filters", func(t *testing.T) {
   923  		params := &model.SearchParams{
   924  			Terms:              "two",
   925  			ExcludedBeforeDate: "2020-03-09",
   926  			ExcludedAfterDate:  "2020-03-11",
   927  			InChannels:         []string{th.ChannelPrivate.Id},
   928  		}
   929  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   930  		require.Nil(t, apperr)
   931  
   932  		require.Len(t, results.Posts, 1)
   933  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
   934  	})
   935  	t.Run("Should search combining excluding dates and in channel filters", func(t *testing.T) {
   936  		params := &model.SearchParams{
   937  			Terms:            "two",
   938  			AfterDate:        "2020-03-11",
   939  			ExcludedChannels: []string{th.ChannelPrivate.Id},
   940  		}
   941  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   942  		require.Nil(t, apperr)
   943  
   944  		require.Len(t, results.Posts, 1)
   945  		th.checkPostInSearchResults(t, p3.Id, results.Posts)
   946  	})
   947  }
   948  
   949  func testSearchIgnoringStopWords(t *testing.T, th *SearchTestHelper) {
   950  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "the search for a bunch of stop words", "", model.POST_DEFAULT, 0, false)
   951  	require.Nil(t, err)
   952  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "the objective is to avoid a bunch of stop words", "", model.POST_DEFAULT, 0, false)
   953  	require.Nil(t, err)
   954  	p3, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "in the a on to where you", "", model.POST_DEFAULT, 0, false)
   955  	require.Nil(t, err)
   956  	defer th.deleteUserPosts(th.User.Id)
   957  
   958  	t.Run("Should avoid stop word 'the'", func(t *testing.T) {
   959  		params := &model.SearchParams{
   960  			Terms: "the search",
   961  		}
   962  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   963  		require.Nil(t, apperr)
   964  
   965  		require.Len(t, results.Posts, 1)
   966  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
   967  	})
   968  
   969  	t.Run("Should avoid stop word 'a'", func(t *testing.T) {
   970  		params := &model.SearchParams{
   971  			Terms: "a avoid",
   972  		}
   973  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   974  		require.Nil(t, apperr)
   975  
   976  		require.Len(t, results.Posts, 1)
   977  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
   978  	})
   979  
   980  	t.Run("Should avoid stop word 'in'", func(t *testing.T) {
   981  		params := &model.SearchParams{
   982  			Terms: "in where",
   983  		}
   984  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
   985  		require.Nil(t, apperr)
   986  
   987  		require.Len(t, results.Posts, 1)
   988  		th.checkPostInSearchResults(t, p3.Id, results.Posts)
   989  	})
   990  }
   991  
   992  func testSupportStemming(t *testing.T, th *SearchTestHelper) {
   993  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "search post", "", model.POST_DEFAULT, 0, false)
   994  	require.Nil(t, err)
   995  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching post", "", model.POST_DEFAULT, 0, false)
   996  	require.Nil(t, err)
   997  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "another post", "", model.POST_DEFAULT, 0, false)
   998  	require.Nil(t, err)
   999  	defer th.deleteUserPosts(th.User.Id)
  1000  
  1001  	params := &model.SearchParams{
  1002  		Terms: "search",
  1003  	}
  1004  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1005  	require.Nil(t, apperr)
  1006  
  1007  	require.Len(t, results.Posts, 2)
  1008  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1009  	th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1010  }
  1011  
  1012  func testSupportWildcards(t *testing.T, th *SearchTestHelper) {
  1013  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "search post", "", model.POST_DEFAULT, 0, false)
  1014  	require.Nil(t, err)
  1015  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching post", "", model.POST_DEFAULT, 0, false)
  1016  	require.Nil(t, err)
  1017  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "another post", "", model.POST_DEFAULT, 0, false)
  1018  	require.Nil(t, err)
  1019  	defer th.deleteUserPosts(th.User.Id)
  1020  
  1021  	params := &model.SearchParams{
  1022  		Terms: "search*",
  1023  	}
  1024  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1025  	require.Nil(t, apperr)
  1026  
  1027  	require.Len(t, results.Posts, 2)
  1028  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1029  	th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1030  }
  1031  
  1032  func testNotSupportPrecedingWildcards(t *testing.T, th *SearchTestHelper) {
  1033  	_, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "search post", "", model.POST_DEFAULT, 0, false)
  1034  	require.Nil(t, err)
  1035  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "searching post", "", model.POST_DEFAULT, 0, false)
  1036  	require.Nil(t, err)
  1037  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "another post", "", model.POST_DEFAULT, 0, false)
  1038  	require.Nil(t, err)
  1039  	defer th.deleteUserPosts(th.User.Id)
  1040  
  1041  	params := &model.SearchParams{
  1042  		Terms: "*earch",
  1043  	}
  1044  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1045  	require.Nil(t, apperr)
  1046  
  1047  	require.Len(t, results.Posts, 0)
  1048  }
  1049  
  1050  func testSearchDiscardWildcardAlone(t *testing.T, th *SearchTestHelper) {
  1051  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "qwerty", "", model.POST_DEFAULT, 0, false)
  1052  	require.Nil(t, err)
  1053  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "qwertyjkl", "", model.POST_DEFAULT, 0, false)
  1054  	require.Nil(t, err)
  1055  	defer th.deleteUserPosts(th.User.Id)
  1056  
  1057  	params := &model.SearchParams{
  1058  		Terms: "qwerty *",
  1059  	}
  1060  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1061  	require.Nil(t, apperr)
  1062  
  1063  	require.Len(t, results.Posts, 1)
  1064  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1065  }
  1066  
  1067  func testSupportTermsWithDash(t *testing.T, th *SearchTestHelper) {
  1068  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "search term-with-dash", "", model.POST_DEFAULT, 0, false)
  1069  	require.Nil(t, err)
  1070  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "searching term with dash", "", model.POST_DEFAULT, 0, false)
  1071  	require.Nil(t, err)
  1072  	defer th.deleteUserPosts(th.User.Id)
  1073  
  1074  	t.Run("Should search terms with dash", func(t *testing.T) {
  1075  		params := &model.SearchParams{
  1076  			Terms: "term-with-dash",
  1077  		}
  1078  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1079  		require.Nil(t, apperr)
  1080  
  1081  		require.Len(t, results.Posts, 1)
  1082  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1083  	})
  1084  
  1085  	t.Run("Should search terms with dash using quotes", func(t *testing.T) {
  1086  		params := &model.SearchParams{
  1087  			Terms: "\"term-with-dash\"",
  1088  		}
  1089  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1090  		require.Nil(t, apperr)
  1091  
  1092  		require.Len(t, results.Posts, 1)
  1093  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1094  	})
  1095  }
  1096  
  1097  func testSupportTermsWithUnderscore(t *testing.T, th *SearchTestHelper) {
  1098  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "search term_with_underscore", "", model.POST_DEFAULT, 0, false)
  1099  	require.Nil(t, err)
  1100  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "searching term with underscore", "", model.POST_DEFAULT, 0, false)
  1101  	require.Nil(t, err)
  1102  	defer th.deleteUserPosts(th.User.Id)
  1103  
  1104  	t.Run("Should search terms with underscore", func(t *testing.T) {
  1105  		params := &model.SearchParams{
  1106  			Terms: "term_with_underscore",
  1107  		}
  1108  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1109  		require.Nil(t, apperr)
  1110  
  1111  		require.Len(t, results.Posts, 1)
  1112  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1113  	})
  1114  
  1115  	t.Run("Should search terms with underscore using quotes", func(t *testing.T) {
  1116  		params := &model.SearchParams{
  1117  			Terms: "\"term_with_underscore\"",
  1118  		}
  1119  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1120  		require.Nil(t, apperr)
  1121  
  1122  		require.Len(t, results.Posts, 1)
  1123  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1124  	})
  1125  }
  1126  
  1127  func testSearchOrExcludePostsWithHashtags(t *testing.T, th *SearchTestHelper) {
  1128  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "search post with #hashtag", "#hashtag", model.POST_DEFAULT, 0, false)
  1129  	require.Nil(t, err)
  1130  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching term with hashtag", "", model.POST_DEFAULT, 0, false)
  1131  	require.Nil(t, err)
  1132  	p3, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching term with", "#hashtag", model.POST_DEFAULT, 0, false)
  1133  	require.Nil(t, err)
  1134  	defer th.deleteUserPosts(th.User.Id)
  1135  
  1136  	t.Run("Should search terms with hashtags", func(t *testing.T) {
  1137  		params := &model.SearchParams{
  1138  			Terms:     "#hashtag",
  1139  			IsHashtag: true,
  1140  		}
  1141  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1142  		require.Nil(t, apperr)
  1143  
  1144  		require.Len(t, results.Posts, 2)
  1145  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1146  		th.checkPostInSearchResults(t, p3.Id, results.Posts)
  1147  	})
  1148  
  1149  	t.Run("Should search hashtag terms without hashtag option", func(t *testing.T) {
  1150  		params := &model.SearchParams{
  1151  			Terms:     "#hashtag",
  1152  			IsHashtag: false,
  1153  		}
  1154  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1155  		require.Nil(t, apperr)
  1156  
  1157  		require.Len(t, results.Posts, 2)
  1158  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1159  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1160  	})
  1161  }
  1162  
  1163  func testSearchHashtagWithMarkdown(t *testing.T, th *SearchTestHelper) {
  1164  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching hashtag #hashtag", "#hashtag", model.POST_DEFAULT, 0, false)
  1165  	require.Nil(t, err)
  1166  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching term with `#hashtag`", "#hashtag", model.POST_DEFAULT, 0, false)
  1167  	require.Nil(t, err)
  1168  	p3, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching term with **#hashtag**", "#hashtag", model.POST_DEFAULT, 0, false)
  1169  	require.Nil(t, err)
  1170  	p4, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching term with ~~#hashtag~~", "#hashtag", model.POST_DEFAULT, 0, false)
  1171  	require.Nil(t, err)
  1172  	p5, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching term with _#hashtag_", "#hashtag", model.POST_DEFAULT, 0, false)
  1173  	require.Nil(t, err)
  1174  	defer th.deleteUserPosts(th.User.Id)
  1175  
  1176  	params := &model.SearchParams{
  1177  		Terms:     "#hashtag",
  1178  		IsHashtag: true,
  1179  	}
  1180  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1181  	require.Nil(t, apperr)
  1182  
  1183  	require.Len(t, results.Posts, 5)
  1184  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1185  	th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1186  	th.checkPostInSearchResults(t, p3.Id, results.Posts)
  1187  	th.checkPostInSearchResults(t, p4.Id, results.Posts)
  1188  	th.checkPostInSearchResults(t, p5.Id, results.Posts)
  1189  }
  1190  
  1191  func testSearcWithMultipleHashtags(t *testing.T, th *SearchTestHelper) {
  1192  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching hashtag #hashtag", "#hashtwo #hashone", model.POST_DEFAULT, 0, false)
  1193  	require.Nil(t, err)
  1194  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching term with `#hashtag`", "#hashtwo #hashthree", model.POST_DEFAULT, 0, false)
  1195  	require.Nil(t, err)
  1196  	defer th.deleteUserPosts(th.User.Id)
  1197  
  1198  	t.Run("Should search posts with multiple hashtags", func(t *testing.T) {
  1199  		params := &model.SearchParams{
  1200  			Terms:     "#hashone #hashtwo",
  1201  			IsHashtag: true,
  1202  		}
  1203  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1204  		require.Nil(t, apperr)
  1205  
  1206  		require.Len(t, results.Posts, 1)
  1207  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1208  	})
  1209  
  1210  	t.Run("Should search posts with multiple hashtags using OR", func(t *testing.T) {
  1211  		params := &model.SearchParams{
  1212  			Terms:     "#hashone #hashtwo",
  1213  			IsHashtag: true,
  1214  			OrTerms:   true,
  1215  		}
  1216  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1217  		require.Nil(t, apperr)
  1218  
  1219  		require.Len(t, results.Posts, 2)
  1220  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1221  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1222  	})
  1223  }
  1224  
  1225  func testSearchPostsWithDotsInHashtags(t *testing.T, th *SearchTestHelper) {
  1226  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching hashtag #hashtag.dot", "#hashtag.dot", model.POST_DEFAULT, 0, false)
  1227  	require.Nil(t, err)
  1228  	defer th.deleteUserPosts(th.User.Id)
  1229  
  1230  	params := &model.SearchParams{
  1231  		Terms:     "#hashtag.dot",
  1232  		IsHashtag: true,
  1233  	}
  1234  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1235  	require.Nil(t, apperr)
  1236  
  1237  	require.Len(t, results.Posts, 1)
  1238  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1239  }
  1240  
  1241  func testSearchHashtagCaseInsensitive(t *testing.T, th *SearchTestHelper) {
  1242  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching hashtag #HaShTaG", "#HaShTaG", model.POST_DEFAULT, 0, false)
  1243  	require.Nil(t, err)
  1244  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching hashtag #hashtag", "#hashtag", model.POST_DEFAULT, 0, false)
  1245  	require.Nil(t, err)
  1246  	p3, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching hashtag #HASHTAG", "#HASHTAG", model.POST_DEFAULT, 0, false)
  1247  	require.Nil(t, err)
  1248  	defer th.deleteUserPosts(th.User.Id)
  1249  
  1250  	t.Run("Lower case hashtag", func(t *testing.T) {
  1251  		params := &model.SearchParams{
  1252  			Terms:     "#hashtag",
  1253  			IsHashtag: true,
  1254  		}
  1255  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1256  		require.Nil(t, apperr)
  1257  
  1258  		require.Len(t, results.Posts, 3)
  1259  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1260  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1261  		th.checkPostInSearchResults(t, p3.Id, results.Posts)
  1262  	})
  1263  
  1264  	t.Run("Upper case hashtag", func(t *testing.T) {
  1265  		params := &model.SearchParams{
  1266  			Terms:     "#HASHTAG",
  1267  			IsHashtag: true,
  1268  		}
  1269  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1270  		require.Nil(t, apperr)
  1271  
  1272  		require.Len(t, results.Posts, 3)
  1273  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1274  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1275  		th.checkPostInSearchResults(t, p3.Id, results.Posts)
  1276  	})
  1277  
  1278  	t.Run("Mixed case hashtag", func(t *testing.T) {
  1279  		params := &model.SearchParams{
  1280  			Terms:     "#HaShTaG",
  1281  			IsHashtag: true,
  1282  		}
  1283  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1284  		require.Nil(t, apperr)
  1285  
  1286  		require.Len(t, results.Posts, 3)
  1287  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1288  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1289  		th.checkPostInSearchResults(t, p3.Id, results.Posts)
  1290  	})
  1291  }
  1292  
  1293  func testSearchHashtagWithDash(t *testing.T, th *SearchTestHelper) {
  1294  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching hashtag #hashtag-test", "#hashtag-test", model.POST_DEFAULT, 0, false)
  1295  	require.Nil(t, err)
  1296  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "searching hashtag #hashtagtest", "#hashtagtest", model.POST_DEFAULT, 0, false)
  1297  	require.Nil(t, err)
  1298  	defer th.deleteUserPosts(th.User.Id)
  1299  
  1300  	params := &model.SearchParams{
  1301  		Terms:     "#hashtag-test",
  1302  		IsHashtag: true,
  1303  	}
  1304  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1305  	require.Nil(t, apperr)
  1306  
  1307  	require.Len(t, results.Posts, 1)
  1308  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1309  }
  1310  
  1311  func testSearchHashtagWithNumbers(t *testing.T, th *SearchTestHelper) {
  1312  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching hashtag #h4sht4g", "#h4sht4g", model.POST_DEFAULT, 0, false)
  1313  	require.Nil(t, err)
  1314  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "searching hashtag #hashtag", "#hashtag", model.POST_DEFAULT, 0, false)
  1315  	require.Nil(t, err)
  1316  	defer th.deleteUserPosts(th.User.Id)
  1317  
  1318  	params := &model.SearchParams{
  1319  		Terms:     "#h4sht4g",
  1320  		IsHashtag: true,
  1321  	}
  1322  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1323  	require.Nil(t, apperr)
  1324  
  1325  	require.Len(t, results.Posts, 1)
  1326  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1327  }
  1328  
  1329  func testSearchHashtagWithDots(t *testing.T, th *SearchTestHelper) {
  1330  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching hashtag #hashtag.test", "#hashtag.test", model.POST_DEFAULT, 0, false)
  1331  	require.Nil(t, err)
  1332  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "searching hashtag #hashtagtest", "#hashtagtest", model.POST_DEFAULT, 0, false)
  1333  	require.Nil(t, err)
  1334  	defer th.deleteUserPosts(th.User.Id)
  1335  
  1336  	params := &model.SearchParams{
  1337  		Terms:     "#hashtag.test",
  1338  		IsHashtag: true,
  1339  	}
  1340  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1341  	require.Nil(t, apperr)
  1342  
  1343  	require.Len(t, results.Posts, 1)
  1344  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1345  }
  1346  
  1347  func testSearchHashtagWithUnderscores(t *testing.T, th *SearchTestHelper) {
  1348  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "searching hashtag #hashtag_test", "#hashtag_test", model.POST_DEFAULT, 0, false)
  1349  	require.Nil(t, err)
  1350  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "searching hashtag #hashtagtest", "#hashtagtest", model.POST_DEFAULT, 0, false)
  1351  	require.Nil(t, err)
  1352  	defer th.deleteUserPosts(th.User.Id)
  1353  
  1354  	params := &model.SearchParams{
  1355  		Terms:     "#hashtag_test",
  1356  		IsHashtag: true,
  1357  	}
  1358  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1359  	require.Nil(t, apperr)
  1360  
  1361  	require.Len(t, results.Posts, 1)
  1362  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1363  }
  1364  
  1365  func testSearchShouldExcludeSytemMessages(t *testing.T, th *SearchTestHelper) {
  1366  	_, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "test system message one", "", model.POST_JOIN_CHANNEL, 0, false)
  1367  	require.Nil(t, err)
  1368  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "test system message two", "", model.POST_LEAVE_CHANNEL, 0, false)
  1369  	require.Nil(t, err)
  1370  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "test system message three", "", model.POST_LEAVE_TEAM, 0, false)
  1371  	require.Nil(t, err)
  1372  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "test system message four", "", model.POST_ADD_TO_CHANNEL, 0, false)
  1373  	require.Nil(t, err)
  1374  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "test system message five", "", model.POST_ADD_TO_TEAM, 0, false)
  1375  	require.Nil(t, err)
  1376  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "test system message six", "", model.POST_HEADER_CHANGE, 0, false)
  1377  	require.Nil(t, err)
  1378  	defer th.deleteUserPosts(th.User.Id)
  1379  
  1380  	params := &model.SearchParams{Terms: "test system"}
  1381  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1382  	require.Nil(t, apperr)
  1383  
  1384  	require.Len(t, results.Posts, 0)
  1385  }
  1386  
  1387  func testSearchShouldBeAbleToMatchByMentions(t *testing.T, th *SearchTestHelper) {
  1388  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "test system @testuser", "", model.POST_DEFAULT, 0, false)
  1389  	require.Nil(t, err)
  1390  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "test system testuser", "", model.POST_DEFAULT, 0, false)
  1391  	require.Nil(t, err)
  1392  	p3, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "test system #testuser", "#testuser", model.POST_DEFAULT, 0, false)
  1393  	require.Nil(t, err)
  1394  	defer th.deleteUserPosts(th.User.Id)
  1395  
  1396  	params := &model.SearchParams{Terms: "@testuser"}
  1397  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1398  	require.Nil(t, apperr)
  1399  
  1400  	require.Len(t, results.Posts, 3)
  1401  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1402  	th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1403  	th.checkPostInSearchResults(t, p3.Id, results.Posts)
  1404  }
  1405  
  1406  func testSearchInDeletedOrArchivedChannels(t *testing.T, th *SearchTestHelper) {
  1407  	p1, err := th.createPost(th.User.Id, th.ChannelDeleted.Id, "message in deleted channel", "", model.POST_DEFAULT, 0, false)
  1408  	require.Nil(t, err)
  1409  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "message in regular channel", "", model.POST_DEFAULT, 0, false)
  1410  	require.Nil(t, err)
  1411  	p3, err := th.createPost(th.User.Id, th.ChannelPrivate.Id, "message in private channel", "", model.POST_DEFAULT, 0, false)
  1412  	require.Nil(t, err)
  1413  	defer th.deleteUserPosts(th.User.Id)
  1414  
  1415  	t.Run("Doesn't include posts in deleted channels", func(t *testing.T) {
  1416  		params := &model.SearchParams{Terms: "message", IncludeDeletedChannels: false}
  1417  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1418  		require.Nil(t, apperr)
  1419  
  1420  		require.Len(t, results.Posts, 2)
  1421  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1422  		th.checkPostInSearchResults(t, p3.Id, results.Posts)
  1423  	})
  1424  
  1425  	t.Run("Include posts in deleted channels", func(t *testing.T) {
  1426  		params := &model.SearchParams{Terms: "message", IncludeDeletedChannels: true}
  1427  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1428  		require.Nil(t, apperr)
  1429  
  1430  		require.Len(t, results.Posts, 3)
  1431  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1432  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1433  		th.checkPostInSearchResults(t, p3.Id, results.Posts)
  1434  	})
  1435  
  1436  	t.Run("Include posts in deleted channels using multiple terms", func(t *testing.T) {
  1437  		params := &model.SearchParams{Terms: "message channel", IncludeDeletedChannels: true}
  1438  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1439  		require.Nil(t, apperr)
  1440  
  1441  		require.Len(t, results.Posts, 3)
  1442  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1443  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1444  		th.checkPostInSearchResults(t, p3.Id, results.Posts)
  1445  	})
  1446  
  1447  	t.Run("Include posts in deleted channels using multiple OR terms", func(t *testing.T) {
  1448  		params := &model.SearchParams{
  1449  			Terms:                  "message channel",
  1450  			IncludeDeletedChannels: true,
  1451  			OrTerms:                true,
  1452  		}
  1453  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1454  		require.Nil(t, apperr)
  1455  
  1456  		require.Len(t, results.Posts, 3)
  1457  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1458  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1459  		th.checkPostInSearchResults(t, p3.Id, results.Posts)
  1460  	})
  1461  }
  1462  
  1463  func testSearchTermsWithDashes(t *testing.T, th *SearchTestHelper) {
  1464  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "message with-dash-term", "", model.POST_DEFAULT, 0, false)
  1465  	require.Nil(t, err)
  1466  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "message with dash term", "", model.POST_DEFAULT, 0, false)
  1467  	require.Nil(t, err)
  1468  	defer th.deleteUserPosts(th.User.Id)
  1469  
  1470  	t.Run("Search for terms with dash", func(t *testing.T) {
  1471  		params := &model.SearchParams{Terms: "with-dash-term"}
  1472  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1473  		require.Nil(t, apperr)
  1474  
  1475  		require.Len(t, results.Posts, 1)
  1476  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1477  	})
  1478  
  1479  	t.Run("Search for terms with quoted dash", func(t *testing.T) {
  1480  		params := &model.SearchParams{Terms: "\"with-dash-term\""}
  1481  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1482  		require.Nil(t, apperr)
  1483  
  1484  		require.Len(t, results.Posts, 1)
  1485  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1486  	})
  1487  
  1488  	t.Run("Search for multiple terms with one having dash", func(t *testing.T) {
  1489  		params := &model.SearchParams{Terms: "with-dash-term message"}
  1490  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1491  		require.Nil(t, apperr)
  1492  
  1493  		require.Len(t, results.Posts, 1)
  1494  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1495  	})
  1496  
  1497  	t.Run("Search for multiple OR terms with one having dash", func(t *testing.T) {
  1498  		params := &model.SearchParams{Terms: "with-dash-term message", OrTerms: true}
  1499  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1500  		require.Nil(t, apperr)
  1501  
  1502  		require.Len(t, results.Posts, 2)
  1503  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1504  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1505  	})
  1506  }
  1507  
  1508  func testSearchTermsWithDots(t *testing.T, th *SearchTestHelper) {
  1509  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "message with.dots.term", "", model.POST_DEFAULT, 0, false)
  1510  	require.Nil(t, err)
  1511  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "message with dots term", "", model.POST_DEFAULT, 0, false)
  1512  	require.Nil(t, err)
  1513  	defer th.deleteUserPosts(th.User.Id)
  1514  
  1515  	t.Run("Search for terms with dots", func(t *testing.T) {
  1516  		params := &model.SearchParams{Terms: "with.dots.term"}
  1517  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1518  		require.Nil(t, apperr)
  1519  
  1520  		require.Len(t, results.Posts, 1)
  1521  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1522  	})
  1523  
  1524  	t.Run("Search for terms with quoted dots", func(t *testing.T) {
  1525  		params := &model.SearchParams{Terms: "\"with.dots.term\""}
  1526  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1527  		require.Nil(t, apperr)
  1528  
  1529  		require.Len(t, results.Posts, 1)
  1530  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1531  	})
  1532  
  1533  	t.Run("Search for multiple terms with one having dots", func(t *testing.T) {
  1534  		params := &model.SearchParams{Terms: "with.dots.term message"}
  1535  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1536  		require.Nil(t, apperr)
  1537  
  1538  		require.Len(t, results.Posts, 1)
  1539  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1540  	})
  1541  
  1542  	t.Run("Search for multiple OR terms with one having dots", func(t *testing.T) {
  1543  		params := &model.SearchParams{Terms: "with.dots.term message", OrTerms: true}
  1544  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1545  		require.Nil(t, apperr)
  1546  
  1547  		require.Len(t, results.Posts, 2)
  1548  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1549  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1550  	})
  1551  }
  1552  
  1553  func testSearchTermsWithUnderscores(t *testing.T, th *SearchTestHelper) {
  1554  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "message with_underscores_term", "", model.POST_DEFAULT, 0, false)
  1555  	require.Nil(t, err)
  1556  	p2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "message with underscores term", "", model.POST_DEFAULT, 0, false)
  1557  	require.Nil(t, err)
  1558  	defer th.deleteUserPosts(th.User.Id)
  1559  
  1560  	t.Run("Search for terms with underscores", func(t *testing.T) {
  1561  		params := &model.SearchParams{Terms: "with_underscores_term"}
  1562  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1563  		require.Nil(t, apperr)
  1564  
  1565  		require.Len(t, results.Posts, 1)
  1566  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1567  	})
  1568  
  1569  	t.Run("Search for terms with quoted underscores", func(t *testing.T) {
  1570  		params := &model.SearchParams{Terms: "\"with_underscores_term\""}
  1571  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1572  		require.Nil(t, apperr)
  1573  
  1574  		require.Len(t, results.Posts, 1)
  1575  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1576  	})
  1577  
  1578  	t.Run("Search for multiple terms with one having underscores", func(t *testing.T) {
  1579  		params := &model.SearchParams{Terms: "with_underscores_term message"}
  1580  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1581  		require.Nil(t, apperr)
  1582  
  1583  		require.Len(t, results.Posts, 1)
  1584  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1585  	})
  1586  
  1587  	t.Run("Search for multiple OR terms with one having underscores", func(t *testing.T) {
  1588  		params := &model.SearchParams{Terms: "with_underscores_term message", OrTerms: true}
  1589  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1590  		require.Nil(t, apperr)
  1591  
  1592  		require.Len(t, results.Posts, 2)
  1593  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1594  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1595  	})
  1596  }
  1597  
  1598  func testSearchBotAccountsPosts(t *testing.T, th *SearchTestHelper) {
  1599  	bot, err := th.createBot("testbot", "Test Bot", th.User.Id)
  1600  	require.Nil(t, err)
  1601  	defer th.deleteBot(bot.UserId)
  1602  	err = th.addUserToTeams(model.UserFromBot(bot), []string{th.Team.Id})
  1603  	require.Nil(t, err)
  1604  	p1, err := th.createPost(bot.UserId, th.ChannelBasic.Id, "bot test message", "", model.POST_DEFAULT, 0, false)
  1605  	require.Nil(t, err)
  1606  	p2, err := th.createPost(bot.UserId, th.ChannelPrivate.Id, "bot test message in private", "", model.POST_DEFAULT, 0, false)
  1607  	require.Nil(t, err)
  1608  	defer th.deleteUserPosts(bot.UserId)
  1609  
  1610  	params := &model.SearchParams{Terms: "bot"}
  1611  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1612  	require.Nil(t, apperr)
  1613  
  1614  	require.Len(t, results.Posts, 2)
  1615  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1616  	th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1617  }
  1618  
  1619  func testSupportStemmingAndWildcards(t *testing.T, th *SearchTestHelper) {
  1620  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "approve", "", model.POST_DEFAULT, 0, false)
  1621  	require.Nil(t, err)
  1622  	p2, err := th.createPost(th.User.Id, th.ChannelPrivate.Id, "approved", "", model.POST_DEFAULT, 0, false)
  1623  	require.Nil(t, err)
  1624  	p3, err := th.createPost(th.User.Id, th.ChannelPrivate.Id, "approvedz", "", model.POST_DEFAULT, 0, false)
  1625  	require.Nil(t, err)
  1626  	defer th.deleteUserPosts(th.User.Id)
  1627  
  1628  	t.Run("Should stem appr", func(t *testing.T) {
  1629  		params := &model.SearchParams{Terms: "appr*"}
  1630  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1631  		require.Nil(t, apperr)
  1632  
  1633  		require.Len(t, results.Posts, 3)
  1634  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1635  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1636  		th.checkPostInSearchResults(t, p3.Id, results.Posts)
  1637  	})
  1638  
  1639  	t.Run("Should stem approve", func(t *testing.T) {
  1640  		params := &model.SearchParams{Terms: "approve*"}
  1641  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1642  		require.Nil(t, apperr)
  1643  
  1644  		require.Len(t, results.Posts, 1)
  1645  		th.checkPostInSearchResults(t, p3.Id, results.Posts)
  1646  	})
  1647  }
  1648  
  1649  func testSupportWildcardOutsideQuotes(t *testing.T, th *SearchTestHelper) {
  1650  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "hello world", "", model.POST_DEFAULT, 0, false)
  1651  	require.Nil(t, err)
  1652  	p2, err := th.createPost(th.User.Id, th.ChannelPrivate.Id, "hell or heaven", "", model.POST_DEFAULT, 0, false)
  1653  	require.Nil(t, err)
  1654  	defer th.deleteUserPosts(th.User.Id)
  1655  
  1656  	t.Run("Should return results without quotes", func(t *testing.T) {
  1657  		params := &model.SearchParams{Terms: "hell*"}
  1658  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1659  		require.Nil(t, apperr)
  1660  
  1661  		require.Len(t, results.Posts, 2)
  1662  		th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1663  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1664  	})
  1665  
  1666  	t.Run("Should return just one result with quotes", func(t *testing.T) {
  1667  		params := &model.SearchParams{Terms: "\"hell\"*"}
  1668  		results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1669  		require.Nil(t, apperr)
  1670  
  1671  		require.Len(t, results.Posts, 1)
  1672  		th.checkPostInSearchResults(t, p2.Id, results.Posts)
  1673  	})
  1674  
  1675  }
  1676  
  1677  func testHashtagSearchShouldSupportThreeOrMoreCharacters(t *testing.T, th *SearchTestHelper) {
  1678  	_, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "one char hashtag #1", "#1", model.POST_DEFAULT, 0, false)
  1679  	require.Nil(t, err)
  1680  	_, err = th.createPost(th.User.Id, th.ChannelPrivate.Id, "two chars hashtag #12", "#12", model.POST_DEFAULT, 0, false)
  1681  	require.Nil(t, err)
  1682  	p3, err := th.createPost(th.User.Id, th.ChannelPrivate.Id, "three chars hashtag #123", "#123", model.POST_DEFAULT, 0, false)
  1683  	require.Nil(t, err)
  1684  	defer th.deleteUserPosts(th.User.Id)
  1685  
  1686  	params := &model.SearchParams{Terms: "#123", IsHashtag: true}
  1687  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1688  	require.Nil(t, apperr)
  1689  
  1690  	require.Len(t, results.Posts, 1)
  1691  	th.checkPostInSearchResults(t, p3.Id, results.Posts)
  1692  }
  1693  
  1694  func testSlashShouldNotBeCharSeparator(t *testing.T, th *SearchTestHelper) {
  1695  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "alpha/beta gamma, theta", "", model.POST_DEFAULT, 0, false)
  1696  	require.Nil(t, err)
  1697  	defer th.deleteUserPosts(th.User.Id)
  1698  
  1699  	params := &model.SearchParams{Terms: "gamma"}
  1700  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1701  	require.Nil(t, apperr)
  1702  
  1703  	require.Len(t, results.Posts, 1)
  1704  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1705  
  1706  	params = &model.SearchParams{Terms: "beta"}
  1707  	results, apperr = th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1708  	require.Nil(t, apperr)
  1709  
  1710  	require.Len(t, results.Posts, 1)
  1711  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1712  
  1713  	params = &model.SearchParams{Terms: "alpha"}
  1714  	results, apperr = th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1715  	require.Nil(t, apperr)
  1716  
  1717  	require.Len(t, results.Posts, 1)
  1718  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1719  }
  1720  
  1721  func testSearchEmailsWithoutQuotes(t *testing.T, th *SearchTestHelper) {
  1722  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "message test@test.com", "", model.POST_DEFAULT, 0, false)
  1723  	require.Nil(t, err)
  1724  	_, err = th.createPost(th.User.Id, th.ChannelBasic.Id, "message test2@test.com", "", model.POST_DEFAULT, 0, false)
  1725  	require.Nil(t, err)
  1726  	defer th.deleteUserPosts(th.User.Id)
  1727  
  1728  	params := &model.SearchParams{Terms: "test@test.com"}
  1729  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1730  	require.Nil(t, apperr)
  1731  
  1732  	require.Len(t, results.Posts, 1)
  1733  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1734  }
  1735  
  1736  func testSupportSearchInComments(t *testing.T, th *SearchTestHelper) {
  1737  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "message test@test.com", "", model.POST_DEFAULT, 0, false)
  1738  	require.Nil(t, err)
  1739  	r1, err := th.createReply(th.User.Id, "reply check", "", p1, 0, false)
  1740  	require.Nil(t, err)
  1741  	defer th.deleteUserPosts(th.User.Id)
  1742  
  1743  	params := &model.SearchParams{Terms: "reply"}
  1744  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1745  	require.Nil(t, apperr)
  1746  
  1747  	require.Len(t, results.Posts, 1)
  1748  	th.checkPostInSearchResults(t, r1.Id, results.Posts)
  1749  }
  1750  
  1751  func testSupportSearchTermsWithinLinks(t *testing.T, th *SearchTestHelper) {
  1752  	p1, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "message with link http://www.wikipedia.org/dolphins", "", model.POST_DEFAULT, 0, false)
  1753  	require.Nil(t, err)
  1754  	defer th.deleteUserPosts(th.User.Id)
  1755  
  1756  	params := &model.SearchParams{Terms: "wikipedia"}
  1757  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1758  	require.Nil(t, apperr)
  1759  
  1760  	require.Len(t, results.Posts, 1)
  1761  	th.checkPostInSearchResults(t, p1.Id, results.Posts)
  1762  }
  1763  
  1764  func testShouldNotReturnLinksEmbeddedInMarkdown(t *testing.T, th *SearchTestHelper) {
  1765  	_, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "message with link [here](http://www.wikipedia.org/dolphins)", "", model.POST_DEFAULT, 0, false)
  1766  	require.Nil(t, err)
  1767  	defer th.deleteUserPosts(th.User.Id)
  1768  
  1769  	params := &model.SearchParams{Terms: "wikipedia"}
  1770  	results, apperr := th.Store.Post().SearchPostsInTeamForUser([]*model.SearchParams{params}, th.User.Id, th.Team.Id, false, false, 0, 20)
  1771  	require.Nil(t, apperr)
  1772  
  1773  	require.Len(t, results.Posts, 0)
  1774  }