debian-mirror-gitlab/spec/support/matchers/exceed_query_limit.rb

233 lines
4.7 KiB
Ruby
Raw Normal View History

2019-10-12 21:52:04 +05:30
# frozen_string_literal: true
2018-11-08 19:23:39 +05:30
module ExceedQueryLimitHelpers
2020-04-08 14:13:33 +05:30
MARGINALIA_ANNOTATION_REGEX = %r{\s*\/\*.*\*\/}.freeze
2018-03-17 18:26:18 +05:30
def with_threshold(threshold)
@threshold = threshold
self
end
def for_query(query)
@query = query
self
end
def threshold
@threshold.to_i
end
def expected_count
if expected.is_a?(ActiveRecord::QueryRecorder)
expected.count
else
expected
end
end
def actual_count
@actual_count ||= if @query
recorder.log.select { |recorded| recorded =~ @query }.size
else
recorder.count
end
end
def recorder
2018-11-08 19:23:39 +05:30
@recorder ||= ActiveRecord::QueryRecorder.new(skip_cached: skip_cached, &@subject_block)
2018-03-17 18:26:18 +05:30
end
def count_queries(queries)
queries.each_with_object(Hash.new(0)) { |query, counts| counts[query] += 1 }
2017-08-17 22:00:37 +05:30
end
2018-03-17 18:26:18 +05:30
def log_message
if expected.is_a?(ActiveRecord::QueryRecorder)
2020-04-08 14:13:33 +05:30
counts = count_queries(strip_marginalia_annotations(expected.log))
extra_queries = strip_marginalia_annotations(@recorder.log).reject { |query| counts[query] -= 1 unless counts[query].zero? }
2018-03-17 18:26:18 +05:30
extra_queries_display = count_queries(extra_queries).map { |query, count| "[#{count}] #{query}" }
(['Extra queries:'] + extra_queries_display).join("\n\n")
else
@recorder.log_message
end
2017-08-17 22:00:37 +05:30
end
2018-11-08 19:23:39 +05:30
def skip_cached
true
end
def verify_count(&block)
@subject_block = block
2020-06-23 00:09:42 +05:30
actual_count > maximum
end
def maximum
expected_count + threshold
2018-11-08 19:23:39 +05:30
end
def failure_message
2020-06-23 00:09:42 +05:30
threshold_message = threshold > 0 ? " (+#{threshold})" : ''
2018-11-08 19:23:39 +05:30
counts = "#{expected_count}#{threshold_message}"
"Expected a maximum of #{counts} queries, got #{actual_count}:\n\n#{log_message}"
end
2020-04-08 14:13:33 +05:30
def strip_marginalia_annotations(logs)
logs.map { |log| log.sub(MARGINALIA_ANNOTATION_REGEX, '') }
end
2018-11-08 19:23:39 +05:30
end
2020-06-23 00:09:42 +05:30
RSpec::Matchers.define :issue_fewer_queries_than do
supports_block_expectations
include ExceedQueryLimitHelpers
def control
block_arg
end
def control_recorder
@control_recorder ||= ActiveRecord::QueryRecorder.new(&control)
end
def expected_count
control_recorder.count
end
def verify_count(&block)
@subject_block = block
# These blocks need to be evaluated in an expected order, in case
# the events in expected affect the counts in actual
expected_count
actual_count
actual_count < expected_count
end
match do |block|
verify_count(&block)
end
def failure_message
<<~MSG
Expected to issue fewer than #{expected_count} queries, but got #{actual_count}
#{log_message}
MSG
end
failure_message_when_negated do |actual|
<<~MSG
Expected query count of #{actual_count} to be less than #{expected_count}
#{log_message}
MSG
end
end
2020-04-22 19:07:51 +05:30
RSpec::Matchers.define :issue_same_number_of_queries_as do
supports_block_expectations
include ExceedQueryLimitHelpers
def control
block_arg
end
2020-06-23 00:09:42 +05:30
chain :or_fewer do
@or_fewer = true
end
chain :ignoring_cached_queries do
@skip_cached = true
end
2020-04-22 19:07:51 +05:30
def control_recorder
@control_recorder ||= ActiveRecord::QueryRecorder.new(&control)
end
def expected_count
2020-06-23 00:09:42 +05:30
control_recorder.count
2020-04-22 19:07:51 +05:30
end
def verify_count(&block)
@subject_block = block
2020-06-23 00:09:42 +05:30
# These blocks need to be evaluated in an expected order, in case
# the events in expected affect the counts in actual
expected_count
actual_count
if @or_fewer
actual_count <= expected_count
else
(expected_count - actual_count).abs <= threshold
end
2020-04-22 19:07:51 +05:30
end
match do |block|
verify_count(&block)
end
2020-06-23 00:09:42 +05:30
def failure_message
<<~MSG
Expected #{expected_count_message} queries, but got #{actual_count}
#{log_message}
MSG
end
2020-04-22 19:07:51 +05:30
failure_message_when_negated do |actual|
2020-06-23 00:09:42 +05:30
<<~MSG
Expected #{actual_count} not to equal #{expected_count_message}
#{log_message}
MSG
end
def expected_count_message
or_fewer_msg = "or fewer" if @or_fewer
threshold_msg = "(+/- #{threshold})" unless threshold.zero?
["#{expected_count}", or_fewer_msg, threshold_msg].compact.join(' ')
2020-04-22 19:07:51 +05:30
end
def skip_cached
2020-06-23 00:09:42 +05:30
@skip_cached || false
2020-04-22 19:07:51 +05:30
end
end
2018-11-08 19:23:39 +05:30
RSpec::Matchers.define :exceed_all_query_limit do |expected|
supports_block_expectations
include ExceedQueryLimitHelpers
match do |block|
verify_count(&block)
end
failure_message_when_negated do |actual|
failure_message
end
def skip_cached
false
end
end
# Excludes cached methods from the query count
RSpec::Matchers.define :exceed_query_limit do |expected|
supports_block_expectations
include ExceedQueryLimitHelpers
match do |block|
verify_count(&block)
end
failure_message_when_negated do |actual|
failure_message
end
2017-08-17 22:00:37 +05:30
end