rspec-sidekiq 2.2.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|