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 }