resque_unit 0.4.8 → 1.0.0.beta.2

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: 1aad0f765a2b78da6d5f17cdbf2f5646066d8b8d
4
- data.tar.gz: c694a2f46b3ec5892f7a83ebfae9d734dd0371ec
3
+ metadata.gz: c7f97661c4942301890a017728285e1ab9d65b3f
4
+ data.tar.gz: 260b78240c5893fd2a63f555699d46643f4d0d1f
5
5
  SHA512:
6
- metadata.gz: 812552beeb3b8c3de00be72b6c13b8dfc4fd2808df1114f308c3eb5aaba2635108d58d9583c5a8c879248b91b716c0bf21c38fad6b2d1453a0405c272daa3f3b
7
- data.tar.gz: 97110758541b5c3335906743fdd0dbfd2f1514106ec90ea98dbb9149bef0f86b0932974cc2ed2455d9ea119fffae551aaf9764302ab64101195f4ae3977dec8a
6
+ metadata.gz: bb7c292dff03229418161eab51a16f8e9f3415df0d5ed24b58dbf8bca94453c0962bf792de19c0669b080c3ed12642f2a1b07ea381003aefb8024847b74950ea
7
+ data.tar.gz: e6b67c8fbd8b9409981b409836d9613a20a8b7fc1732b98beaee8b353ccbf18c3977b8af464bd368165c9021b0e47dceec1bbd4ac8d2f3db514aaa696973b776
data/README.md CHANGED
@@ -3,7 +3,7 @@ ResqueUnit
3
3
 
4
4
  ResqueUnit provides some extra assertions and a mock Resque for
5
5
  testing Rails code that depends on Resque. You can install it as
6
- either a gem or a plugin:
6
+ either a gem:
7
7
 
8
8
  gem install resque_unit
9
9
 
@@ -11,12 +11,6 @@ and in your test.rb:
11
11
 
12
12
  config.gem 'resque_unit'
13
13
 
14
- If you'd rather install it as a plugin, you should be able to run
15
-
16
- script/plugin install git://github.com/justinweiss/resque_unit.git
17
-
18
- inside your Rails projects.
19
-
20
14
  Examples
21
15
  ========
22
16
 
@@ -103,10 +97,6 @@ Caveats
103
97
 
104
98
  * You should make sure that you call `Resque.reset!` in your test's
105
99
  setup method to clear all of the test queues.
106
- * Hooks support is optional. Just because you probably don't want to call
107
- them during unit tests if they play with a DB. Call `Resque.enable_hooks!`
108
- in your tests's setup method to enable hooks. To disable hooks, call
109
- `Resque.disable_hooks!`.
110
100
 
111
101
  Resque-Scheduler Support
112
102
  ========================
@@ -1,7 +1,6 @@
1
1
  # These are a group of assertions you can use in your unit tests to
2
2
  # verify that your code is using Resque correctly.
3
3
  module ResqueUnit::Assertions
4
-
5
4
  # Asserts that +klass+ has been queued into its appropriate queue at
6
5
  # least once. If +args+ is nil, it only asserts that the klass has
7
6
  # been queued. Otherwise, it asserts that the klass has been queued
@@ -9,14 +8,14 @@ module ResqueUnit::Assertions
9
8
  # want to assert that klass has been queued without arguments. Pass a block
10
9
  # if you want to assert something was queued within its execution.
11
10
  def assert_queued(klass, args = nil, message = nil, &block)
12
- queue_name = Resque.queue_for(klass)
11
+ queue_name = Resque.queue_from_class(klass)
13
12
  assert_job_created(queue_name, klass, args, message, &block)
14
13
  end
15
14
  alias assert_queues assert_queued
16
15
 
17
16
  # The opposite of +assert_queued+.
18
17
  def assert_not_queued(klass = nil, args = nil, message = nil, &block)
19
- queue_name = Resque.queue_for(klass)
18
+ queue_name = Resque.queue_from_class(klass)
20
19
 
21
20
  queue = if block_given?
22
21
  snapshot = Resque.size(queue_name)
@@ -32,9 +31,9 @@ module ResqueUnit::Assertions
32
31
 
33
32
  # Asserts no jobs were queued within the block passed.
34
33
  def assert_nothing_queued(message = nil, &block)
35
- snapshot = Resque.size
34
+ snapshot = total_job_count
36
35
  yield
37
- present = Resque.size
36
+ present = total_job_count
38
37
  assert_equal snapshot, present, message || "No jobs should have been queued"
39
38
  end
40
39
 
@@ -54,6 +53,11 @@ module ResqueUnit::Assertions
54
53
 
55
54
  private
56
55
 
56
+ # The total count of all the jobs in Resque.
57
+ def total_job_count
58
+ Resque.queues.inject(0) { |acc, queue| acc + Resque.size(queue) }
59
+ end
60
+
57
61
  # In Test::Unit, +assert_block+ displays only the message on a test
58
62
  # failure and +assert+ always appends a message to the end of the
59
63
  # passed-in assertion message. In MiniTest, it's the other way
@@ -0,0 +1,66 @@
1
+ module Resque
2
+ module TestExtensions
3
+ # A redis connection that always uses fakeredis.
4
+ def fake_redis
5
+ @fake_redis ||= Redis.new(driver: :memory)
6
+ end
7
+
8
+ # Always return the fake redis.
9
+ def redis
10
+ fake_redis
11
+ end
12
+
13
+ # Resets all the queues to the empty state. This should be called in
14
+ # your test's +setup+ method until I can figure out a way for it to
15
+ # automatically be called.
16
+ #
17
+ # If <tt>queue_name</tt> is given, then resets only that queue.
18
+ def reset!(queue = nil)
19
+ if queue
20
+ remove_queue(queue)
21
+ else
22
+ redis.flushall
23
+ end
24
+ end
25
+
26
+ # Return an array of all jobs' payloads for queue
27
+ # Elements are decoded
28
+ def all(queue_name)
29
+ jobs = peek(queue_name, 0, size(queue_name))
30
+ jobs.kind_of?(Array) ? jobs : [jobs]
31
+ end
32
+ alias queue all
33
+
34
+ # Executes all jobs in all queues in an undefined order.
35
+ def run!
36
+ payloads = []
37
+ queues.each do |queue|
38
+ size(queue).times { payloads << pop(queue) }
39
+ end
40
+ exec_payloads payloads.shuffle
41
+ end
42
+
43
+ def run_for!(queue, limit = Float::INFINITY)
44
+ job_count = [limit, size(queue)].min
45
+ payloads = []
46
+
47
+ job_count.times { payloads << pop(queue) }
48
+ exec_payloads payloads.shuffle
49
+ end
50
+
51
+ def exec_payloads(raw_payloads)
52
+ raw_payloads.each do |raw_payload|
53
+ Resque::Job.new(:inline, raw_payload).perform
54
+ end
55
+ end
56
+
57
+ private :exec_payloads
58
+
59
+ # 1. Execute all jobs in all queues in an undefined order,
60
+ # 2. Check if new jobs were announced, and execute them.
61
+ # 3. Repeat 3
62
+ def full_run!
63
+ run! until queues.all? { |queue| size(queue) == 0 }
64
+ end
65
+ end
66
+ end
@@ -1,224 +1,15 @@
1
- # The fake Resque class. This needs to be loaded after the real Resque
2
- # for the assertions in +ResqueUnit::Assertions+ to work.
3
- module Resque
4
- include ResqueUnit::Helpers
5
- extend self
6
-
7
- # Resets all the queues to the empty state. This should be called in
8
- # your test's +setup+ method until I can figure out a way for it to
9
- # automatically be called.
10
- #
11
- # If <tt>queue_name</tt> is given, then resets only that queue.
12
- def reset!(queue_name = nil)
13
- if @queue && queue_name
14
- @queue[queue_name] = []
15
- else
16
- @queue = Hash.new { |h, k| h[k] = [] }
17
- end
18
- end
19
-
20
- # Returns a hash of all the queue names and jobs that have been queued. The
21
- # format is <tt>{queue_name => [job, ..]}</tt>.
22
- def self.queues
23
- @queue || reset!
24
- end
25
-
26
- # Returns an array of all the jobs that have been queued. Each
27
- # element is of the form +{"class" => klass, "args" => args}+ where
28
- # +klass+ is the job's class and +args+ is an array of the arguments
29
- # passed to the job.
30
- def queue(queue_name)
31
- queues[queue_name]
32
- end
33
-
34
- # Return an array of all jobs' payloads for queue
35
- # Elements are decoded
36
- def all(queue_name)
37
- result = list_range(queue_name, 0, size(queue_name))
38
- result.is_a?(Array) ? result : [ result ]
39
- end
40
-
41
- # Returns an array of jobs' payloads for queue.
42
- #
43
- # start and count should be integer and can be used for pagination.
44
- # start is the item to begin, count is how many items to return.
45
- #
46
- # To get the 3rd page of a 30 item, paginatied list one would use:
47
- # Resque.peek('my_list', 59, 30)
48
- def peek(queue_name, start = 0, count = 1)
49
- list_range(queue_name, start, count)
50
- end
51
-
52
- # Gets a range of jobs' payloads from queue.
53
- # Returns single element if count equal 1
54
- # Elements are decoded
55
- def list_range(key, start = 0, count = 1)
56
- data = if count == 1
57
- decode(queues[key][start])
58
- else
59
- (queues[key][start...start + count] || []).map { |entry| decode(entry) }
60
- end
61
- end
62
-
63
- # Yes, all Resque hooks!
64
- def enable_hooks!
65
- @hooks_enabled = true
66
- end
67
-
68
- def disable_hooks!
69
- @hooks_enabled = nil
70
- end
71
-
72
- # Executes all jobs in all queues in an undefined order.
73
- def run!
74
- payloads = []
75
- @queue.each do |queue_name, queue|
76
- payloads.concat queue.slice!(0, queue.size)
77
- end
78
- exec_payloads payloads.shuffle
79
- end
80
-
81
- def run_for!(queue_name, limit=false)
82
- queue = @queue[queue_name]
83
- exec_payloads queue.slice!(0, ( limit ? limit : queue.size) ).shuffle
84
- end
85
-
86
- def exec_payloads(raw_payloads)
87
- raw_payloads.each do |raw_payload|
88
- job_payload = decode(raw_payload)
89
- @hooks_enabled ? perform_with_hooks(job_payload) : perform_without_hooks(job_payload)
90
- end
91
- end
92
- private :exec_payloads
93
-
94
- # 1. Execute all jobs in all queues in an undefined order,
95
- # 2. Check if new jobs were announced, and execute them.
96
- # 3. Repeat 3
97
- def full_run!
98
- run! until empty_queues?
99
- end
100
-
101
- # Returns the size of the given queue
102
- def size(queue_name = nil)
103
- if queue_name
104
- queues[queue_name].length
105
- else
106
- queues.values.flatten.length
107
- end
108
- end
109
-
110
- # :nodoc:
111
- def enqueue(klass, *args)
112
- enqueue_to( queue_for(klass), klass, *args)
113
- end
114
-
115
- # :nodoc:
116
- def enqueue_to( queue_name, klass, *args )
117
- # Behaves like Resque, raise if no queue was specifed
118
- raise NoQueueError.new("Jobs must be placed onto a queue.") unless queue_name
119
- enqueue_unit(queue_name, {"class" => klass.to_s, "args" => args })
120
- end
121
-
122
- # :nodoc:
123
- def queue_for(klass)
124
- klass.instance_variable_get(:@queue) || (klass.respond_to?(:queue) && klass.queue)
125
- end
126
- alias :queue_from_class :queue_for
127
-
128
- # :nodoc:
129
- def empty_queues?
130
- queues.all? do |k, v|
131
- v.empty?
132
- end
133
- end
134
-
135
- def enqueue_unit(queue_name, hash)
136
- klass = constantize(hash["class"])
137
- if @hooks_enabled
138
- before_hooks = Plugin.before_enqueue_hooks(klass).map do |hook|
139
- klass.send(hook, *hash["args"])
140
- end
141
- return nil if before_hooks.any? { |result| result == false }
142
- end
143
- queue(queue_name) << encode(hash)
144
- if @hooks_enabled
145
- Plugin.after_enqueue_hooks(klass).each do |hook|
146
- klass.send(hook, *hash["args"])
147
- end
148
- end
149
- queue(queue_name).size
150
- end
151
-
152
- # Call perform on the job class
153
- def perform_without_hooks(job_payload)
154
- constantize(job_payload["class"]).perform(*job_payload["args"])
155
- end
156
-
157
- # Call perform on the job class, and adds support for Resque hooks.
158
- def perform_with_hooks(job_payload)
159
- job_class = constantize(job_payload["class"])
160
- before_hooks = Resque::Plugin.before_hooks(job_class)
161
- around_hooks = Resque::Plugin.around_hooks(job_class)
162
- after_hooks = Resque::Plugin.after_hooks(job_class)
163
- failure_hooks = Resque::Plugin.failure_hooks(job_class)
164
-
165
- begin
166
- # Execute before_perform hook. Abort the job gracefully if
167
- # Resque::DontPerform is raised.
168
- begin
169
- before_hooks.each do |hook|
170
- job_class.send(hook, *job_payload["args"])
171
- end
172
- rescue Resque::Job::DontPerform
173
- return false
174
- end
175
-
176
- # Execute the job. Do it in an around_perform hook if available.
177
- if around_hooks.empty?
178
- perform_without_hooks(job_payload)
179
- job_was_performed = true
180
- else
181
- # We want to nest all around_perform plugins, with the last one
182
- # finally calling perform
183
- stack = around_hooks.reverse.inject(nil) do |last_hook, hook|
184
- if last_hook
185
- lambda do
186
- job_class.send(hook, *job_payload["args"]) { last_hook.call }
187
- end
188
- else
189
- lambda do
190
- job_class.send(hook, *job_payload["args"]) do
191
- result = perform_without_hooks(job_payload)
192
- job_was_performed = true
193
- result
194
- end
195
- end
196
- end
197
- end
198
- stack.call
199
- end
200
-
201
- # Execute after_perform hook
202
- after_hooks.each do |hook|
203
- job_class.send(hook, *job_payload["args"])
204
- end
205
-
206
- # Return true if the job was performed
207
- return job_was_performed
208
-
209
- # If an exception occurs during the job execution, look for an
210
- # on_failure hook then re-raise.
211
- rescue Object => e
212
- failure_hooks.each { |hook| job_class.send(hook, e, *job_payload["args"]) }
213
- raise e
214
- end
215
- end
216
-
217
- class Job
218
- extend ResqueUnit::Helpers
219
- def self.create(queue, klass_name, *args)
220
- Resque.enqueue_unit(queue, {"class" => constantize(klass_name).to_s, "args" => args})
221
- end
222
- end
223
-
224
- end
1
+ require 'resque'
2
+ require 'resque_unit/resque/test_extensions'
3
+
4
+ # This is a little weird. Fakeredis registers itself as the default
5
+ # redis driver after you load it. This might not be what you want,
6
+ # though -- resque_unit needs fakeredis, but you may have a reason to
7
+ # use a different redis driver for the rest of your test code. So
8
+ # we'll store the old default here, and restore it afer we're done
9
+ # loading fakeredis. Then, we'll point resque at fakeredis
10
+ # specifically.
11
+ default_redis_driver = Redis::Connection.drivers.pop
12
+ require 'fakeredis'
13
+ Redis::Connection.drivers << default_redis_driver if default_redis_driver
14
+
15
+ Resque.extend Resque::TestExtensions
@@ -3,7 +3,7 @@
3
3
  require 'time'
4
4
 
5
5
  module ResqueUnit::SchedulerAssertions
6
-
6
+
7
7
  # Asserts that +klass+ has been queued into its appropriate queue at
8
8
  # least once, with a +timestamp+ less than or equal to
9
9
  # +expected_timestamp+. If the job wasn't queued with a timestamp,
@@ -13,7 +13,7 @@ module ResqueUnit::SchedulerAssertions
13
13
  # +args+ if you want to assert that klass has been queued without
14
14
  # arguments.
15
15
  def assert_queued_at(expected_timestamp, klass, args = nil, message = nil)
16
- queue = Resque.queue_for(klass)
16
+ queue = Resque.queue_from_class(klass)
17
17
  assert in_timestamped_queue?(queue, expected_timestamp, klass, args),
18
18
  (message || "#{klass} should have been queued in #{queue} before #{expected_timestamp}: #{Resque.queue(queue).inspect}.")
19
19
  end
@@ -23,10 +23,10 @@ module ResqueUnit::SchedulerAssertions
23
23
  def assert_queued_in(expected_time_difference, klass, args = nil, message = nil)
24
24
  assert_queued_at(Time.now + expected_time_difference, klass, args, message)
25
25
  end
26
-
26
+
27
27
  # opposite of +assert_queued_at+
28
28
  def assert_not_queued_at(expected_timestamp, klass, args = nil, message = nil)
29
- queue = Resque.queue_for(klass)
29
+ queue = Resque.queue_from_class(klass)
30
30
  assert !in_timestamped_queue?(queue, expected_timestamp, klass, args),
31
31
  (message || "#{klass} should not have been queued in #{queue} before #{expected_timestamp}.")
32
32
  end
@@ -38,10 +38,24 @@ module ResqueUnit::SchedulerAssertions
38
38
 
39
39
  private
40
40
 
41
- def in_timestamped_queue?(queue_name, expected_timestamp, klass, args = nil)
41
+ def in_queue?(queue, klass, args = nil)
42
+ super(queue, klass, args) || !matching_jobs(all_jobs_scheduled_before_or_at(:forever), klass, args).empty?
43
+ end
44
+
45
+ def in_timestamped_queue?(queue_name, max_timestamp, klass, args = nil)
42
46
  # check if we have any matching jobs with a timestamp less than
43
47
  # expected_timestamp
44
- !matching_jobs(Resque.all(queue_name), klass, args).select {|e| e["timestamp"] && Time.parse(e["timestamp"]) <= expected_timestamp}.empty?
48
+ !matching_jobs(all_jobs_scheduled_before_or_at(max_timestamp), klass, args).empty?
45
49
  end
46
-
50
+
51
+ def all_jobs_scheduled_before_or_at(max_timestamp = :forever)
52
+ timestamps = Resque.delayed_queue_peek(0, Resque.delayed_queue_schedule_size).map(&:to_i)
53
+
54
+ if max_timestamp != :forever
55
+ timestamps.select! { |timestamp| Time.at(timestamp) <= Time.at(max_timestamp) }
56
+ end
57
+
58
+ timestamps.flat_map { |timestamp| Resque.delayed_timestamp_peek(timestamp, 0, Resque.delayed_timestamp_size(timestamp)) }
59
+ end
60
+
47
61
  end
data/lib/resque_unit.rb CHANGED
@@ -6,14 +6,11 @@ begin
6
6
  rescue LoadError
7
7
  require 'json'
8
8
  end
9
-
10
- require 'resque_unit/helpers'
9
+ require 'resque'
11
10
  require 'resque_unit/resque'
12
- require 'resque_unit/errors'
13
11
  require 'resque_unit/assertions'
14
- require 'resque_unit/plugin'
15
12
 
16
- if defined?(Test::Unit)
13
+ if defined?(Test::Unit::TestCase)
17
14
  Test::Unit::TestCase.send(:include, ResqueUnit::Assertions)
18
15
  end
19
16
 
@@ -1,7 +1,8 @@
1
- require 'resque_unit/scheduler'
1
+ require 'resque_unit'
2
+ require 'resque-scheduler'
2
3
  require 'resque_unit/scheduler_assertions'
3
4
 
4
- if defined?(Test::Unit)
5
+ if defined?(Test::Unit::TestCase)
5
6
  Test::Unit::TestCase.send(:include, ResqueUnit::SchedulerAssertions)
6
7
  end
7
8
 
@@ -0,0 +1,11 @@
1
+ require 'test_helper'
2
+
3
+ describe Redis do
4
+ it "uses a real Redis connection by default" do
5
+ redis = Redis.current
6
+ refute_equal Redis::Connection::Memory, redis.client.driver
7
+
8
+ redis = Redis.new
9
+ refute_equal Redis::Connection::Memory, redis.client.driver
10
+ end
11
+ end
data/test/resque_test.rb CHANGED
@@ -1,60 +1,60 @@
1
1
  require 'test_helper'
2
+ describe Resque do
2
3
 
3
- class ResqueTest < Test::Unit::TestCase
4
-
5
- def setup
4
+ before do
6
5
  Resque.reset!
7
6
  end
8
7
 
9
- context "with one queued job" do
10
- setup do
8
+ describe "with one queued job" do
9
+ before do
11
10
  Resque.enqueue(MediumPriorityJob, "some args")
12
11
  @job_payload = {"args"=>["some args"], "class"=>"MediumPriorityJob"}
13
12
  end
14
13
 
15
- should "return job payload when peek method called with count equal 1" do
14
+ it "returns the job payload when peek method called with count equal 1" do
16
15
  assert_equal @job_payload, Resque.peek(MediumPriorityJob.queue, 0, 1)
17
16
  end
18
17
 
19
- should "return array of jobs' payloads when peek method called with count different than 1" do
18
+ it "returns an array of jobs' payloads when peek method called with count different than 1" do
20
19
  assert_equal [@job_payload], Resque.peek(MediumPriorityJob.queue, 0, 5)
21
20
  end
22
21
  end
23
22
 
24
- context "with few queued jobs" do
25
- setup do
23
+ describe "with few queued jobs" do
24
+ before do
26
25
  Resque.enqueue(MediumPriorityJob, "1")
27
26
  Resque.enqueue(MediumPriorityJob, "2")
28
27
  Resque.enqueue(MediumPriorityJob, "3")
29
28
  end
30
29
 
31
- should "return jobs' payloads 2 and 3 when peek method called with start equal 1 and count equal 2" do
30
+ it "returns jobs' payloads 2 and 3 when peek method called with start equal 1 and count equal 2" do
32
31
  assert_equal [["2"], ["3"]], Resque.peek(MediumPriorityJob.queue, 1, 2).map{|h| h["args"]}
33
32
  end
34
33
 
35
- should "return empty array when peek method called with start higher than queue size" do
34
+ it "returns an empty array when peek method called with start higher than queue size" do
36
35
  assert_equal [], Resque.peek(MediumPriorityJob.queue, 4, 2)
37
36
  end
38
37
 
39
- should "return empty array when peek method called with count equal 0" do
40
- assert_equal [], Resque.peek(MediumPriorityJob.queue, 0, 0)
38
+ it "returns all jobs' payloads when peek method called with count equal 0" do
39
+ # This is the way Resque.peek works, so it's now the way resque-unit works!
40
+ assert_equal Resque.all(MediumPriorityJob.queue), Resque.peek(MediumPriorityJob.queue, 0, 0)
41
41
  end
42
42
 
43
- should "return all jobs' payloads when all method called" do
43
+ it "returns all jobs' payloads when all method called" do
44
44
  assert Resque.all(MediumPriorityJob.queue).length == 3, "should return all 3 elements"
45
45
  end
46
46
  end
47
47
 
48
- context "without queued jobs" do
49
- should "return nil when peek method called with count equal 1" do
48
+ describe "without queued jobs" do
49
+ it "returns nil when peek method called with count equal 1" do
50
50
  assert_equal nil, Resque.peek(MediumPriorityJob.queue, 0, 1)
51
51
  end
52
52
 
53
- should "return empty array when peek method called with count not equal 1" do
53
+ it "returns an empty array when peek method called with count not equal 1" do
54
54
  assert_equal [], Resque.peek(MediumPriorityJob.queue, 0, 999)
55
55
  end
56
56
 
57
- should "return empty array when all method called" do
57
+ it "returns an empty array when `all` is called" do
58
58
  assert_equal [], Resque.all(MediumPriorityJob.queue)
59
59
  end
60
60
  end