Fixed issue #2742 - Removing a record drops whole index on Elasticsearch 6 and later.

This commit is contained in:
Martin Edenhofer 2019-09-26 13:41:20 +02:00 committed by Thorsten Eckel
parent c33bd9c7e3
commit f806ac3611
3 changed files with 93 additions and 22 deletions

View file

@ -121,7 +121,7 @@ pre:github:
RAILS_ENV: "test" RAILS_ENV: "test"
script: script:
- bundle exec rake zammad:db:init - bundle exec rake zammad:db:init
- bundle exec rspec -t ~type:system - bundle exec rspec -t ~type:system --t ~searchindex
test:rspec:mysql: test:rspec:mysql:
stage: test stage: test

View file

@ -251,7 +251,12 @@ remove whole data from index
=end =end
def self.remove(type, o_id = nil) def self.remove(type, o_id = nil)
url = build_url(type, o_id, false, false) url = if o_id
build_url(type, o_id, false, true)
else
build_url(type, o_id, false, false)
end
return if url.blank? return if url.blank?
Rails.logger.info "# curl -X DELETE \"#{url}\"" Rails.logger.info "# curl -X DELETE \"#{url}\""
@ -737,7 +742,25 @@ return true if backend is configured
"#{local_index}_#{index.underscore.tr('/', '_')}" "#{local_index}_#{index.underscore.tr('/', '_')}"
end end
def self.build_url(type = nil, o_id = nil, pipeline = true, with_type = true) =begin
generate url for index or document access (only for internal use)
# url to access single document in index (in case with_pipeline or not)
url = SearchIndexBackend.build_url('User', 123, with_pipeline)
# url to access whole index
url = SearchIndexBackend.build_url('User')
# url to access document definition in index (only es6 and higher)
url = SearchIndexBackend.build_url('User', nil, false, true)
# base url
url = SearchIndexBackend.build_url
=end
def self.build_url(type = nil, o_id = nil, with_pipeline = true, with_document_type = true)
return if !SearchIndexBackend.enabled? return if !SearchIndexBackend.enabled?
# for elasticsearch 5.6 and lower # for elasticsearch 5.6 and lower
@ -745,7 +768,7 @@ return true if backend is configured
if Setting.get('es_multi_index') == false if Setting.get('es_multi_index') == false
url = Setting.get('es_url') url = Setting.get('es_url')
url = if type url = if type
if pipeline == true if with_pipeline == true
url_pipline = Setting.get('es_pipeline') url_pipline = Setting.get('es_pipeline')
if url_pipline.present? if url_pipline.present?
url_pipline = "?pipeline=#{url_pipline}" url_pipline = "?pipeline=#{url_pipline}"
@ -764,7 +787,7 @@ return true if backend is configured
# for elasticsearch 6.x and higher # for elasticsearch 6.x and higher
url = Setting.get('es_url') url = Setting.get('es_url')
if pipeline == true if with_pipeline == true
url_pipline = Setting.get('es_pipeline') url_pipline = Setting.get('es_pipeline')
if url_pipline.present? if url_pipline.present?
url_pipline = "?pipeline=#{url_pipline}" url_pipline = "?pipeline=#{url_pipline}"
@ -772,20 +795,36 @@ return true if backend is configured
end end
if type if type
index = build_index_name(type) index = build_index_name(type)
if with_type == false
# access (e. g. creating or dropping) whole index
if with_document_type == false
return "#{url}/#{index}" return "#{url}/#{index}"
end end
# access single document in index (e. g. drop or add document)
if o_id if o_id
return "#{url}/#{index}/_doc/#{o_id}#{url_pipline}" return "#{url}/#{index}/_doc/#{o_id}#{url_pipline}"
end end
# access document type (e. g. creating or dropping document mapping)
return "#{url}/#{index}/_doc#{url_pipline}" return "#{url}/#{index}/_doc#{url_pipline}"
end end
"#{url}/" "#{url}/"
end end
def self.build_search_url(index) =begin
generate url searchaccess (only for internal use)
# url search access with single index
url = SearchIndexBackend.build_search_url('User')
# url to access all over es
url = SearchIndexBackend.build_search_url
=end
def self.build_search_url(index = nil)
# for elasticsearch 5.6 and lower # for elasticsearch 5.6 and lower
if Setting.get('es_multi_index') == false if Setting.get('es_multi_index') == false

View file

@ -18,9 +18,26 @@ RSpec.describe SearchIndexBackend, searchindex: true do
end end
describe '.search' do describe '.search' do
subject(:search) { described_class.search(query, index, limit: 3000) }
context 'query finds results' do
let(:record_type) { 'Ticket'.freeze }
let(:record) { create :ticket }
before do
described_class.add(record_type, record)
described_class.refresh
end
it 'finds added records' do
result = described_class.search(record.number, record_type, sort_by: ['updated_at'], order_by: ['desc'])
expect(result).to eq([{ id: record.id.to_s, type: record_type }])
end
end
context 'for query with no results' do context 'for query with no results' do
subject(:search) { described_class.search(query, index, limit: 3000) }
let(:query) { 'preferences.notification_sound.enabled:*' } let(:query) { 'preferences.notification_sound.enabled:*' }
context 'on a single index' do context 'on a single index' do
@ -107,26 +124,41 @@ RSpec.describe SearchIndexBackend, searchindex: true do
end end
describe '.remove' do describe '.remove' do
context 'ticket' do context 'record gets deleted' do
it 'from index after ticket delete' do
skip('No ES configured') if !described_class.enabled? let(:record_type) { 'Ticket'.freeze }
let(:deleted_record) { create :ticket }
ticket = create :ticket before do
described_class.add('Ticket', ticket) described_class.add(record_type, deleted_record)
described_class.refresh
end
# give es time to rebuild index it 'removes record from search index' do
sleep 2 described_class.remove(record_type, deleted_record.id)
result = described_class.search(ticket.number, 'Ticket', sort_by: ['updated_at'], order_by: ['desc']) described_class.refresh
expect(result).to eq([{ id: ticket.id.to_s, type: 'Ticket' }])
described_class.remove('Ticket', ticket.id) result = described_class.search(deleted_record.number, record_type, sort_by: ['updated_at'], order_by: ['desc'])
# give es time to rebuild index
sleep 2
result = described_class.search(ticket.number, 'Ticket', sort_by: ['updated_at'], order_by: ['desc'])
expect(result).to eq([]) expect(result).to eq([])
end end
context 'other records present' do
let(:other_record) { create :ticket }
before do
described_class.add(record_type, other_record)
described_class.refresh
end
it "doesn't remove other records" do
described_class.remove(record_type, deleted_record.id)
described_class.refresh
result = described_class.search(other_record.number, record_type, sort_by: ['updated_at'], order_by: ['desc'])
expect(result).to eq([{ id: other_record.id.to_s, type: record_type }])
end
end
end end
end end
end end