search_index_backend_spec.rb 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. require 'rails_helper'
  2. RSpec.describe SearchIndexBackend, searchindex: true do
  3. before do
  4. configure_elasticsearch
  5. rebuild_searchindex
  6. end
  7. describe '.build_query' do
  8. subject(:query) { described_class.build_query('', query_extension: params) }
  9. let(:params) { { 'bool' => { 'filter' => { 'term' => { 'a' => 'b' } } } } }
  10. it 'coerces :query_extension hash keys to symbols' do
  11. expect(query.dig(:query, :bool, :filter, :term, :a)).to eq('b')
  12. end
  13. end
  14. describe '.search' do
  15. subject(:search) { described_class.search(query, index, limit: 3000) }
  16. context 'for query with no results' do
  17. let(:query) { 'preferences.notification_sound.enabled:*' }
  18. context 'on a single index' do
  19. let(:index) { 'User' }
  20. it { is_expected.to be_an(Array).and be_empty }
  21. end
  22. context 'on multiple indices' do
  23. let(:index) { %w[User Organization] }
  24. it { is_expected.to be_an(Array).and not_include(nil).and be_empty }
  25. end
  26. end
  27. end
  28. describe '.append_wildcard_to_simple_query' do
  29. context 'with "simple" queries' do
  30. let(:queries) { <<~QUERIES.lines.map { |x| x.split('#')[0] }.map(&:strip) }
  31. M
  32. Max
  33. Max. # dot and underscore are acceptable characters in simple queries
  34. A_
  35. A_B
  36. äöü
  37. 123
  38. *ax # wildcards are allowed in simple queries
  39. Max*
  40. M*x
  41. M?x
  42. test@example.com
  43. test@example.
  44. test@example
  45. test@
  46. QUERIES
  47. it 'appends a * to the original query' do
  48. expect(queries.map(&described_class.method(:append_wildcard_to_simple_query)))
  49. .to eq(queries.map { |q| "#{q}*" })
  50. end
  51. end
  52. context 'with "complex" queries (using search operators)' do
  53. let(:queries) { <<~QUERIES.lines.map { |x| x.split('#')[0] }.map(&:strip) }
  54. title:"some words with spaces" # exact phrase / without quotation marks " an AND search for the words will be performed (in Zammad 1.5 and lower an OR search will be performed)
  55. title:"some wor*" # exact phrase beginning with "some wor*" will be searched
  56. created_at:[2017-01-01 TO 2017-12-31] # a time range
  57. created_at:>now-1h # created within last hour
  58. state:new OR state:open
  59. (state:new OR state:open) OR priority:"3 normal"
  60. (state:new OR state:open) AND customer.lastname:smith
  61. state:(new OR open) AND title:(full text search) # state: new OR open & title: full OR text OR search
  62. tags: "some tag"
  63. owner.email: "bod@example.com" AND state: (new OR open OR pending*) # show all open tickets of a certain agent
  64. state:closed AND _missing_:tag # all closed objects without tags
  65. article_count: [1 TO 5] # tickets with 1 to 5 articles
  66. article_count: [10 TO *] # tickets with 10 or more articles
  67. article.from: bob # also article.from can be used
  68. article.body: heat~ # using the fuzzy operator will also find terms that are similar, in this case also "head"
  69. article.body: /joh?n(ath[oa]n)/ # using regular expressions
  70. user:M
  71. user:Max
  72. user:Max.
  73. user:Max*
  74. organization:A_B
  75. organization:A_B*
  76. user: M
  77. user: Max
  78. user: Max.
  79. user: Max*
  80. organization: A_B
  81. organization: A_B*
  82. id:123
  83. number:123
  84. id:"123"
  85. number:"123"
  86. QUERIES
  87. it 'returns the original query verbatim' do
  88. expect(queries.map(&described_class.method(:append_wildcard_to_simple_query)))
  89. .to eq(queries)
  90. end
  91. end
  92. end
  93. describe '.remove' do
  94. context 'ticket' do
  95. it 'from index after ticket delete' do
  96. skip('No ES configured') if !SearchIndexBackend.enabled?
  97. ticket = create :ticket
  98. described_class.add('Ticket', ticket)
  99. # give es time to rebuild index
  100. sleep 2
  101. result = described_class.search(ticket.number, 'Ticket', sort_by: ['updated_at'], order_by: ['desc'])
  102. expect(result).to eq([{ id: ticket.id.to_s, type: 'Ticket' }])
  103. described_class.remove('Ticket', ticket.id)
  104. # give es time to rebuild index
  105. sleep 2
  106. result = described_class.search(ticket.number, 'Ticket', sort_by: ['updated_at'], order_by: ['desc'])
  107. expect(result).to eq([])
  108. end
  109. end
  110. end
  111. end