ruote-resque 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,208 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+ require 'ruote/storage/fs_storage'
5
+
6
+ class BravoJob
7
+ @queue = :rspec
8
+ extend Ruote::Resque::Job
9
+ def self.perform(workitem)
10
+ workitem['fields']['resque_bravo'] = 'was here'
11
+ end
12
+ end
13
+
14
+ class BravoError < RuntimeError
15
+ end
16
+
17
+ class BravoFailureJob < BravoJob
18
+ @queue = :rspec
19
+ extend Ruote::Resque::Job
20
+ def self.perform(workitem)
21
+ raise BravoError, 'im a failure'
22
+ end
23
+ end
24
+
25
+ RUOTE_WAIT_TIMEOUT = 10
26
+
27
+ describe Ruote::Resque::Receiver do
28
+
29
+ before :each do
30
+
31
+ Resque.redis.flushdb
32
+
33
+ @board = Ruote::Dashboard.new(Ruote::Worker.new(Ruote::HashStorage.new))
34
+ # @board.noisy = true
35
+
36
+ @board.register(/^block_/) do |workitem|
37
+ workitem.fields[workitem.participant_name] = 'was here'
38
+ end
39
+
40
+ @worker = Thread.new do
41
+ queues = ['rspec']
42
+ worker = Resque::Worker.new(*queues)
43
+ worker.term_timeout = 4
44
+ worker.term_child = true
45
+ # worker.verbose = true
46
+ worker.work(1)
47
+ end
48
+
49
+ Ruote::Resque.configure do |config|
50
+ config.interval = 1
51
+ end
52
+
53
+ @receiver = Ruote::Resque::Receiver.new(@board)
54
+
55
+ end
56
+
57
+ after :each do
58
+
59
+ @board.shutdown
60
+ @board.storage.purge!
61
+ @receiver.shutdown
62
+ @worker.kill
63
+
64
+ Ruote::Resque.configure do |config|
65
+ config.interval = 5
66
+ end
67
+ end
68
+
69
+ let(:definition) do
70
+ Ruote.define :on_error => 'block_delta' do
71
+ block_alpha
72
+ resque_bravo
73
+ block_charly
74
+ end
75
+ end
76
+
77
+ context 'invalid job handling' do
78
+
79
+ it 'raises InvalidJob' do
80
+
81
+ class AnotherJob
82
+ end
83
+
84
+ Ruote::Resque::Receiver.any_instance.should_receive(:handle_error) do |e|
85
+ e.class.should eq(Ruote::Resque::InvalidJob)
86
+ end
87
+
88
+ Resque.enqueue_to(Ruote::Resque.configuration.reply_queue, 'AnotherJob')
89
+
90
+ # Ensure it is picked up by the receiver + cleanup afterwards
91
+ sleep 2
92
+ ::Resque.reserve(Ruote::Resque.configuration.reply_queue)
93
+
94
+ end
95
+
96
+ it 'raises InvalidWorkitem' do
97
+
98
+ Ruote::Resque::Receiver.any_instance.should_receive(:handle_error) do |e|
99
+ e.class.should eq(Ruote::Resque::InvalidWorkitem)
100
+ end
101
+
102
+ Resque.enqueue_to(Ruote::Resque.configuration.reply_queue, Ruote::Resque::ReplyJob, {})
103
+
104
+ # Ensure it is picked up by the receiver + cleanup afterwards
105
+ sleep 2
106
+ ::Resque.reserve(Ruote::Resque.configuration.reply_queue)
107
+
108
+ end
109
+
110
+ end
111
+
112
+ context 'participant/reply flow' do
113
+
114
+ context 'with no exceptions raised' do
115
+
116
+ before(:each) do
117
+ Ruote::Resque.register @board do
118
+ resque_bravo BravoJob, :rspec
119
+ end
120
+ end
121
+
122
+ it 'completes successfully' do
123
+
124
+ wfid = @board.launch(definition)
125
+
126
+ r = @board.wait_for(wfid, :timeout => RUOTE_WAIT_TIMEOUT)
127
+ # wait until process terminates or hits an error
128
+
129
+ r['workitem'].should_not eq(nil)
130
+ r['workitem']['fields']['block_alpha'].should eq('was here')
131
+ r['workitem']['fields']['resque_bravo'].should eq('was here')
132
+ r['workitem']['fields']['block_charly'].should eq('was here')
133
+ r['workitem']['fields']['block_delta'].should eq(nil)
134
+ end
135
+ end
136
+
137
+ context 'with an exception raised' do
138
+
139
+ before(:each) do
140
+ Ruote::Resque.register @board do
141
+ resque_bravo BravoFailureJob, :rspec
142
+ end
143
+ end
144
+
145
+ it 'routes to the error handler' do
146
+
147
+ wfid = @board.launch(definition)
148
+
149
+ r = @board.wait_for(wfid, :timeout => RUOTE_WAIT_TIMEOUT)
150
+ # wait until process terminates or hits an error
151
+
152
+ r['workitem'].should_not eq(nil)
153
+ r['workitem']['fields']['block_alpha'].should eq('was here')
154
+ r['workitem']['fields']['resque_bravo'].should eq(nil)
155
+ r['workitem']['fields']['block_charly'].should eq(nil)
156
+ r['workitem']['fields']['block_delta'].should eq('was here')
157
+ end
158
+
159
+ it 'marks the job as failed in Resque' do
160
+
161
+ wfid = @board.launch(definition)
162
+
163
+ r = @board.wait_for(wfid, :timeout => RUOTE_WAIT_TIMEOUT)
164
+ # wait until process terminates or hits an error
165
+
166
+ Resque::Failure.count.should eq(1)
167
+ failed = Resque::Failure.all(0, 1)
168
+ failed.class.should eq(Hash)
169
+ failed['payload']['class'].should eq('BravoFailureJob')
170
+ failed['exception'].should eq('BravoError')
171
+ failed['error'].should eq('im a failure')
172
+ end
173
+
174
+ it 'can be replayed from Ruote' do
175
+
176
+ definition = Ruote.define do
177
+ block_alpha
178
+ resque_bravo
179
+ block_charly
180
+ end
181
+
182
+ wfid = @board.launch(definition)
183
+
184
+ r = @board.wait_for(wfid, :timeout => RUOTE_WAIT_TIMEOUT)
185
+ error = @board.errors(wfid).first
186
+
187
+ expect(error.class).to eq(Ruote::ProcessError)
188
+ expect(error.klass).to eq('Ruote::ReceivedError')
189
+ expect(error.message).to eq('raised: Ruote::ReceivedError: BravoError: im a failure')
190
+ expect(error.trace).to include("/lib/resque/worker.rb:195:in `perform'")
191
+
192
+ Ruote::Resque.register @board do
193
+ resque_bravo BravoJob, :rspec
194
+ end
195
+ @board.replay_at_error(error)
196
+
197
+ r = @board.wait_for(wfid, :timeout => RUOTE_WAIT_TIMEOUT)
198
+
199
+ r['workitem'].should_not eq(nil)
200
+ r['workitem']['fields']['block_alpha'].should eq('was here')
201
+ r['workitem']['fields']['resque_bravo'].should eq('was here')
202
+ r['workitem']['fields']['block_charly'].should eq('was here')
203
+
204
+ end
205
+ end
206
+ end
207
+
208
+ end
@@ -0,0 +1,38 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Ruote::Resque::ReplyJob do
6
+
7
+ context '::queue' do
8
+
9
+ let(:queue) { :my_queue }
10
+ let!(:default_queue) { Ruote::Resque.configuration.reply_queue }
11
+
12
+ before :each do
13
+ Ruote::Resque.configure do |config|
14
+ config.reply_queue = queue
15
+ end
16
+ end
17
+
18
+ after :each do
19
+ Ruote::Resque.configure do |config|
20
+ config.reply_queue = default_queue
21
+ end
22
+ end
23
+
24
+ it 'returns the configured reply queue' do
25
+ expect(Ruote::Resque::ReplyJob.queue).to eq :my_queue
26
+ end
27
+
28
+ end
29
+
30
+ context '::perform' do
31
+
32
+ it 'returns nil' do
33
+ expect(Ruote::Resque::ReplyJob.perform).to be_nil
34
+ end
35
+
36
+ end
37
+
38
+ end
@@ -0,0 +1,99 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Ruote::Resque do
6
+
7
+ context '::logger' do
8
+
9
+ it 'returns a Logger instance' do
10
+ expect(Ruote::Resque.logger.class).to eq Logger
11
+ end
12
+
13
+ end
14
+
15
+ context '::reply' do
16
+
17
+ it 'enqueues a reply' do
18
+ Ruote::Resque.reply({ 'field' => 'test' })
19
+
20
+ expected_job = { 'class' => 'Ruote::Resque::ReplyJob', 'args' => [{ 'field' => 'test' }] }
21
+ expect(::Resque.pop(:ruote_replies)).to eq expected_job
22
+
23
+ end
24
+
25
+ end
26
+
27
+ context '::register' do
28
+
29
+ class MyAwesomeJob; end
30
+
31
+ let(:mock_dashboard) { Object.new }
32
+
33
+ it 'allows registration of participants with a block' do
34
+
35
+ mock_dashboard.should_receive(:register_participant).with('be_awesome', Ruote::Resque::Participant, { :class => MyAwesomeJob, :queue => :rspec })
36
+ Ruote::Resque.register mock_dashboard do
37
+ be_awesome MyAwesomeJob, :rspec
38
+ end
39
+
40
+ end
41
+
42
+ end
43
+
44
+ context '::configuration' do
45
+
46
+ it 'returns a Configuration object' do
47
+ expect(Ruote::Resque.configuration.class.to_s).to eq 'Ruote::Resque::Configuration'
48
+ end
49
+
50
+ context '::reply_queue' do
51
+
52
+ it 'is :ruote_replies by default' do
53
+ expect(Ruote::Resque.configuration.reply_queue).to eq :ruote_replies
54
+ end
55
+
56
+ it 'is setable' do
57
+ Ruote::Resque.configuration.reply_queue = :another_queue
58
+ expect(Ruote::Resque.configuration.reply_queue).to eq :another_queue
59
+ end
60
+
61
+ end
62
+
63
+ context '::interval' do
64
+
65
+ it 'is 5 by default' do
66
+ expect(Ruote::Resque.configuration.interval).to eq 5
67
+ end
68
+
69
+ it 'is setable' do
70
+ Ruote::Resque.configuration.interval = 1
71
+ expect(Ruote::Resque.configuration.interval).to eq 1
72
+ end
73
+
74
+ end
75
+
76
+ context '::logger' do
77
+
78
+ it 'is a Logger instance' do
79
+ expect(Ruote::Resque.configuration.logger.class).to eq Logger
80
+ end
81
+
82
+ it 'is logging at INFO level' do
83
+ expect(Ruote::Resque.configuration.logger.level).to eq Logger::INFO
84
+ end
85
+
86
+ it 'is a setable' do
87
+
88
+ class MyLogger < Logger
89
+ end
90
+ Ruote::Resque.configuration.logger = MyLogger.new(STDOUT)
91
+
92
+ expect(Ruote::Resque.configuration.logger.class).to eq MyLogger
93
+ end
94
+
95
+ end
96
+
97
+ end
98
+
99
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'coveralls'
4
+ Coveralls.wear!
5
+
6
+ require 'resque'
7
+ require 'ruote/resque'
8
+
9
+ RSpec.configure do |config|
10
+
11
+ config.mock_with :rspec
12
+
13
+ config.before(:suite) do
14
+ Resque.redis.namespace = 'resque:rspec'
15
+ end
16
+
17
+ config.after(:each) do
18
+ Resque.queues.each { |queue| Resque.remove_queue(queue) }
19
+ end
20
+
21
+ end
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruote-resque
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Adrien Kohlbecker
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-06-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: resque
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: mutant
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: redcarpet
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Resque participant/receiver pair for Ruote
98
+ email:
99
+ - adrien.kohlbecker@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - .gitignore
105
+ - .rspec
106
+ - .rubocop.yml
107
+ - .travis.yml
108
+ - .yardopts
109
+ - Gemfile
110
+ - LICENSE
111
+ - README.md
112
+ - Rakefile
113
+ - lib/ruote/resque.rb
114
+ - lib/ruote/resque/client.rb
115
+ - lib/ruote/resque/job.rb
116
+ - lib/ruote/resque/participant.rb
117
+ - lib/ruote/resque/participant_registrar.rb
118
+ - lib/ruote/resque/receiver.rb
119
+ - lib/ruote/resque/reply_job.rb
120
+ - lib/ruote/resque/version.rb
121
+ - ruote-resque.gemspec
122
+ - spec/lib/ruote/resque/job_spec.rb
123
+ - spec/lib/ruote/resque/participant_registrar_spec.rb
124
+ - spec/lib/ruote/resque/participant_spec.rb
125
+ - spec/lib/ruote/resque/receiver_spec.rb
126
+ - spec/lib/ruote/resque/reply_job_spec.rb
127
+ - spec/lib/ruote/resque_spec.rb
128
+ - spec/spec_helper.rb
129
+ homepage: https://github.com/adrienkohlbecker/ruote-resque
130
+ licenses:
131
+ - MIT
132
+ metadata: {}
133
+ post_install_message:
134
+ rdoc_options: []
135
+ require_paths:
136
+ - lib
137
+ required_ruby_version: !ruby/object:Gem::Requirement
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ required_rubygems_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ! '>='
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ requirements: []
148
+ rubyforge_project:
149
+ rubygems_version: 2.0.3
150
+ signing_key:
151
+ specification_version: 4
152
+ summary: Resque participant/receiver pair for Ruote
153
+ test_files:
154
+ - spec/lib/ruote/resque/job_spec.rb
155
+ - spec/lib/ruote/resque/participant_registrar_spec.rb
156
+ - spec/lib/ruote/resque/participant_spec.rb
157
+ - spec/lib/ruote/resque/receiver_spec.rb
158
+ - spec/lib/ruote/resque/reply_job_spec.rb
159
+ - spec/lib/ruote/resque_spec.rb
160
+ - spec/spec_helper.rb
161
+ has_rdoc: