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