resque_unit 0.4.8 → 1.0.0.beta.2

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