Maintenance: Added test coverage for public Knowledge Base search.

This commit is contained in:
Mantas Masalskis 2019-09-24 15:04:42 +02:00 committed by Thorsten Eckel
parent 5e38ca46fc
commit 21c3b31c97
10 changed files with 175 additions and 7 deletions

View file

@ -215,18 +215,21 @@ test:integration:clearbit:
### Elasticsearch ### Elasticsearch
.script_integration_es_variables: &script_integration_es_variables
ES_INDEX_RAND: "true"
ES_URL: "http://elasticsearch:9200"
.script_integration_es_template: &script_integration_es_definition .script_integration_es_template: &script_integration_es_definition
<<: *base_env <<: *base_env
stage: test stage: test
variables: variables:
<<: *script_integration_es_variables
RAILS_ENV: "test" RAILS_ENV: "test"
ES_INDEX_RAND: "true"
ES_URL: "http://elasticsearch:9200"
script: script:
- bundle exec rake zammad:db:unseeded - bundle exec rake zammad:db:unseeded
- bundle exec rails test test/integration/elasticsearch_active_test.rb - bundle exec rails test test/integration/elasticsearch_active_test.rb
- bundle exec rails test test/integration/elasticsearch_test.rb - bundle exec rails test test/integration/elasticsearch_test.rb
- bundle exec rspec --tag searchindex - bundle exec rspec --tag searchindex --tag ~type:system
- bundle exec rails test test/integration/report_test.rb - bundle exec rails test test/integration/report_test.rb
test:integration:es:5.6: test:integration:es:5.6:
@ -375,12 +378,14 @@ browser:build:
.variables_capybara_chrome_template: &variables_capybara_chrome_definition .variables_capybara_chrome_template: &variables_capybara_chrome_definition
<<: *test_capybara_definition <<: *test_capybara_definition
variables: variables:
<<: *script_integration_es_variables
RAILS_ENV: "test" RAILS_ENV: "test"
BROWSER: "chrome" BROWSER: "chrome"
.variables_capybara_ff_template: &variables_capybara_ff_definition .variables_capybara_ff_template: &variables_capybara_ff_definition
<<: *test_capybara_definition <<: *test_capybara_definition
variables: variables:
<<: *script_integration_es_variables
RAILS_ENV: "test" RAILS_ENV: "test"
BROWSER: "firefox" BROWSER: "firefox"

View file

@ -868,4 +868,42 @@ return true if backend is configured
data data
end end
=begin
refreshes all indexes to make previous request data visible in future requests
SearchIndexBackend.refresh
=end
def self.refresh
return if !enabled?
url = "#{Setting.get('es_url')}/_all/_refresh"
Rails.logger.info "# curl -X POST \"#{url}\" "
response = UserAgent.post(
url,
{},
{
open_timeout: 8,
read_timeout: 60,
open_socket_tries: 3,
user: Setting.get('es_user'),
password: Setting.get('es_password'),
}
)
Rails.logger.info "# #{response.code}"
return true if response.success?
raise humanized_error(
verb: 'POST',
url: url,
response: response,
)
end
end end

View file

@ -147,6 +147,12 @@ namespace :searchindex do
end end
task :refresh, [:opts] => :environment do |_t, _args|
print 'refresh all indexes...'
SearchIndexBackend.refresh
end
task :rebuild, [:opts] => :environment do |_t, _args| task :rebuild, [:opts] => :environment do |_t, _args|
Rake::Task['searchindex:drop'].execute Rake::Task['searchindex:drop'].execute
Rake::Task['searchindex:create'].execute Rake::Task['searchindex:create'].execute

View file

@ -1,5 +1,9 @@
FactoryBot.define do FactoryBot.define do
factory 'knowledge_base/answer', aliases: %i[knowledge_base_answer] do factory 'knowledge_base/answer', aliases: %i[knowledge_base_answer] do
transient do
add_translation { true }
end
category { create(:knowledge_base_category) } category { create(:knowledge_base_category) }
before(:create) do |answer| before(:create) do |answer|

View file

@ -1,5 +1,9 @@
FactoryBot.define do FactoryBot.define do
factory 'knowledge_base/category', aliases: %i[knowledge_base_category] do factory 'knowledge_base/category', aliases: %i[knowledge_base_category] do
transient do
add_translation { true }
end
knowledge_base { parent&.knowledge_base || create(:knowledge_base) } knowledge_base { parent&.knowledge_base || create(:knowledge_base) }
category_icon { 'f04b' } category_icon { 'f04b' }

View file

@ -0,0 +1,20 @@
RSpec::Matchers.define :allow_to_search_for do |expected|
match do |actual|
search_string = expected.translation.title
actual.find('.js-search-input').fill_in with: search_string
actual.find('.search-results').has_text? search_string
end
description do
"allows to search for \"#{expected.translation.title}\""
end
failure_message do
"could not search for \"#{expected.translation.title}\""
end
failure_message do
"\"#{expected.translation.title}\" showed up in search results"
end
end

View file

@ -16,7 +16,17 @@ module SearchindexBackendHelper
end end
end end
def configure_elasticsearch(required: false) =begin
prepares elasticsearch
@param required [Boolean] raises error if ES is not configured. Recommended to avoid mysterious errors in CI.
@param rebuild [Boolean] rebuilds indexes and sleeps for 1 second after given yield block is executed
@yield given block run after ES is setup, but before index rebuilding
=end
def configure_elasticsearch(required: false, rebuild: false)
if ENV['ES_URL'].blank? if ENV['ES_URL'].blank?
return if !required return if !required
@ -33,7 +43,7 @@ module SearchindexBackendHelper
if ENV['ES_INDEX_RAND'].present? if ENV['ES_INDEX_RAND'].present?
rand_id = ENV.fetch('CI_JOB_ID', "r#{rand(999)}") rand_id = ENV.fetch('CI_JOB_ID', "r#{rand(999)}")
test_method_name = self.class.description.gsub(/[^\w]/, '_') test_method_name = self.class.description.gsub(/[^\w]/, '_')
ENV['ES_INDEX'] = "es_index_#{test_method_name}_#{rand_id}_#{rand(999_999_999)}" ENV['ES_INDEX'] = "es_index_#{test_method_name.downcase}_#{rand_id}_#{rand(999_999_999)}"
end end
if ENV['ES_INDEX'].blank? if ENV['ES_INDEX'].blank?
raise "ERROR: Need ES_INDEX - hint ES_INDEX='estest.local_zammad'" raise "ERROR: Need ES_INDEX - hint ES_INDEX='estest.local_zammad'"
@ -45,16 +55,22 @@ module SearchindexBackendHelper
Setting.set('es_attachment_max_size_in_mb', 1) Setting.set('es_attachment_max_size_in_mb', 1)
yield if block_given? yield if block_given?
return if !rebuild
rebuild_searchindex
end end
def rebuild_searchindex def rebuild_searchindex
Rake::Task.clear Rake::Task.clear
Zammad::Application.load_tasks Zammad::Application.load_tasks
Rake::Task['searchindex:rebuild'].execute Rake::Task['searchindex:rebuild'].execute
Rake::Task['searchindex:refresh'].execute
end end
end end
# configure_elasticsearch has to be executed manually!!!
RSpec.configure do |config| RSpec.configure do |config|
config.include SearchindexBackendHelper, searchindex: true config.include SearchindexBackendHelper, searchindex: true
end end

View file

@ -0,0 +1,30 @@
require 'rails_helper'
RSpec.describe 'Public Knowledge Base for guest search', type: :system, authenticated: true, searchindex: true do
include_context 'basic Knowledge Base'
before do
configure_elasticsearch(required: true, rebuild: true) do
published_answer && answer && internal_answer
end
visit help_no_locale_path
end
it 'shows no results notification for gibberish search' do
find('.js-search-input').fill_in with: 'Asdasdasdasdasd'
expect(page).to have_text 'No results were found'
end
it 'list published article' do
expect(page).to allow_to_search_for published_answer
end
it 'list draft article' do
expect(page).to allow_to_search_for answer
end
it 'list internal article' do
expect(page).to allow_to_search_for internal_answer
end
end

View file

@ -0,0 +1,30 @@
require 'rails_helper'
RSpec.describe 'Public Knowledge Base for guest search', type: :system, authenticated: false, searchindex: true do
include_context 'basic Knowledge Base'
before do
configure_elasticsearch(required: true, rebuild: true) do
published_answer && answer && internal_answer
end
visit help_no_locale_path
end
it 'shows no results notification for gibberish search' do
find('.js-search-input').fill_in with: 'Asdasdasdasdasd'
expect(page).to have_text 'No results were found'
end
it 'list published article' do
expect(page).to allow_to_search_for published_answer
end
it 'not list draft article' do
expect(page).not_to allow_to_search_for answer
end
it 'not list internal article' do
expect(page).not_to allow_to_search_for internal_answer
end
end

View file

@ -13,7 +13,17 @@ module SearchindexHelper
end end
end end
def configure_elasticsearch(required: false) =begin
prepares elasticsearch
@param required [Boolean] raises error if ES is not configured. Recommended to avoid mysterious errors in CI.
@param rebuild [Boolean] rebuilds indexes and sleeps for 1 second after given yield block is executed
@yield given block run after ES is setup, but before index rebuilding
=end
def configure_elasticsearch(required: false, rebuild: false)
if ENV['ES_URL'].blank? if ENV['ES_URL'].blank?
return if !required return if !required
@ -30,7 +40,7 @@ module SearchindexHelper
if ENV['ES_INDEX_RAND'].present? if ENV['ES_INDEX_RAND'].present?
rand_id = ENV.fetch('CI_JOB_ID', "r#{rand(999)}") rand_id = ENV.fetch('CI_JOB_ID', "r#{rand(999)}")
test_method_name = method_name.gsub(/[^\w]/, '_') test_method_name = method_name.gsub(/[^\w]/, '_')
ENV['ES_INDEX'] = "es_index_#{test_method_name}_#{rand_id}_#{rand(999_999_999)}" ENV['ES_INDEX'] = "es_index_#{test_method_name.downcase}_#{rand_id}_#{rand(999_999_999)}"
end end
if ENV['ES_INDEX'].blank? if ENV['ES_INDEX'].blank?
raise "ERROR: Need ES_INDEX - hint ES_INDEX='estest.local_zammad'" raise "ERROR: Need ES_INDEX - hint ES_INDEX='estest.local_zammad'"
@ -42,12 +52,17 @@ module SearchindexHelper
Setting.set('es_attachment_max_size_in_mb', 1) Setting.set('es_attachment_max_size_in_mb', 1)
yield if block_given? yield if block_given?
return if !rebuild
rebuild_searchindex
end end
def rebuild_searchindex def rebuild_searchindex
Rake::Task.clear Rake::Task.clear
Zammad::Application.load_tasks Zammad::Application.load_tasks
Rake::Task['searchindex:rebuild'].execute Rake::Task['searchindex:rebuild'].execute
Rake::Task['searchindex:refresh'].execute
end end
end end