resque-mock 0.1.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.
- data/Rakefile +10 -0
- data/lib/resque/mock.rb +84 -0
- data/spec/mock_spec.rb +111 -0
- metadata +85 -0
data/Rakefile
ADDED
data/lib/resque/mock.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'resque'
|
2
|
+
|
3
|
+
module Resque
|
4
|
+
def self.mock!
|
5
|
+
extend MockExt
|
6
|
+
end
|
7
|
+
|
8
|
+
module MockExt
|
9
|
+
def async
|
10
|
+
@async = true
|
11
|
+
create_worker_manager
|
12
|
+
yield
|
13
|
+
ensure
|
14
|
+
wait_for_worker_manager
|
15
|
+
@async = false
|
16
|
+
end
|
17
|
+
|
18
|
+
def enqueue(klass, *args)
|
19
|
+
puts "Mock enqueue: async=#{!!@async}, stack_depth=#{caller.size}, #{klass}, #{args.inspect}" if ENV['VERBOSE']
|
20
|
+
defer(klass, args)
|
21
|
+
end
|
22
|
+
|
23
|
+
def enqueue_in(delay, klass, *args)
|
24
|
+
puts "Mock enqueue in #{delay}: async=#{!!@async}, stack_depth=#{caller.size}, #{klass}, #{args.inspect}" if ENV['VERBOSE']
|
25
|
+
defer(klass, args, delay)
|
26
|
+
end
|
27
|
+
|
28
|
+
def defer(klass, args, delay = nil)
|
29
|
+
if @async
|
30
|
+
add_job('payload' => { 'class' => klass, 'args' => args }, 'delay' => delay)
|
31
|
+
else
|
32
|
+
sleep delay if delay
|
33
|
+
klass.perform(*roundtrip(args))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def create_worker_manager
|
38
|
+
@worker_manager = Thread.new do
|
39
|
+
Thread.current.abort_on_exception = true
|
40
|
+
worker_threads = []
|
41
|
+
|
42
|
+
while true
|
43
|
+
break if Thread.current[:exit] && worker_threads.empty? && Thread.current[:jobs].empty?
|
44
|
+
|
45
|
+
worker_threads.reject! {|t| !t.alive? }
|
46
|
+
|
47
|
+
while Thread.current[:jobs] && job_data = Thread.current[:jobs].shift
|
48
|
+
worker_threads << create_worker_thread_for(job_data)
|
49
|
+
end
|
50
|
+
|
51
|
+
sleep 0.5
|
52
|
+
end
|
53
|
+
end.tap {|t| t[:jobs] = [] }
|
54
|
+
end
|
55
|
+
|
56
|
+
def wait_for_worker_manager
|
57
|
+
@worker_manager[:exit] = true
|
58
|
+
@worker_manager.join
|
59
|
+
@worker_manager = nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_worker_thread_for(data)
|
63
|
+
Thread.new(data) do |data|
|
64
|
+
Thread.current.abort_on_exception = true
|
65
|
+
if delay = data['delay']
|
66
|
+
sleep delay
|
67
|
+
end
|
68
|
+
|
69
|
+
klass = data['payload']['class']
|
70
|
+
puts "Mock perform: #{klass}.perform(*#{data['payload']['args'].inspect})" if ENV['VERBOSE']
|
71
|
+
klass.perform(*roundtrip(data['payload']['args']))
|
72
|
+
puts "Mock exit: #{klass}.perform(*#{data['payload']['args'].inspect})" if ENV['VERBOSE']
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def roundtrip(args)
|
77
|
+
decode(encode(args))
|
78
|
+
end
|
79
|
+
|
80
|
+
def add_job(data)
|
81
|
+
@worker_manager[:jobs] << data
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
data/spec/mock_spec.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
#require 'spec_helper'
|
2
|
+
require 'resque/mock'
|
3
|
+
|
4
|
+
Resque.mock!
|
5
|
+
|
6
|
+
class Performer
|
7
|
+
def self.run?
|
8
|
+
!!@args
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.args
|
12
|
+
@args
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.runs
|
16
|
+
@runs || 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.perform(*args)
|
20
|
+
@runs += 1
|
21
|
+
if Hash === (options = args.first)
|
22
|
+
if runs_left = options['runs']
|
23
|
+
runs_left -= 1
|
24
|
+
if runs_left > 0
|
25
|
+
Resque.enqueue(self, 'runs' => runs_left)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
@args = args
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.reset!
|
33
|
+
@args = nil
|
34
|
+
@runs = 0
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class BadPerformer < Performer
|
39
|
+
def self.perform(*args)
|
40
|
+
raise 'hello'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe Resque do
|
45
|
+
before { Performer.reset! }
|
46
|
+
|
47
|
+
describe "synchronously" do
|
48
|
+
it "performs jobs without delay" do
|
49
|
+
Resque.enqueue(Performer, 'hello', 'there')
|
50
|
+
Performer.should be_run
|
51
|
+
Performer.args.should == ['hello', 'there']
|
52
|
+
end
|
53
|
+
|
54
|
+
it "performs jobs with a delay" do
|
55
|
+
Resque.should_receive(:sleep).with(5)
|
56
|
+
Resque.enqueue_in(5, Performer, 'hello', 'there')
|
57
|
+
Performer.should be_run
|
58
|
+
Performer.args.should == ['hello', 'there']
|
59
|
+
end
|
60
|
+
|
61
|
+
it "can perform more jobs that are queued" do
|
62
|
+
Resque.enqueue(Performer, 'runs' => 3)
|
63
|
+
Performer.runs.should == 3
|
64
|
+
end
|
65
|
+
|
66
|
+
it "roundtrips arguments" do
|
67
|
+
Resque.enqueue(Performer, :hello => :there)
|
68
|
+
Performer.args.should == [{ 'hello' => 'there' }]
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe "asynchronously" do
|
73
|
+
it "performs jobs without delay" do
|
74
|
+
Resque.async do
|
75
|
+
Resque.enqueue(Performer, 'hello', 'there')
|
76
|
+
end
|
77
|
+
|
78
|
+
Performer.should be_run
|
79
|
+
Performer.args.should == ['hello', 'there']
|
80
|
+
end
|
81
|
+
|
82
|
+
it "performs jobs with delay" do
|
83
|
+
# not immediately sure how to mock this
|
84
|
+
|
85
|
+
Resque.async do
|
86
|
+
Resque.enqueue_in(5, Performer, 'hello', 'there')
|
87
|
+
end
|
88
|
+
|
89
|
+
Performer.should be_run
|
90
|
+
Performer.args.should == ['hello', 'there']
|
91
|
+
end
|
92
|
+
|
93
|
+
it "can perform more jobs that are queued" do
|
94
|
+
Resque.async { Resque.enqueue(Performer, 'runs' => 3) }
|
95
|
+
Performer.runs.should == 3
|
96
|
+
end
|
97
|
+
|
98
|
+
it "roundtrips arguments" do
|
99
|
+
Resque.async { Resque.enqueue(Performer, :hello => :there) }
|
100
|
+
Performer.args.should == [{ 'hello' => 'there' }]
|
101
|
+
end
|
102
|
+
|
103
|
+
it "raises errors encountered inside the block" do
|
104
|
+
expect { Resque.async { raise 'hello' } }.to raise_error
|
105
|
+
end
|
106
|
+
|
107
|
+
it "raises errors encountered by jobs" do
|
108
|
+
expect { Resque.async { Resque.enqueue(BadPerformer, 5) } }.to raise_error
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: resque-mock
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dan Peterson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-06-16 00:00:00.000000000 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: resque
|
17
|
+
requirement: &2169208800 !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: *2169208800
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: rake
|
28
|
+
requirement: &2169208360 !ruby/object:Gem::Requirement
|
29
|
+
none: false
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: *2169208360
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rspec
|
39
|
+
requirement: &2169207940 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ! '>='
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: '0'
|
45
|
+
type: :development
|
46
|
+
prerelease: false
|
47
|
+
version_requirements: *2169207940
|
48
|
+
description: Mock resque with threads
|
49
|
+
email:
|
50
|
+
- dpiddy@gmail.com
|
51
|
+
executables: []
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- lib/resque/mock.rb
|
56
|
+
- Rakefile
|
57
|
+
- spec/mock_spec.rb
|
58
|
+
has_rdoc: true
|
59
|
+
homepage: https://github.com/dpiddy/resque-mock
|
60
|
+
licenses: []
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options: []
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
requirements: []
|
78
|
+
rubyforge_project:
|
79
|
+
rubygems_version: 1.5.2
|
80
|
+
signing_key:
|
81
|
+
specification_version: 3
|
82
|
+
summary: Mock resque with threads
|
83
|
+
test_files:
|
84
|
+
- Rakefile
|
85
|
+
- spec/mock_spec.rb
|