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
|
|
|
|
actual_count > expected_count + threshold
|
|
|
|
end
|
|
|
|
|
|
|
|
def failure_message
|
|
|
|
threshold_message = threshold > 0 ? " (+#{@threshold})" : ''
|
|
|
|
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-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
|
|
|
|
|
|
|
|
def control_recorder
|
|
|
|
@control_recorder ||= ActiveRecord::QueryRecorder.new(&control)
|
|
|
|
end
|
|
|
|
|
|
|
|
def expected_count
|
|
|
|
@expected_count ||= control_recorder.count
|
|
|
|
end
|
|
|
|
|
|
|
|
def verify_count(&block)
|
|
|
|
@subject_block = block
|
|
|
|
|
|
|
|
(expected_count - actual_count).abs <= threshold
|
|
|
|
end
|
|
|
|
|
|
|
|
match do |block|
|
|
|
|
verify_count(&block)
|
|
|
|
end
|
|
|
|
|
|
|
|
failure_message_when_negated do |actual|
|
|
|
|
failure_message
|
|
|
|
end
|
|
|
|
|
|
|
|
def skip_cached
|
|
|
|
false
|
|
|
|
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
|