Module: RSpec::SidekiqPro::Matchers::JobMatcher

Includes:
Matchers::Composable
Included in:
EnqueueSidekiqJobs, HaveEnqueuedSidekiqJobs
Defined in:
lib/rspec/sidekiq_pro/matchers/job_matcher.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#actual_jobsObject (readonly)

Returns the value of attribute actual_jobs.



9
10
11
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 9

def actual_jobs
  @actual_jobs
end

#expected_argumentsObject (readonly)

Returns the value of attribute expected_arguments.



9
10
11
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 9

def expected_arguments
  @expected_arguments
end

#expected_batchObject (readonly)

Returns the value of attribute expected_batch.



9
10
11
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 9

def expected_batch
  @expected_batch
end

#expected_countObject (readonly)

Returns the value of attribute expected_count.



9
10
11
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 9

def expected_count
  @expected_count
end

#expected_intervalObject (readonly)

Returns the value of attribute expected_interval.



9
10
11
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 9

def expected_interval
  @expected_interval
end

#expected_least_countObject (readonly)

Returns the value of attribute expected_least_count.



9
10
11
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 9

def expected_least_count
  @expected_least_count
end

#expected_less_countObject (readonly)

Returns the value of attribute expected_less_count.



9
10
11
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 9

def expected_less_count
  @expected_less_count
end

#expected_more_countObject (readonly)

Returns the value of attribute expected_more_count.



9
10
11
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 9

def expected_more_count
  @expected_more_count
end

#expected_most_countObject (readonly)

Returns the value of attribute expected_most_count.



9
10
11
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 9

def expected_most_count
  @expected_most_count
end

#expected_scheduleObject (readonly)

Returns the value of attribute expected_schedule.



9
10
11
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 9

def expected_schedule
  @expected_schedule
end

#expected_timestampObject (readonly)

Returns the value of attribute expected_timestamp.



9
10
11
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 9

def expected_timestamp
  @expected_timestamp
end

#expected_without_batchObject (readonly)

Returns the value of attribute expected_without_batch.



9
10
11
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 9

def expected_without_batch
  @expected_without_batch
end

#worker_classObject (readonly)

Returns the value of attribute worker_class.



9
10
11
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 9

def worker_class
  @worker_class
end

Instance Method Details

#actual_jobs_details_in_failure_messageObject



233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 233

def actual_jobs_details_in_failure_message
  actual_jobs.flat_map do |job|
    job_details_in_failure_message(job).map.with_index do |line, index|
      if actual_jobs.size > 1
        indent = "    "
        indent = "  - " if index.zero?
        line = "#{indent}#{line[2..]}"
      end

      line
    end
  end
end

#actual_jobs_size_in_failure_messageObject



198
199
200
201
202
203
204
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 198

def actual_jobs_size_in_failure_message
  if actual_jobs.empty?
    "no #{worker_class} found"
  else
    "found #{actual_jobs.size} #{worker_class}"
  end
end

#at(timestamp) ⇒ Object



43
44
45
46
47
48
49
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 43

def at(timestamp)
  raise "setting expecations with both `at` and `in` is not supported" if @expected_interval

  @expected_timestamp = timestamp
  @expected_schedule = timestamp.to_i
  self
end

#at_least(count) ⇒ Object



64
65
66
67
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 64

def at_least(count)
  @expected_least_count = count
  self
end

#at_most(count) ⇒ Object



69
70
71
72
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 69

def at_most(count)
  @expected_most_count = count
  self
end

#batch_match?(expected_batch, bid) ⇒ Boolean

Returns:

  • (Boolean)


285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 285

def batch_match?(expected_batch, bid)
  case expected_batch
  when :__undef__
    !bid.nil?
  when String
    expected_batch == bid
  when ::Sidekiq::Batch
    expected_batch.bid == bid
  else
    return unless bid

    batch = ::Sidekiq::Batch.new(bid)
    values_match?(expected_batch, batch)
  end
end

#does_not_match?(jobs) ⇒ Boolean

Returns:

  • (Boolean)


129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 129

def does_not_match?(jobs)
  @actual_jobs = jobs
  filtered_jobs = filter_jobs(actual_jobs)

  if expected_count
    filtered_jobs.count != expected_count
  elsif expected_least_count
    raise ArgumentError, "ambiguous `at_least` matcher used with negative form"
  elsif expected_most_count
    raise ArgumentError, "ambiguous `at_most` matcher used with negative form"
  elsif expected_more_count
    filtered_jobs.count < expected_more_count
  elsif expected_less_count
    filtered_jobs.count > expected_less_count
  else
    filtered_jobs.empty?
  end
end

#exactly(count) ⇒ Object



59
60
61
62
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 59

def exactly(count)
  @expected_count = count
  self
end

#expectations_in_failure_messageObject

rubocop:disable Layout/ExtraSpacing It becomes unreadable when not allowing alignement



208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 208

def expectations_in_failure_message
  message = []
  message << "  exactly:   #{expected_count} time(s)"       if expected_count
  message << "  at least:  #{expected_least_count} time(s)" if expected_least_count
  message << "  at most:   #{expected_most_count} time(s)"  if expected_most_count
  message << "  more than: #{expected_more_count} time(s)"  if expected_more_count
  message << "  less than: #{expected_less_count} time(s)"  if expected_less_count
  message << "  arguments: #{expected_arguments}"           if expected_arguments
  message << "  in:        #{expected_interval_output}"     if expected_interval
  message << "  at:        #{expected_timestamp}"           if expected_timestamp
  message << "  batch:     #{output_batch(expected_batch)}" if expected_batch
  message << "  batch:     no batch"                        if expected_without_batch
  message
end

#expected_interval_outputObject

rubocop:enable Layout/ExtraSpacing



249
250
251
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 249

def expected_interval_output
  "#{expected_interval.inspect} (#{output_schedule(expected_schedule)})"
end

#expected_job_descriptionObject



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 156

def expected_job_description
  description = "#{worker_class} job"

  if expected_count == 1
    description += " once"
  elsif expected_count == 2
    description += " twice"
  elsif expected_count
    description += " #{expected_count} times"
  elsif expected_least_count
    description += " at least #{expected_least_count} times"
  elsif expected_most_count
    description += " at most #{expected_most_count} times"
  elsif expected_more_count
    description += " more than #{expected_more_count} times"
  elsif expected_less_count
    description += " less than #{expected_less_count} times"
  end

  if expected_arguments.is_a?(Proc)
    description += " with some arguments"
  elsif expected_arguments
    description += " with arguments #{expected_arguments}"
  end

  description
end

#failure_message_diffObject



184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 184

def failure_message_diff
  message = []
  message += expectations_in_failure_message
  message << "" if message.any?
  message << actual_jobs_size_in_failure_message

  if expected_arguments || expected_schedule || expected_without_batch || expected_batch
    message[-1] = "#{message[-1]}:"
    message += actual_jobs_details_in_failure_message
  end

  message.join("\n")
end

#filter_jobs(jobs) ⇒ Object



274
275
276
277
278
279
280
281
282
283
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 274

def filter_jobs(jobs)
  jobs.select do |job|
    next if expected_arguments && !values_match?(expected_arguments, job["args"])
    next if expected_schedule && !values_match?(expected_schedule.to_i, job["at"].to_i)
    next if expected_without_batch && job["bid"]
    next if expected_batch && !batch_match?(expected_batch, job["bid"])

    true
  end
end

#in(interval) ⇒ Object



35
36
37
38
39
40
41
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 35

def in(interval)
  raise "setting expecations with both `at` and `in` is not supported" if @expected_timestamp

  @expected_interval = interval
  @expected_schedule = interval.from_now.to_i
  self
end

#job_details_in_failure_message(job) ⇒ Object



223
224
225
226
227
228
229
230
231
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 223

def job_details_in_failure_message(job)
  message = []
  message << "  arguments: #{job["args"]}"                if expected_arguments
  message << "  at:        #{output_schedule(job["at"])}" if expected_schedule && job["at"]
  message << "  at:        no schedule"                   if expected_schedule && !job["at"]
  message << "  batch:     #{output_batch(job["bid"])}"   if (expected_without_batch || expected_batch) && job["bid"]
  message << "  batch:     no batch"                      if (expected_without_batch || expected_batch) && !job["bid"]
  message
end

#less_than(count) ⇒ Object



79
80
81
82
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 79

def less_than(count)
  @expected_less_count = count
  self
end

#matches?(jobs) ⇒ Boolean

Returns:

  • (Boolean)


110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 110

def matches?(jobs)
  @actual_jobs = jobs
  filtered_jobs = filter_jobs(actual_jobs)

  if expected_count
    filtered_jobs.count == expected_count
  elsif expected_least_count
    filtered_jobs.count >= expected_least_count
  elsif expected_most_count
    filtered_jobs.count <= expected_most_count
  elsif expected_more_count
    filtered_jobs.count > expected_more_count
  elsif expected_less_count
    filtered_jobs.count < expected_less_count
  else
    filtered_jobs.any?
  end
end

#more_than(count) ⇒ Object



74
75
76
77
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 74

def more_than(count)
  @expected_more_count = count
  self
end

#normalize_arguments(arguments) ⇒ Object



148
149
150
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 148

def normalize_arguments(arguments)
  JSON.parse(JSON.dump(arguments))
end

#onceObject



51
52
53
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 51

def once
  exactly(1)
end

#output_arguments(arguments) ⇒ Object



152
153
154
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 152

def output_arguments(arguments)
  arguments.map(&:inspect).join(", ")
end

#output_batch(value) ⇒ Object



257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 257

def output_batch(value)
  case value
  when :__undef__
    "to be present"
  when String
    "<Sidekiq::Batch bid: #{value.inspect}>"
  when Sidekiq::Batch
    "<Sidekiq::Batch bid: #{value.bid.inspect}>"
  else
    if value.respond_to?(:description)
      value.description
    else
      value
    end
  end
end

#output_schedule(timestamp) ⇒ Object



253
254
255
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 253

def output_schedule(timestamp)
  Time.at(timestamp) if timestamp
end

#timesObject Also known as: time



84
85
86
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 84

def times
  self
end

#twiceObject



55
56
57
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 55

def twice
  exactly(2)
end

#with(*expected_arguments, &block) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 23

def with(*expected_arguments, &block)
  if block
    raise ArgumentError, "setting block to `with` is not supported for this matcher" if supports_value_expectations?
    raise ArgumentError, "setting arguments and block together in `with` is not supported" if expected_arguments.any?
    @expected_arguments = block
  else
    @expected_arguments = normalize_arguments(expected_arguments)
  end

  self
end

#within_batch(batch_expectation = :__undef__, &block) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 96

def within_batch(batch_expectation = :__undef__, &block)
  raise "setting expecations with both `without_batch` and `within_batch` is not supported" if @expected_without_batch

  if block
    raise ArgumentError, "setting arguments and block together in `with_batch` is not supported" if batch_expectation != :__undef__

    @expected_batch = block
  else
    @expected_batch = batch_expectation
  end

  self
end

#without_batchObject



89
90
91
92
93
94
# File 'lib/rspec/sidekiq_pro/matchers/job_matcher.rb', line 89

def without_batch
  raise "setting expecations with both `without_batch` and `within_batch` is not supported" if @expected_batch

  @expected_without_batch = true
  self
end