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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4e76f040dc9a72982978b86c4085e90a4efeab6f
4
- data.tar.gz: 4f3531dc67714ce9f1aae2858b2e12c4baf80f2e
3
+ metadata.gz: 71242ca35cdc2cccbfbae1008db364d84f58a1f1
4
+ data.tar.gz: 6114262aa4025c8d10b982d3a7261b36667318bb
5
5
  SHA512:
6
- metadata.gz: 02c75664a4f650debe93f2a6a61d51ce5c8341c16388824f500d0d5afe75b7ab044a6606a2c3fab25649ea424f9da683da05e8ab71dd69893f54a9dc7cea5345
7
- data.tar.gz: 7528d4c9f3cda76979b3118dee4069fdb86792e566e91bfd475703d2f107e5555ed1a850a0ff0e4b79b874f37b74261f2250bc28e148324555d22b31bdf4dbfd
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
 
@@ -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 default_retries_exhausted_args.merge(user_msg)
6
+ sidekiq_retries_exhausted_block.call(default_retries_exhausted_message.merge(user_msg), exception)
7
7
  end
8
8
 
9
- def default_retries_exhausted_args
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 description
10
- 'be unique in the queue'
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
- def failure_message
14
- "expected #{@klass} to be unique in the queue"
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
- def matches?(job)
18
- @klass = job.is_a?(Class) ? job : job.class
19
- @actual = @klass.get_sidekiq_options['unique']
20
- [true, :all].include?(@actual)
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
- def failure_message_when_negated
24
- "expected #{@klass} to not be unique in the queue"
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, :actual
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 with arguments #{expected_arguments}\n\n" \
21
- "found: #{actual}"
22
- end
23
-
24
- def matches?(klass)
25
- @klass = klass
26
- @actual = unwrapped_job_arguments(klass.jobs)
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 not have an enqueued #{klass} job with arguments #{expected_arguments}"
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).flatten
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
@@ -1,5 +1,5 @@
1
1
  module RSpec
2
2
  module Sidekiq
3
- VERSION = '2.2.0'
3
+ VERSION = '3.0.0'
4
4
  end
5
5
  end
@@ -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
- null_status = Sidekiq::Batch.new.status
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
- null_status = batch.status
40
+ expect(subject.total).to eq(1)
41
+ end
42
+ end
28
43
 
29
- expect(null_status.total).to eq(1)
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
- null_status = Sidekiq::Batch.new
36
- expect(null_status.bid).to_not be_nil
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 arguments to the block' do
25
+ it 'passes message and exception to the block' do
22
26
  args = { 'args' => ['a', 'b']}
23
- FooClass.within_sidekiq_retries_exhausted_block(args) do
24
- expect(FooClass).to receive(:foo).with(FooClass.default_retries_exhausted_args.merge(args))
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
- before { @worker = create_worker unique: :all }
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 regular worker' do
47
- before { @worker = create_worker unique: true }
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 be_a RSpec::Sidekiq::Matchers::BeUnique
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
- it 'matches' do
22
- expect(worker).to have_enqueued_job *worker_args
23
- end
22
+ context 'Sidekiq' do
23
+ it 'matches' do
24
+ expect(worker).to have_enqueued_job *worker_args
25
+ end
24
26
 
25
- it 'matches on the global Worker queue' do
26
- expect(Sidekiq::Worker).to have_enqueued_job *worker_args
27
- end
27
+ it 'matches on the global Worker queue' do
28
+ expect(Sidekiq::Worker).to have_enqueued_job *worker_args
29
+ end
28
30
 
29
- it 'matches on an enqueued ActiveJob' do
30
- expect(Sidekiq::Worker).to have_enqueued_job 'someResource'
31
- end
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
- it 'matches on an enqueued ActiveJob by global_id' do
34
- expect(Sidekiq::Worker).to have_enqueued_job("_aj_globalid" => resource.to_global_id.uri.to_s)
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
- it 'matches on ActionMailer Job' do
38
- expect(Sidekiq::Worker).to have_enqueued_job(
39
- "TestActionMailer",
40
- "testmail",
41
- "deliver_now"
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
- it 'matches on ActionMailer with a resource Job' do
46
- expect(Sidekiq::Worker).to have_enqueued_job(
47
- "TestActionMailer",
48
- "testmail",
49
- "deliver_now",
50
- { "_aj_globalid" => resource.to_global_id.uri.to_s }
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
- expect(argument_subject.description).to eq "have an enqueued #{worker} job with arguments [\"string\", 1, true, {\"key\"=>\"value\", \"nested\"=>[{\"hash\"=>true}]}]"
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
- expect(argument_subject.failure_message).to eq "expected to have an enqueued #{worker} job with arguments [\"string\", 1, true, {\"key\"=>\"value\", \"nested\"=>[{\"hash\"=>true}]}]\n\nfound: [[\"string\", 1, true, {\"key\"=>\"value\", \"nested\"=>[{\"hash\"=>true}]}]]"
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
- describe '#failure_message_when_negated' do
106
- it 'returns message' do
107
- expect(argument_subject.failure_message_when_negated).to eq "expected to not have an enqueued #{worker} job with arguments [\"string\", 1, true, {\"key\"=>\"value\", \"nested\"=>[{\"hash\"=>true}]}]"
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
@@ -1,5 +1,5 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe RSpec::Sidekiq::VERSION do
4
- it { is_expected.to eq('2.2.0') }
4
+ it { is_expected.to eq('3.0.0') }
5
5
  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: 2.2.0
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: 2015-12-22 00:00:00.000000000 Z
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.4.8
210
+ rubygems_version: 2.5.2
197
211
  signing_key:
198
212
  specification_version: 4
199
213
  summary: RSpec for Sidekiq