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