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