rspec-sidekiq 2.2.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +11 -0
- data/README.md +21 -0
- data/lib/rspec/sidekiq/batch.rb +3 -1
- data/lib/rspec/sidekiq/helpers/within_sidekiq_retries_exhausted_block.rb +7 -3
- data/lib/rspec/sidekiq/matchers/be_unique.rb +68 -10
- data/lib/rspec/sidekiq/matchers/have_enqueued_job.rb +122 -17
- data/lib/rspec/sidekiq/version.rb +1 -1
- data/rspec-sidekiq.gemspec +2 -1
- data/spec/rspec/sidekiq/batch_spec.rb +46 -9
- data/spec/rspec/sidekiq/helpers/retries_exhausted_spec.rb +16 -4
- data/spec/rspec/sidekiq/matchers/be_unique_spec.rb +59 -6
- data/spec/rspec/sidekiq/matchers/have_enqueued_job_spec.rb +137 -33
- data/spec/rspec/sidekiq/version_spec.rb +1 -1
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 71242ca35cdc2cccbfbae1008db364d84f58a1f1
|
4
|
+
data.tar.gz: 6114262aa4025c8d10b982d3a7261b36667318bb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 861094f58471094e392603b3978e9c95d8f6ca0ca1da86ff064831d0bd42c28c4ea8fac5c779a01b030286bbab6bde0ca378b066bf8635706cd7f2e9a00583d1
|
7
|
+
data.tar.gz: 0f6a5cd8b3f6a5fbc436e4594d96cc25286a9631a7f93941878f87df7ccb8dc313e2ce3fa21535c1b442d5fa2849526a22c003afee4d59315b10992690d43b7e
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
3.0.0
|
2
|
+
---
|
3
|
+
* Use default arguments for NullStatus initialization [briansharon#111]
|
4
|
+
* Fix at and in chainable methods [wpolicarpo#109]
|
5
|
+
* Rely on all of RSpec in development [packrat386#101]
|
6
|
+
* Pass exception to within_sidekiq_retries_exhausted_block [packrat386#100]
|
7
|
+
* Add support for testing scheduled jobs [wpolicarpo#81]
|
8
|
+
* only depend on rspec-core [urkle#96]
|
9
|
+
* Add support for Sidekiq Enterprise [Geesu#82]
|
10
|
+
* Fix clash with rspec-rails [pavel-jurasek-bcgdv-com#95]
|
11
|
+
|
1
12
|
2.2.0
|
2
13
|
---
|
3
14
|
* Fix typo in README file [bradhaydon#87]
|
data/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
**Welcome @wpolicarpo and @packrat386 as new maintainers for `rspec-sidekiq`!**
|
2
|
+
|
1
3
|
# RSpec for Sidekiq
|
2
4
|
|
3
5
|
[![RubyGems][gem_version_badge]][ruby_gems]
|
@@ -124,6 +126,7 @@ sidekiq_options unique: true
|
|
124
126
|
expect(AwesomeJob).to be_unique
|
125
127
|
it { is_expected.to be_unique }
|
126
128
|
```
|
129
|
+
|
127
130
|
### be_expired_in
|
128
131
|
*Describes when a job should expire*
|
129
132
|
```ruby
|
@@ -141,6 +144,19 @@ AwesomeJob.perform_async 'Awesome', true
|
|
141
144
|
expect(AwesomeJob).to have_enqueued_job('Awesome', true)
|
142
145
|
```
|
143
146
|
|
147
|
+
#### Testing scheduled jobs
|
148
|
+
*Use chainable matchers `#at` and `#in`*
|
149
|
+
```ruby
|
150
|
+
Awesomejob.perform_at 5.minutes.from_now, 'Awesome', true
|
151
|
+
# test with...
|
152
|
+
expect(AwesomeJob).to have_enqueued_job('Awesome', true).at(5.minutes.from_now)
|
153
|
+
```
|
154
|
+
```ruby
|
155
|
+
Awesomejob.perform_in 5.minutes, 'Awesome', true
|
156
|
+
# test with...
|
157
|
+
expect(AwesomeJob).to have_enqueued_job('Awesome', true).in(5.minutes)
|
158
|
+
```
|
159
|
+
|
144
160
|
## Example matcher usage
|
145
161
|
```ruby
|
146
162
|
require 'spec_helper'
|
@@ -180,6 +196,11 @@ FooClass.within_sidekiq_retries_exhausted_block {
|
|
180
196
|
## Testing
|
181
197
|
```bundle exec rspec spec```
|
182
198
|
|
199
|
+
## Maintainers
|
200
|
+
* @wpolicarpo
|
201
|
+
* @packrat386
|
202
|
+
* @philostler
|
203
|
+
|
183
204
|
## Contribute
|
184
205
|
Please do! If there's a feature missing that you'd love to see then get in on the action!
|
185
206
|
|
data/lib/rspec/sidekiq/batch.rb
CHANGED
@@ -33,7 +33,7 @@ if defined? Sidekiq::Batch
|
|
33
33
|
class NullStatus < NullObject
|
34
34
|
attr_reader :bid
|
35
35
|
|
36
|
-
def initialize(bid, callbacks)
|
36
|
+
def initialize(bid = SecureRandom.hex(8), callbacks = [])
|
37
37
|
@bid = bid
|
38
38
|
@callbacks = callbacks
|
39
39
|
end
|
@@ -59,6 +59,7 @@ if defined? Sidekiq::Batch
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
+
# :nocov:
|
62
63
|
RSpec.configure do |config|
|
63
64
|
config.before(:each) do |example|
|
64
65
|
next if example.metadata[:stub_batches] == false
|
@@ -76,4 +77,5 @@ if defined? Sidekiq::Batch
|
|
76
77
|
def mocked_with_mocha?
|
77
78
|
Sidekiq::Batch.respond_to? :stubs
|
78
79
|
end
|
80
|
+
# :nocov:
|
79
81
|
end
|
@@ -1,12 +1,12 @@
|
|
1
1
|
module Sidekiq
|
2
2
|
module Worker
|
3
3
|
module ClassMethods
|
4
|
-
def within_sidekiq_retries_exhausted_block(user_msg = {}, &block)
|
4
|
+
def within_sidekiq_retries_exhausted_block(user_msg = {}, exception = default_retries_exhausted_exception, &block)
|
5
5
|
block.call
|
6
|
-
sidekiq_retries_exhausted_block.call
|
6
|
+
sidekiq_retries_exhausted_block.call(default_retries_exhausted_message.merge(user_msg), exception)
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
9
|
+
def default_retries_exhausted_message
|
10
10
|
{
|
11
11
|
'queue' => get_sidekiq_options[:worker],
|
12
12
|
'class' => name,
|
@@ -14,6 +14,10 @@ module Sidekiq
|
|
14
14
|
'error_message' => 'An error occured'
|
15
15
|
}
|
16
16
|
end
|
17
|
+
|
18
|
+
def default_retries_exhausted_exception
|
19
|
+
StandardError.new('An error occured')
|
20
|
+
end
|
17
21
|
end
|
18
22
|
end
|
19
23
|
end
|
@@ -6,22 +6,80 @@ module RSpec
|
|
6
6
|
end
|
7
7
|
|
8
8
|
class BeUnique
|
9
|
-
def
|
10
|
-
|
9
|
+
def self.new
|
10
|
+
if defined?(::Sidekiq::Enterprise)
|
11
|
+
SidekiqEnterprise.new
|
12
|
+
elsif defined?(::SidekiqUniqueJobs)
|
13
|
+
SidekiqUniqueJobs.new
|
14
|
+
else
|
15
|
+
fail "No support found for Sidekiq unique jobs"
|
16
|
+
end
|
11
17
|
end
|
12
18
|
|
13
|
-
|
14
|
-
|
19
|
+
class Base
|
20
|
+
def description
|
21
|
+
'be unique in the queue'
|
22
|
+
end
|
23
|
+
|
24
|
+
def failure_message
|
25
|
+
if !interval_matches? && @expected_interval
|
26
|
+
"expected #{@klass} to be unique for #{@expected_interval} seconds, "\
|
27
|
+
"but its interval was #{actual_interval} seconds"
|
28
|
+
else
|
29
|
+
"expected #{@klass} to be unique in the queue"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def matches?(job)
|
34
|
+
@klass = job.is_a?(Class) ? job : job.class
|
35
|
+
@actual = @klass.get_sidekiq_options[unique_key]
|
36
|
+
!!(value_matches? && interval_matches?)
|
37
|
+
end
|
38
|
+
|
39
|
+
def for(interval)
|
40
|
+
@expected_interval = interval
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
def interval_specified?
|
45
|
+
@expected_interval
|
46
|
+
end
|
47
|
+
|
48
|
+
def interval_matches?
|
49
|
+
!interval_specified? || actual_interval == @expected_interval
|
50
|
+
end
|
51
|
+
|
52
|
+
def failure_message_when_negated
|
53
|
+
"expected #{@klass} to not be unique in the queue"
|
54
|
+
end
|
15
55
|
end
|
16
56
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
57
|
+
class SidekiqUniqueJobs < Base
|
58
|
+
def actual_interval
|
59
|
+
@klass.get_sidekiq_options['unique_job_expiration']
|
60
|
+
end
|
61
|
+
|
62
|
+
def value_matches?
|
63
|
+
[true, :all].include?(@actual)
|
64
|
+
end
|
65
|
+
|
66
|
+
def unique_key
|
67
|
+
'unique'
|
68
|
+
end
|
21
69
|
end
|
22
70
|
|
23
|
-
|
24
|
-
|
71
|
+
class SidekiqEnterprise < Base
|
72
|
+
def actual_interval
|
73
|
+
@actual
|
74
|
+
end
|
75
|
+
|
76
|
+
def value_matches?
|
77
|
+
@actual && @actual > 0
|
78
|
+
end
|
79
|
+
|
80
|
+
def unique_key
|
81
|
+
'unique_for'
|
82
|
+
end
|
25
83
|
end
|
26
84
|
end
|
27
85
|
end
|
@@ -5,11 +5,110 @@ module RSpec
|
|
5
5
|
HaveEnqueuedJob.new expected_arguments
|
6
6
|
end
|
7
7
|
|
8
|
+
if Gem::Dependency.new('rspec-rails', '>= 3.4.0').matching_specs.max_by(&:version)
|
9
|
+
warn "[DEPRECATION] `have_enqueued_job` is deprecated. Please use `have_enqueued_sidekiq_job` instead."
|
10
|
+
alias have_enqueued_sidekiq_job have_enqueued_job
|
11
|
+
end
|
12
|
+
|
13
|
+
class JobOptionParser
|
14
|
+
attr_reader :job
|
15
|
+
|
16
|
+
def initialize(job)
|
17
|
+
@job = job
|
18
|
+
end
|
19
|
+
|
20
|
+
def matches?(option, value)
|
21
|
+
raise ArgumentError, "Option `#{option}` is not defined." unless %w(in at).include?(option.to_s)
|
22
|
+
send("#{option}_evaluator", value)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def at_evaluator(value)
|
28
|
+
return false if job['at'].blank?
|
29
|
+
value.to_time.to_s == Time.at(job['at']).to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
def in_evaluator(value)
|
33
|
+
return false if job['at'].blank?
|
34
|
+
(Time.now + value).to_s == Time.at(job['at']).to_s
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class JobMatcher
|
39
|
+
attr_reader :jobs
|
40
|
+
|
41
|
+
def initialize(klass)
|
42
|
+
@jobs = unwrap_jobs(klass.jobs)
|
43
|
+
end
|
44
|
+
|
45
|
+
def present?(arguments, options)
|
46
|
+
find_job(arguments, options).present?
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def matches?(job, arguments, options)
|
52
|
+
arguments_matches?(job, arguments) &&
|
53
|
+
options_matches?(job, options)
|
54
|
+
end
|
55
|
+
|
56
|
+
def arguments_matches?(job, arguments)
|
57
|
+
arguments_got = job_arguments(job)
|
58
|
+
contain_exactly?(arguments, arguments_got)
|
59
|
+
end
|
60
|
+
|
61
|
+
def options_matches?(job, options)
|
62
|
+
options.all? do |option, value|
|
63
|
+
parser = JobOptionParser.new(job)
|
64
|
+
parser.matches?(option, value)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def find_job(arguments, options)
|
69
|
+
jobs.find { |job| matches?(job, arguments, options) }
|
70
|
+
end
|
71
|
+
|
72
|
+
def job_arguments(job)
|
73
|
+
args = job['args']
|
74
|
+
return args[0]['arguments'] if args.is_a?(Array) && args[0].is_a?(Hash) && args[0].has_key?('arguments')
|
75
|
+
args
|
76
|
+
end
|
77
|
+
|
78
|
+
def unwrap_jobs(jobs)
|
79
|
+
return jobs if jobs.is_a?(Array)
|
80
|
+
jobs.values.flatten
|
81
|
+
end
|
82
|
+
|
83
|
+
def contain_exactly?(expected, got)
|
84
|
+
exactly = RSpec::Matchers::BuiltIn::ContainExactly.new(expected)
|
85
|
+
exactly.matches?(got)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
8
89
|
class HaveEnqueuedJob
|
9
|
-
attr_reader :klass, :expected_arguments, :
|
90
|
+
attr_reader :klass, :expected_arguments, :actual_arguments, :expected_options, :actual_options
|
10
91
|
|
11
92
|
def initialize(expected_arguments)
|
12
93
|
@expected_arguments = normalize_arguments(expected_arguments)
|
94
|
+
@expected_options = {}
|
95
|
+
end
|
96
|
+
|
97
|
+
def matches?(klass)
|
98
|
+
@klass = klass
|
99
|
+
@actual_arguments = unwrapped_job_arguments(klass.jobs)
|
100
|
+
@actual_options = unwrapped_job_options(klass.jobs)
|
101
|
+
JobMatcher.new(klass).present?(expected_arguments, expected_options)
|
102
|
+
end
|
103
|
+
|
104
|
+
def at(timestamp)
|
105
|
+
@expected_options['at'] = timestamp
|
106
|
+
self
|
107
|
+
end
|
108
|
+
|
109
|
+
def in(interval)
|
110
|
+
@expected_options['in'] = interval
|
111
|
+
self
|
13
112
|
end
|
14
113
|
|
15
114
|
def description
|
@@ -17,30 +116,39 @@ module RSpec
|
|
17
116
|
end
|
18
117
|
|
19
118
|
def failure_message
|
20
|
-
"expected to have an enqueued #{klass} job
|
21
|
-
"
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
@actual.any? { |arguments| contain_exactly?(arguments) }
|
119
|
+
message = ["expected to have an enqueued #{klass} job"]
|
120
|
+
message << " arguments: #{expected_arguments}" if expected_arguments
|
121
|
+
message << " options: #{expected_options}" if expected_options.any?
|
122
|
+
message << "found"
|
123
|
+
message << " arguments: #{actual_arguments}" if expected_arguments
|
124
|
+
message << " options: #{actual_options}" if expected_options.any?
|
125
|
+
message.join("\n")
|
28
126
|
end
|
29
127
|
|
30
128
|
def failure_message_when_negated
|
31
|
-
"expected to
|
129
|
+
message = ["expected not to have an enqueued #{klass} job"]
|
130
|
+
message << " arguments: #{expected_arguments}" if expected_arguments.any?
|
131
|
+
message << " options: #{expected_options}" if expected_options.any?
|
132
|
+
message.join("\n")
|
32
133
|
end
|
33
134
|
|
34
135
|
private
|
35
136
|
|
137
|
+
def unwrapped_job_options(jobs)
|
138
|
+
jobs = jobs.values if jobs.is_a?(Hash)
|
139
|
+
jobs.flatten.map do |job|
|
140
|
+
job.slice('at')
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
36
144
|
def unwrapped_job_arguments(jobs)
|
37
145
|
if jobs.is_a? Hash
|
38
146
|
jobs.values.flatten.map do |job|
|
39
|
-
map_arguments(job)
|
147
|
+
map_arguments(job)
|
40
148
|
end
|
41
149
|
else
|
42
150
|
map_arguments(jobs)
|
43
|
-
end
|
151
|
+
end.map { |job| job.flatten }
|
44
152
|
end
|
45
153
|
|
46
154
|
def map_arguments(job)
|
@@ -56,11 +164,6 @@ module RSpec
|
|
56
164
|
hash['arguments'] || hash['args'] if hash.is_a? Hash
|
57
165
|
end
|
58
166
|
|
59
|
-
def contain_exactly?(arguments)
|
60
|
-
exactly = RSpec::Matchers::BuiltIn::ContainExactly.new(expected_arguments)
|
61
|
-
exactly.matches?(arguments)
|
62
|
-
end
|
63
|
-
|
64
167
|
def normalize_arguments(args)
|
65
168
|
if args.is_a?(Array)
|
66
169
|
args.map{ |x| normalize_arguments(x) }
|
@@ -68,6 +171,8 @@ module RSpec
|
|
68
171
|
args.each_with_object({}) do |(key, value), hash|
|
69
172
|
hash[key.to_s] = normalize_arguments(value)
|
70
173
|
end
|
174
|
+
elsif args.is_a?(Symbol)
|
175
|
+
args.to_s
|
71
176
|
else
|
72
177
|
args
|
73
178
|
end
|
data/rspec-sidekiq.gemspec
CHANGED
@@ -11,9 +11,10 @@ Gem::Specification.new do |s|
|
|
11
11
|
s.description = 'Simple testing of Sidekiq jobs via a collection of matchers and helpers'
|
12
12
|
s.license = 'MIT'
|
13
13
|
|
14
|
-
s.add_dependency 'rspec', '~> 3.0', '>= 3.0.0'
|
14
|
+
s.add_dependency 'rspec-core', '~> 3.0', '>= 3.0.0'
|
15
15
|
s.add_dependency 'sidekiq', '>= 2.4.0'
|
16
16
|
|
17
|
+
s.add_development_dependency 'rspec', '~> 3.0'
|
17
18
|
s.add_development_dependency 'coveralls', '~> 0.8', '>= 0.8.0'
|
18
19
|
s.add_development_dependency 'fuubar', '~> 2.0', '>= 2.0.0'
|
19
20
|
s.add_development_dependency 'activejob', '~> 4.2', '>= 4.0.0'
|
@@ -10,31 +10,68 @@ RSpec.describe 'Batch' do
|
|
10
10
|
|
11
11
|
load File.expand_path(File.join(File.dirname(__FILE__), '../../../lib/rspec/sidekiq/batch.rb'))
|
12
12
|
|
13
|
+
describe 'NullObject' do
|
14
|
+
describe '#method_missing' do
|
15
|
+
it 'returns itself' do
|
16
|
+
batch = Sidekiq::Batch.new
|
17
|
+
expect(batch.non_existent_method).to eq(batch)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe 'NullBatch' do
|
23
|
+
end
|
24
|
+
|
13
25
|
describe 'NullStatus' do
|
26
|
+
let(:batch) { Sidekiq::Batch.new }
|
27
|
+
|
28
|
+
subject { batch.status }
|
29
|
+
|
14
30
|
describe '#total' do
|
15
31
|
it 'returns 0 when no jobs' do
|
16
|
-
|
17
|
-
expect(null_status.total).to eq(0)
|
32
|
+
expect(subject.total).to eq(0)
|
18
33
|
end
|
19
34
|
|
20
35
|
it 'returns 1 when 1 job' do
|
21
|
-
batch = Sidekiq::Batch.new
|
22
|
-
|
23
36
|
batch.jobs do
|
24
37
|
TestWorker.perform_async('5')
|
25
38
|
end
|
26
39
|
|
27
|
-
|
40
|
+
expect(subject.total).to eq(1)
|
41
|
+
end
|
42
|
+
end
|
28
43
|
|
29
|
-
|
44
|
+
describe '#failures' do
|
45
|
+
it 'returns 0' do
|
46
|
+
expect(subject.failures).to eq(0)
|
30
47
|
end
|
31
48
|
end
|
32
49
|
|
33
50
|
describe '#bid' do
|
34
51
|
it 'returns a bid' do
|
35
|
-
|
36
|
-
|
52
|
+
expect(subject.bid).to_not be_nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#join' do
|
57
|
+
class MyCallback
|
58
|
+
def on_event(status, options); end
|
59
|
+
end
|
60
|
+
|
61
|
+
before(:each) do
|
62
|
+
batch.on(:event, MyCallback, my_arg: 42)
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'executes callbacks' do
|
66
|
+
expect_any_instance_of(MyCallback).to receive(:on_event).with(subject, { my_arg: 42 })
|
67
|
+
subject.join
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#initialize' do
|
72
|
+
it 'uses default argument values when none are provided' do
|
73
|
+
expect { Sidekiq::Batch::Status.new }.to_not raise_error
|
37
74
|
end
|
38
75
|
end
|
39
76
|
end
|
40
|
-
end
|
77
|
+
end
|
@@ -2,9 +2,10 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
RSpec.describe 'Retries Exhausted block' do
|
4
4
|
class FooClass < TestWorkerAlternative
|
5
|
-
sidekiq_retries_exhausted do |msg|
|
5
|
+
sidekiq_retries_exhausted do |msg, exception|
|
6
6
|
bar('hello')
|
7
7
|
foo(msg)
|
8
|
+
baz(exception)
|
8
9
|
end
|
9
10
|
|
10
11
|
def self.bar(input)
|
@@ -12,17 +13,28 @@ RSpec.describe 'Retries Exhausted block' do
|
|
12
13
|
|
13
14
|
def self.foo(msg)
|
14
15
|
end
|
16
|
+
|
17
|
+
def self.baz(exception)
|
18
|
+
end
|
15
19
|
end
|
16
20
|
|
17
21
|
it 'executes whatever is within the block' do
|
18
22
|
FooClass.within_sidekiq_retries_exhausted_block { expect(FooClass).to receive(:bar).with('hello') }
|
19
23
|
end
|
20
24
|
|
21
|
-
it 'passes
|
25
|
+
it 'passes message and exception to the block' do
|
22
26
|
args = { 'args' => ['a', 'b']}
|
23
|
-
|
24
|
-
|
27
|
+
exception = StandardError.new('something went wrong')
|
28
|
+
FooClass.within_sidekiq_retries_exhausted_block(args, exception) do
|
29
|
+
expect(FooClass).to receive(:foo).with(FooClass.default_retries_exhausted_message.merge(args))
|
30
|
+
expect(FooClass).to receive(:baz).with(exception)
|
25
31
|
end
|
26
32
|
end
|
27
33
|
|
34
|
+
it 'sets a default value for the message and exception' do
|
35
|
+
FooClass.within_sidekiq_retries_exhausted_block do
|
36
|
+
expect(FooClass).to receive(:foo).with(FooClass.default_retries_exhausted_message)
|
37
|
+
expect(FooClass).to receive(:baz).with(FooClass.default_retries_exhausted_exception)
|
38
|
+
end
|
39
|
+
end
|
28
40
|
end
|
@@ -2,6 +2,9 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
RSpec.describe RSpec::Sidekiq::Matchers::BeUnique do
|
4
4
|
shared_context 'a unique worker' do
|
5
|
+
before do
|
6
|
+
stub_const(module_constant, true)
|
7
|
+
end
|
5
8
|
before(:each) { subject.matches? @worker }
|
6
9
|
|
7
10
|
describe 'expected usage' do
|
@@ -14,7 +17,6 @@ RSpec.describe RSpec::Sidekiq::Matchers::BeUnique do
|
|
14
17
|
expect(subject.failure_message).to eq "expected #{@worker} to be unique in the queue"
|
15
18
|
end
|
16
19
|
end
|
17
|
-
|
18
20
|
end
|
19
21
|
|
20
22
|
describe '#matches?' do
|
@@ -36,27 +38,78 @@ RSpec.describe RSpec::Sidekiq::Matchers::BeUnique do
|
|
36
38
|
end
|
37
39
|
end
|
38
40
|
end
|
41
|
+
|
42
|
+
describe '#description' do
|
43
|
+
it 'returns description' do
|
44
|
+
expect(subject.description).to eq 'be unique in the queue'
|
45
|
+
end
|
46
|
+
end
|
39
47
|
end
|
40
48
|
|
41
|
-
context 'a scheduled worker' do
|
42
|
-
|
49
|
+
context 'a sidekiq-enterprise scheduled worker' do
|
50
|
+
let(:interval) { 3.hours }
|
51
|
+
let(:module_constant) { "Sidekiq::Enterprise" }
|
52
|
+
before { @worker = create_worker unique_for: interval }
|
43
53
|
include_context 'a unique worker'
|
44
54
|
end
|
45
55
|
|
46
|
-
context 'a
|
47
|
-
|
56
|
+
context 'a sidekiq-unique-jobs scheduled worker' do
|
57
|
+
let(:module_constant) { "SidekiqUniqueJobs" }
|
58
|
+
before { @worker = create_worker unique: :all }
|
59
|
+
include_context 'a unique worker'
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'a sidekiq-unique-jobs regular worker' do
|
63
|
+
let(:module_constant) { "SidekiqUniqueJobs" }
|
64
|
+
before { @worker = create_worker unique: true }
|
48
65
|
include_context 'a unique worker'
|
49
66
|
end
|
50
67
|
|
51
68
|
describe '#be_unique' do
|
69
|
+
before do
|
70
|
+
stub_const("SidekiqUniqueJobs", true)
|
71
|
+
end
|
72
|
+
|
52
73
|
it 'returns instance' do
|
53
|
-
expect(be_unique).to
|
74
|
+
expect(be_unique).to be_kind_of RSpec::Sidekiq::Matchers::BeUnique::Base
|
54
75
|
end
|
55
76
|
end
|
56
77
|
|
57
78
|
describe '#failure_message_when_negated' do
|
79
|
+
before do
|
80
|
+
stub_const("SidekiqUniqueJobs", true)
|
81
|
+
end
|
82
|
+
|
58
83
|
it 'returns message' do
|
59
84
|
expect(subject.failure_message_when_negated).to eq "expected #{@worker} to not be unique in the queue"
|
60
85
|
end
|
61
86
|
end
|
87
|
+
|
88
|
+
describe '#unique_key' do
|
89
|
+
context "with Sidekiq Enterprise" do
|
90
|
+
before do
|
91
|
+
stub_const("Sidekiq::Enterprise", true)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "returns the correct key" do
|
95
|
+
expect(subject.unique_key).to eq('unique_for')
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "with sidekiq-unique-jobs" do
|
100
|
+
before do
|
101
|
+
stub_const("SidekiqUniqueJobs", true)
|
102
|
+
end
|
103
|
+
|
104
|
+
it "returns the correct key" do
|
105
|
+
expect(subject.unique_key).to eq('unique')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
context "without a uniquing solution" do
|
110
|
+
it "raises an exception" do
|
111
|
+
expect{subject.unique_key}.to raise_error
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
62
115
|
end
|
@@ -1,10 +1,12 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
RSpec.describe RSpec::Sidekiq::Matchers::HaveEnqueuedJob do
|
4
|
+
let(:tomorrow) { DateTime.now + 1 }
|
5
|
+
let(:interval) { 3.minutes }
|
4
6
|
let(:argument_subject) { RSpec::Sidekiq::Matchers::HaveEnqueuedJob.new worker_args }
|
5
7
|
let(:matcher_subject) { RSpec::Sidekiq::Matchers::HaveEnqueuedJob.new [be_a(String), be_a(Fixnum), true, be_a(Hash)] }
|
6
8
|
let(:worker) { create_worker }
|
7
|
-
let(:worker_args) { ['string', 1, true, {key: 'value', nested: [{hash: true}]}] }
|
9
|
+
let(:worker_args) { ['string', 1, true, { key: 'value', bar: :foo, nested: [{hash: true}] }] }
|
8
10
|
let(:active_job) { create_active_job :mailers }
|
9
11
|
let(:resource) { TestResource.new }
|
10
12
|
|
@@ -14,41 +16,70 @@ RSpec.describe RSpec::Sidekiq::Matchers::HaveEnqueuedJob do
|
|
14
16
|
active_job.perform_later(resource)
|
15
17
|
TestActionMailer.testmail.deliver_later
|
16
18
|
TestActionMailer.testmail(resource).deliver_later
|
17
|
-
argument_subject.matches? worker
|
18
19
|
end
|
19
20
|
|
20
21
|
describe 'expected usage' do
|
21
|
-
|
22
|
-
|
23
|
-
|
22
|
+
context 'Sidekiq' do
|
23
|
+
it 'matches' do
|
24
|
+
expect(worker).to have_enqueued_job *worker_args
|
25
|
+
end
|
24
26
|
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
it 'matches on the global Worker queue' do
|
28
|
+
expect(Sidekiq::Worker).to have_enqueued_job *worker_args
|
29
|
+
end
|
28
30
|
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
context 'perform_in' do
|
32
|
+
let(:worker_args_in) { worker_args + ['in'] }
|
33
|
+
|
34
|
+
before(:each) do
|
35
|
+
worker.perform_in 3.minutes, *worker_args_in
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'matches on an scheduled job with #perform_in' do
|
39
|
+
expect(worker).to have_enqueued_job(*worker_args_in).in(interval)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'perform_at' do
|
44
|
+
let(:worker_args_at) { worker_args + ['at'] }
|
32
45
|
|
33
|
-
|
34
|
-
|
46
|
+
before(:each) do
|
47
|
+
worker.perform_at tomorrow, *worker_args_at
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'matches on an scheduled job with #perform_at' do
|
51
|
+
expect(worker).to have_enqueued_job(*worker_args_at).at(tomorrow)
|
52
|
+
end
|
53
|
+
end
|
35
54
|
end
|
36
55
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
56
|
+
context 'ActiveJob' do
|
57
|
+
it 'matches on an enqueued ActiveJob' do
|
58
|
+
expect(Sidekiq::Worker).to have_enqueued_job 'someResource'
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'matches on an enqueued ActiveJob by global_id' do
|
62
|
+
expect(Sidekiq::Worker).to have_enqueued_job('_aj_globalid' => resource.to_global_id.uri.to_s)
|
63
|
+
end
|
43
64
|
end
|
44
65
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
66
|
+
context 'ActionMailer' do
|
67
|
+
it 'matches on ActionMailer Job' do
|
68
|
+
expect(Sidekiq::Worker).to have_enqueued_job(
|
69
|
+
'TestActionMailer',
|
70
|
+
'testmail',
|
71
|
+
'deliver_now'
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'matches on ActionMailer with a resource Job' do
|
76
|
+
expect(Sidekiq::Worker).to have_enqueued_job(
|
77
|
+
'TestActionMailer',
|
78
|
+
'testmail',
|
79
|
+
'deliver_now',
|
80
|
+
{ '_aj_globalid' => resource.to_global_id.uri.to_s }
|
81
|
+
)
|
82
|
+
end
|
52
83
|
end
|
53
84
|
end
|
54
85
|
|
@@ -60,13 +91,30 @@ RSpec.describe RSpec::Sidekiq::Matchers::HaveEnqueuedJob do
|
|
60
91
|
|
61
92
|
describe '#description' do
|
62
93
|
it 'returns description' do
|
63
|
-
|
94
|
+
argument_subject.matches? worker
|
95
|
+
expect(argument_subject.description).to eq %{have an enqueued #{worker} job with arguments [\"string\", 1, true, {\"key\"=>\"value\", \"bar\"=>\"foo\", \"nested\"=>[{\"hash\"=>true}]}]}
|
64
96
|
end
|
65
97
|
end
|
66
98
|
|
67
99
|
describe '#failure_message' do
|
68
100
|
it 'returns message' do
|
69
|
-
|
101
|
+
argument_subject.matches? worker
|
102
|
+
expect(argument_subject.failure_message).to eq <<-eos.gsub(/^ {6}/, '').strip
|
103
|
+
expected to have an enqueued #{worker} job
|
104
|
+
arguments: [\"string\", 1, true, {\"key\"=>\"value\", \"bar\"=>\"foo\", \"nested\"=>[{\"hash\"=>true}]}]
|
105
|
+
found
|
106
|
+
arguments: [[\"string\", 1, true, {\"key\"=>\"value\", \"bar\"=>\"foo\", \"nested\"=>[{\"hash\"=>true}]}]]
|
107
|
+
eos
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '#failure_message_when_negated' do
|
112
|
+
it 'returns message' do
|
113
|
+
argument_subject.matches? worker
|
114
|
+
expect(argument_subject.failure_message_when_negated).to eq <<-eos.gsub(/^ {6}/, '').strip
|
115
|
+
expected not to have an enqueued #{worker} job
|
116
|
+
arguments: [\"string\", 1, true, {\"key\"=>\"value\", \"bar\"=>\"foo\", \"nested\"=>[{\"hash\"=>true}]}]
|
117
|
+
eos
|
70
118
|
end
|
71
119
|
end
|
72
120
|
|
@@ -74,15 +122,55 @@ RSpec.describe RSpec::Sidekiq::Matchers::HaveEnqueuedJob do
|
|
74
122
|
context 'when condition matches' do
|
75
123
|
context 'when expected are arguments' do
|
76
124
|
it 'returns true' do
|
125
|
+
worker.perform_async *worker_args
|
77
126
|
expect(argument_subject.matches? worker).to be true
|
78
127
|
end
|
79
128
|
end
|
80
129
|
|
81
130
|
context 'when expected are matchers' do
|
82
131
|
it 'returns true' do
|
132
|
+
worker.perform_async *worker_args
|
83
133
|
expect(matcher_subject.matches? worker).to be true
|
84
134
|
end
|
85
135
|
end
|
136
|
+
|
137
|
+
context 'when job is scheduled' do
|
138
|
+
context 'with #perform_at' do
|
139
|
+
before(:each) do
|
140
|
+
worker.perform_at(tomorrow, *worker_args)
|
141
|
+
end
|
142
|
+
|
143
|
+
context 'and timestamp matches' do
|
144
|
+
it 'returns true' do
|
145
|
+
expect(matcher_subject.at(tomorrow).matches? worker).to be true
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
context 'and timestamp does not match' do
|
150
|
+
it 'returns false' do
|
151
|
+
expect(matcher_subject.at(tomorrow + 1).matches? worker).to be false
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context 'with #perform_in' do
|
157
|
+
before(:each) do
|
158
|
+
worker.perform_in(interval, *worker_args)
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'and interval matches' do
|
162
|
+
it 'returns true' do
|
163
|
+
expect(matcher_subject.in(interval).matches? worker).to be true
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context 'and interval does not match' do
|
168
|
+
it 'returns false' do
|
169
|
+
expect(matcher_subject.in(interval + 1.minute).matches? worker).to be false
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
86
174
|
end
|
87
175
|
|
88
176
|
context 'when condition does not match' do
|
@@ -99,12 +187,28 @@ RSpec.describe RSpec::Sidekiq::Matchers::HaveEnqueuedJob do
|
|
99
187
|
expect(matcher_subject.matches? worker).to be false
|
100
188
|
end
|
101
189
|
end
|
102
|
-
end
|
103
|
-
end
|
104
190
|
|
105
|
-
|
106
|
-
|
107
|
-
|
191
|
+
context 'when job is scheduled' do
|
192
|
+
context 'with #perform_at' do
|
193
|
+
before(:each) do
|
194
|
+
allow(matcher_subject).to receive(:options).and_return(at: tomorrow + 1)
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'returns false' do
|
198
|
+
expect(matcher_subject.at(tomorrow).matches? worker).to be false
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
context 'with #perform_in' do
|
203
|
+
before(:each) do
|
204
|
+
allow(matcher_subject).to receive(:options).and_return(in: interval + 1)
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'returns false' do
|
208
|
+
expect(matcher_subject.in(interval).matches? worker).to be false
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
108
212
|
end
|
109
213
|
end
|
110
214
|
end
|
metadata
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-sidekiq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Phil Ostler
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-04-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name: rspec
|
14
|
+
name: rspec-core
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
@@ -44,6 +44,20 @@ dependencies:
|
|
44
44
|
- - ">="
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: 2.4.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '3.0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '3.0'
|
47
61
|
- !ruby/object:Gem::Dependency
|
48
62
|
name: coveralls
|
49
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -193,7 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
193
207
|
version: '0'
|
194
208
|
requirements: []
|
195
209
|
rubyforge_project:
|
196
|
-
rubygems_version: 2.
|
210
|
+
rubygems_version: 2.5.2
|
197
211
|
signing_key:
|
198
212
|
specification_version: 4
|
199
213
|
summary: RSpec for Sidekiq
|