mirror of
https://github.com/discourse/discourse.git
synced 2024-12-01 07:33:37 +08:00
4dcc5f16f1
The global setting disable_search_queue_threshold (DISCOURSE_DISABLE_SEARCH_QUEUE_THRESHOLD) which default to 1 second was added. This protection ensures that when the application is unable to keep up with requests it will simply turn off search till it is not backed up. To disable this protection set this to 0.
382 lines
10 KiB
Ruby
382 lines
10 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'rails_helper'
|
|
|
|
describe SearchController do
|
|
|
|
fab!(:awesome_post) do
|
|
SearchIndexer.enable
|
|
Fabricate(:post, raw: 'this is my really awesome post')
|
|
end
|
|
|
|
fab!(:user) do
|
|
Fabricate(:user)
|
|
end
|
|
|
|
fab!(:user_post) do
|
|
SearchIndexer.enable
|
|
Fabricate(:post, raw: "#{user.username} is a cool person")
|
|
end
|
|
|
|
context "integration" do
|
|
before do
|
|
SearchIndexer.enable
|
|
end
|
|
|
|
before do
|
|
# TODO be a bit more strategic here instead of junking
|
|
# all of redis
|
|
$redis.flushall
|
|
end
|
|
|
|
after do
|
|
$redis.flushall
|
|
end
|
|
|
|
context "when overloaded" do
|
|
|
|
before do
|
|
global_setting :disable_search_queue_threshold, 0.2
|
|
end
|
|
|
|
let! :start_time do
|
|
freeze_time
|
|
Time.now
|
|
end
|
|
|
|
let! :current_time do
|
|
freeze_time 0.3.seconds.from_now
|
|
end
|
|
|
|
it "errors on #query" do
|
|
|
|
get "/search/query.json", headers: {
|
|
"HTTP_X_REQUEST_START" => "t=#{start_time.to_f}"
|
|
}, params: {
|
|
term: "hi there", include_blurb: true
|
|
}
|
|
|
|
expect(response.status).to eq(409)
|
|
end
|
|
|
|
it "no results and error on #index" do
|
|
get "/search.json", headers: {
|
|
"HTTP_X_REQUEST_START" => "t=#{start_time.to_f}"
|
|
}, params: {
|
|
q: "awesome"
|
|
}
|
|
|
|
expect(response.status).to eq(200)
|
|
|
|
data = JSON.parse(response.body)
|
|
|
|
expect(data["posts"]).to be_empty
|
|
expect(data["grouped_search_result"]["error"]).not_to be_empty
|
|
end
|
|
|
|
end
|
|
|
|
it "returns a 400 error if you search for null bytes" do
|
|
term = "hello\0hello"
|
|
|
|
get "/search/query.json", params: {
|
|
term: term, include_blurb: true
|
|
}
|
|
|
|
expect(response.status).to eq(400)
|
|
end
|
|
|
|
it "can search correctly" do
|
|
get "/search/query.json", params: {
|
|
term: 'awesome', include_blurb: true
|
|
}
|
|
|
|
expect(response.status).to eq(200)
|
|
|
|
data = JSON.parse(response.body)
|
|
|
|
expect(data['posts'].length).to eq(1)
|
|
expect(data['posts'][0]['id']).to eq(awesome_post.id)
|
|
expect(data['posts'][0]['blurb']).to eq(awesome_post.raw)
|
|
expect(data['topics'][0]['id']).to eq(awesome_post.topic_id)
|
|
end
|
|
|
|
it 'performs the query with a type filter' do
|
|
|
|
get "/search/query.json", params: {
|
|
term: user.username, type_filter: 'topic'
|
|
}
|
|
|
|
expect(response.status).to eq(200)
|
|
data = JSON.parse(response.body)
|
|
|
|
expect(data['posts'][0]['id']).to eq(user_post.id)
|
|
expect(data['users']).to be_blank
|
|
|
|
get "/search/query.json", params: {
|
|
term: user.username, type_filter: 'user'
|
|
}
|
|
|
|
expect(response.status).to eq(200)
|
|
data = JSON.parse(response.body)
|
|
|
|
expect(data['posts']).to be_blank
|
|
expect(data['users'][0]['id']).to eq(user.id)
|
|
end
|
|
|
|
context 'searching by topic id' do
|
|
it 'should not be restricted by minimum search term length' do
|
|
SiteSetting.min_search_term_length = 20000
|
|
|
|
get "/search/query.json", params: {
|
|
term: awesome_post.topic_id,
|
|
type_filter: 'topic',
|
|
search_for_id: true
|
|
}
|
|
|
|
expect(response.status).to eq(200)
|
|
data = JSON.parse(response.body)
|
|
|
|
expect(data['topics'][0]['id']).to eq(awesome_post.topic_id)
|
|
end
|
|
|
|
it "should return the right result" do
|
|
|
|
get "/search/query.json", params: {
|
|
term: user_post.topic_id,
|
|
type_filter: 'topic',
|
|
search_for_id: true
|
|
}
|
|
|
|
expect(response.status).to eq(200)
|
|
data = JSON.parse(response.body)
|
|
|
|
expect(data['topics'][0]['id']).to eq(user_post.topic_id)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "#query" do
|
|
it "logs the search term" do
|
|
SiteSetting.log_search_queries = true
|
|
get "/search/query.json", params: { term: 'wookie' }
|
|
|
|
expect(response.status).to eq(200)
|
|
expect(SearchLog.where(term: 'wookie')).to be_present
|
|
|
|
json = JSON.parse(response.body)
|
|
search_log_id = json['grouped_search_result']['search_log_id']
|
|
expect(search_log_id).to be_present
|
|
|
|
log = SearchLog.where(id: search_log_id).first
|
|
expect(log).to be_present
|
|
expect(log.term).to eq('wookie')
|
|
end
|
|
|
|
it "doesn't log when disabled" do
|
|
SiteSetting.log_search_queries = false
|
|
get "/search/query.json", params: { term: 'wookie' }
|
|
expect(response.status).to eq(200)
|
|
expect(SearchLog.where(term: 'wookie')).to be_blank
|
|
end
|
|
end
|
|
|
|
context "#show" do
|
|
it "doesn't raise an error when search term not specified" do
|
|
get "/search"
|
|
expect(response.status).to eq(200)
|
|
end
|
|
|
|
it "raises an error when the search term length is less than required" do
|
|
get "/search.json", params: { q: 'ba' }
|
|
expect(response.status).to eq(400)
|
|
end
|
|
|
|
it "raises an error when search term is a hash" do
|
|
get "/search.json?q[foo]"
|
|
expect(response.status).to eq(400)
|
|
end
|
|
|
|
it "logs the search term" do
|
|
SiteSetting.log_search_queries = true
|
|
get "/search.json", params: { q: 'bantha' }
|
|
expect(response.status).to eq(200)
|
|
expect(SearchLog.where(term: 'bantha')).to be_present
|
|
end
|
|
|
|
it "doesn't log when disabled" do
|
|
SiteSetting.log_search_queries = false
|
|
get "/search.json", params: { q: 'bantha' }
|
|
expect(response.status).to eq(200)
|
|
expect(SearchLog.where(term: 'bantha')).to be_blank
|
|
end
|
|
end
|
|
|
|
context "search context" do
|
|
it "raises an error with an invalid context type" do
|
|
get "/search/query.json", params: {
|
|
term: 'test', search_context: { type: 'security', id: 'hole' }
|
|
}
|
|
expect(response.status).to eq(400)
|
|
end
|
|
|
|
it "raises an error with a missing id" do
|
|
get "/search/query.json",
|
|
params: { term: 'test', search_context: { type: 'user' } }
|
|
expect(response.status).to eq(400)
|
|
end
|
|
|
|
context "with a user" do
|
|
|
|
it "raises an error if the user can't see the context" do
|
|
get "/search/query.json", params: {
|
|
term: 'test', search_context: { type: 'private_messages', id: user.username }
|
|
}
|
|
expect(response).to be_forbidden
|
|
end
|
|
|
|
it 'performs the query with a search context' do
|
|
get "/search/query.json", params: {
|
|
term: 'test', search_context: { type: 'user', id: user.username }
|
|
}
|
|
|
|
expect(response.status).to eq(200)
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
context "#click" do
|
|
after do
|
|
SearchLog.clear_debounce_cache!
|
|
end
|
|
|
|
it "doesn't work wthout the necessary parameters" do
|
|
post "/search/click.json"
|
|
expect(response.status).to eq(400)
|
|
end
|
|
|
|
it "doesn't record the click for a different user" do
|
|
sign_in(user)
|
|
|
|
_, search_log_id = SearchLog.log(
|
|
term: SecureRandom.hex,
|
|
search_type: :header,
|
|
user_id: -10,
|
|
ip_address: '127.0.0.1'
|
|
)
|
|
|
|
post "/search/click", params: {
|
|
search_log_id: search_log_id,
|
|
search_result_id: 12345,
|
|
search_result_type: 'topic'
|
|
}
|
|
|
|
expect(response.status).to eq(200)
|
|
expect(SearchLog.find(search_log_id).search_result_id).to be_blank
|
|
end
|
|
|
|
it "records the click for a logged in user" do
|
|
sign_in(user)
|
|
|
|
_, search_log_id = SearchLog.log(
|
|
term: SecureRandom.hex,
|
|
search_type: :header,
|
|
user_id: user.id,
|
|
ip_address: '127.0.0.1'
|
|
)
|
|
|
|
post "/search/click.json", params: {
|
|
search_log_id: search_log_id,
|
|
search_result_id: 12345,
|
|
search_result_type: 'user'
|
|
}
|
|
|
|
expect(response.status).to eq(200)
|
|
expect(SearchLog.find(search_log_id).search_result_id).to eq(12345)
|
|
expect(SearchLog.find(search_log_id).search_result_type).to eq(SearchLog.search_result_types[:user])
|
|
end
|
|
|
|
it "records the click for an anonymous user" do
|
|
get "/"
|
|
ip_address = request.remote_ip
|
|
|
|
_, search_log_id = SearchLog.log(
|
|
term: SecureRandom.hex,
|
|
search_type: :header,
|
|
ip_address: ip_address
|
|
)
|
|
|
|
post "/search/click.json", params: {
|
|
search_log_id: search_log_id,
|
|
search_result_id: 22222,
|
|
search_result_type: 'topic'
|
|
}
|
|
|
|
expect(response.status).to eq(200)
|
|
expect(SearchLog.find(search_log_id).search_result_id).to eq(22222)
|
|
expect(SearchLog.find(search_log_id).search_result_type).to eq(SearchLog.search_result_types[:topic])
|
|
end
|
|
|
|
it "doesn't record the click for a different IP" do
|
|
_, search_log_id = SearchLog.log(
|
|
term: SecureRandom.hex,
|
|
search_type: :header,
|
|
ip_address: '192.168.0.19'
|
|
)
|
|
|
|
post "/search/click", params: {
|
|
search_log_id: search_log_id,
|
|
search_result_id: 22222,
|
|
search_result_type: 'topic'
|
|
}
|
|
|
|
expect(response.status).to eq(200)
|
|
expect(SearchLog.find(search_log_id).search_result_id).to be_blank
|
|
end
|
|
|
|
it "records the click for search result type category" do
|
|
get "/"
|
|
ip_address = request.remote_ip
|
|
|
|
_, search_log_id = SearchLog.log(
|
|
term: SecureRandom.hex,
|
|
search_type: :header,
|
|
ip_address: ip_address
|
|
)
|
|
|
|
post "/search/click.json", params: {
|
|
search_log_id: search_log_id,
|
|
search_result_id: 23456,
|
|
search_result_type: 'category'
|
|
}
|
|
|
|
expect(response.status).to eq(200)
|
|
expect(SearchLog.find(search_log_id).search_result_id).to eq(23456)
|
|
expect(SearchLog.find(search_log_id).search_result_type).to eq(SearchLog.search_result_types[:category])
|
|
end
|
|
|
|
it "records the click for search result type tag" do
|
|
get "/"
|
|
ip_address = request.remote_ip
|
|
tag = Fabricate(:tag, name: 'test')
|
|
|
|
_, search_log_id = SearchLog.log(
|
|
term: SecureRandom.hex,
|
|
search_type: :header,
|
|
ip_address: ip_address
|
|
)
|
|
|
|
post "/search/click.json", params: {
|
|
search_log_id: search_log_id,
|
|
search_result_id: tag.name,
|
|
search_result_type: 'tag'
|
|
}
|
|
|
|
expect(response.status).to eq(200)
|
|
expect(SearchLog.find(search_log_id).search_result_id).to eq(tag.id)
|
|
expect(SearchLog.find(search_log_id).search_result_type).to eq(SearchLog.search_result_types[:tag])
|
|
end
|
|
end
|
|
end
|