sidekiq_strategies 0.0.1

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.
@@ -0,0 +1,182 @@
1
+ require 'spec_helper'
2
+
3
+ describe SidekiqStrategies::AccountHandler do
4
+
5
+ before(:each) do
6
+ @subscriber = create_double_subscriber
7
+ @acc_handler = SidekiqStrategies::AccountHandler.new(120, 250, :query, 0, Spool::Publisher)
8
+ @acc_handler.add_subscriber(@subscriber)
9
+ end
10
+
11
+ describe '#new' do
12
+
13
+ it 'return an instance of AccountHandler object' do
14
+ expect( @acc_handler ).to be_an(SidekiqStrategies::AccountHandler)
15
+ end
16
+
17
+ it 'should have an Account reference with id 120' do
18
+ expect( @acc_handler.account ).to be_an(Account)
19
+ expect( @acc_handler.account.id ).to be(120)
20
+ end
21
+
22
+ it 'should have a Transaction reference with id 250' do
23
+ expect( @acc_handler.transaction ).to be_an(Transaction)
24
+ expect( @acc_handler.transaction.id ).to be(250)
25
+ end
26
+
27
+ end
28
+
29
+ describe 'instance methods' do
30
+
31
+ describe '#save_sidekiq_jid' do
32
+ it 'should save jid value' do
33
+ @acc_handler.save_sidekiq_jid('jid123')
34
+ expect( @acc_handler.transaction.sidekiq_jid ).to eql('jid123')
35
+ end
36
+
37
+ it 'should call Transaction.save! with no params' do
38
+ expect( @acc_handler.transaction ).to receive(:save!)
39
+ @acc_handler.save_sidekiq_jid('jid123')
40
+ end
41
+ end
42
+
43
+ describe '#save_beanstalkd_jid' do
44
+ it 'should save jid value' do
45
+ @acc_handler.save_beanstalkd_jid(562)
46
+ expect( @acc_handler.transaction.beanstalkd_jid ).to eql(562)
47
+ end
48
+
49
+ it 'should call Transaction.save! with no params' do
50
+ expect( @acc_handler.transaction ).to receive(:save!)
51
+ @acc_handler.save_beanstalkd_jid(562)
52
+ end
53
+ end
54
+
55
+ describe '#success' do
56
+ it 'should set account state to ready' do
57
+ @acc_handler.success
58
+ expect( @acc_handler.account.state ).to eql('ready')
59
+ end
60
+
61
+ it 'should notify subscribers' do
62
+ expect( @subscriber ).to receive(:state_changed).with(@acc_handler.account, 'reserved', 'ready')
63
+ @acc_handler.success
64
+ end
65
+ end
66
+
67
+ describe '#error' do
68
+ it 'should set account state to error' do
69
+ @acc_handler.error
70
+ expect( @acc_handler.account.state ).to eql('error')
71
+ end
72
+
73
+ it 'should notify subscribers' do
74
+ expect( @subscriber ).to receive(:state_changed).with(@acc_handler.account, 'reserved', 'error')
75
+ @acc_handler.error
76
+ end
77
+ end
78
+
79
+ describe '#start_action' do
80
+ it 'should set account state to querying' do
81
+ @acc_handler.start_action
82
+ expect( @acc_handler.account.state ).to eql('querying')
83
+ end
84
+
85
+ it 'should notify subscribers' do
86
+ expect( @subscriber ).to receive(:state_changed).with(@acc_handler.account, 'reserved', 'querying')
87
+ @acc_handler.start_action
88
+ end
89
+ end
90
+
91
+ describe '#queue_for_retry' do
92
+ it 'should set account state to awaiting_retry' do
93
+ @acc_handler.queue_for_retry
94
+ expect( @acc_handler.account.state ).to eql('awaiting_retry')
95
+ end
96
+
97
+ it 'should increase retry_count in 1' do
98
+ begin_retry_count = @acc_handler.transaction.retry_count
99
+ @acc_handler.queue_for_retry
100
+ expect( @acc_handler.transaction.retry_count ).to be(begin_retry_count + 1)
101
+ end
102
+
103
+ it 'should call Transaction.save! with params "validate: false"' do
104
+ expect( @acc_handler.transaction ).to receive(:save!).with(validate: false)
105
+ @acc_handler.queue_for_retry
106
+ end
107
+
108
+ it 'should notify subscribers' do
109
+ expect( @subscriber ).to receive(:state_changed).with(@acc_handler.account, 'reserved', 'awaiting_retry')
110
+ @acc_handler.queue_for_retry
111
+ end
112
+ end
113
+
114
+ describe '#queue_for_wait_at_worker' do
115
+ it 'should set account state to waiting_at_worker' do
116
+ @acc_handler.queue_for_wait_at_worker
117
+ expect( @acc_handler.account.state ).to eql('waiting_at_worker')
118
+ end
119
+
120
+ it 'should notify subscribers' do
121
+ expect( @subscriber ).to receive(:state_changed).with(@acc_handler.account, 'reserved', 'waiting_at_worker')
122
+ @acc_handler.queue_for_wait_at_worker
123
+ end
124
+ end
125
+
126
+ describe '#save_success_response' do
127
+ it 'should update Transaction.resonse' do
128
+ @acc_handler.save_success_response(create_worker_response)
129
+ expect( @acc_handler.transaction.response ).to eq(create_worker_response)
130
+ end
131
+
132
+ it 'should update Transaction.amount' do
133
+ @acc_handler.save_success_response(create_worker_response)
134
+ expect( @acc_handler.transaction.amount ).to eq(create_worker_response[:amount_due])
135
+ end
136
+
137
+ it 'should update account response' do
138
+ @acc_handler.save_success_response(create_worker_response)
139
+ expect( @acc_handler.account.response ).to_not be(nil)
140
+ end
141
+
142
+ it 'should call Transaction.save! with params "validate: false"' do
143
+ expect( @acc_handler.transaction ).to receive(:save!).with(validate: false)
144
+ @acc_handler.queue_for_retry
145
+ end
146
+ end
147
+
148
+ describe '#save_exception' do
149
+ before(:each) do
150
+ @exception = XBP::Error::ApiInternalError.new('test error')
151
+ @acc_handler.save_exception(@exception)
152
+ end
153
+
154
+ it 'shuold update Transaction.response' do
155
+ expect( @acc_handler.transaction.response ).to_not be(nil)
156
+ end
157
+
158
+ it 'shuold update Transaction.response_code' do
159
+ exception = XBP::Error::ApiInternalError.new('test error')
160
+ end
161
+
162
+ it 'shuold update Transaction.response_messsage' do
163
+ expect( @acc_handler.transaction.response_message ).to_not be(nil)
164
+ end
165
+
166
+ it 'shuold update Transaction.exception_type' do
167
+ expect( @acc_handler.transaction.exception_type ).to eql("XBP::Error::ApiInternalError")
168
+ end
169
+
170
+ it 'shuold update Transaction.exception_message' do
171
+ expect( @acc_handler.transaction.exception_message ).to eql("test error")
172
+ end
173
+
174
+ it 'should call Transaction.save! with params "validate: false"' do
175
+ expect( @acc_handler.transaction ).to receive(:save!).with(validate: false)
176
+ @acc_handler.save_exception(@exception)
177
+ end
178
+ end
179
+
180
+ end
181
+
182
+ end
@@ -0,0 +1,50 @@
1
+ require 'spec_helper'
2
+
3
+ describe SidekiqStrategies::BeanstalkdHandler do
4
+
5
+ before(:each) do
6
+ jobs = create_double_beaneater_jobs({1=>create_double_beaneater_job, 2=>nil})
7
+ tube_pronet = create_double_beaneater_tube(:name=>'pronet')
8
+ tubes = {'pronet' => tube_pronet}
9
+ pool = create_double_beaneater_pool({:jobs=>jobs, :tubes=>tubes})
10
+ @bns_handler = SidekiqStrategies::BeanstalkdHandler.new( pool )
11
+ end
12
+
13
+ describe '#new' do
14
+
15
+ it 'return an BeanstalkdHandler object' do
16
+ expect( @bns_handler ).to be_a SidekiqStrategies::BeanstalkdHandler
17
+ end
18
+
19
+ end
20
+
21
+ describe 'public instance methods' do
22
+
23
+ it '#obtain_tube should return a tube with name pronet' do
24
+ expect( @bns_handler.obtain_tube('pronet') ).to_not be(nil)
25
+ expect( @bns_handler.obtain_tube('pronet').name ).to eq('pronet')
26
+ end
27
+
28
+ it '#find_job with param 1 should return an specific job' do
29
+ expect( @bns_handler.find_job(1) ).to_not be(nil)
30
+ end
31
+
32
+ it '#find_job with param 2 should return null' do
33
+ expect( @bns_handler.find_job(2) ).to be(nil)
34
+ end
35
+
36
+ end
37
+
38
+ describe 'private instance methods' do
39
+
40
+ it '#conn should return a Beaneater::Pool object' do
41
+ expect( @bns_handler.send(:conn) ).to be_an(create_double_beaneater_pool.class)
42
+ end
43
+
44
+ it '#host should be a valid host name' do
45
+ expect( @bns_handler.send(:host) ).to eql('localhost:11300')
46
+ end
47
+
48
+ end
49
+
50
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe SidekiqStrategies::Helper do
4
+
5
+ before(:each) do
6
+ @acc_handler = SidekiqStrategies::AccountHandler.new(120, 250, :query, 0, Spool::Publisher)
7
+ @helper = SidekiqStrategies::Helper.new(@acc_handler, Rails.application.routes.url_helpers)
8
+ end
9
+
10
+ describe '#new' do
11
+
12
+ it 'return an instance of Helper object' do
13
+ expect( @helper ).to be_an(SidekiqStrategies::Helper)
14
+ end
15
+
16
+ end
17
+
18
+ describe 'instance methods' do
19
+
20
+ it '#reply_tube_name should return a valid tube name' do
21
+ expect( @helper.reply_tube_name ).to eql("gt-120")
22
+ end
23
+
24
+ it '#request_tube_name should return a valid tube name' do
25
+ expect( @helper.request_tube_name ).to eql("pronet")
26
+ end
27
+
28
+ it '#queue_message should return a valid message' do
29
+ queue_message = {
30
+ :account => 120,
31
+ :account_url => "http://api.bluekite.com/v1/services/gt/claro-postpay/accounts/120",
32
+ :action => :query,
33
+ :fields => {:reference=>"", :end_user_id=>"", :priority=>"normal", :code=>"", :end_user_ip_address=>"192.168.0.1", :monitor_as_url=>"http://10.33.33.22:3000/v1/services/gt/claro-postpay/accounts/1", :account_number=>"55748576", :total_cents=>""},
34
+ :number => "55748576",
35
+ :provider => "claro_postpay",
36
+ :reply_tube => "gt-120",
37
+ :request_tube => "pronet",
38
+ :retry_count => 0,
39
+ :service => "claro-postpay"
40
+ }
41
+ expect( @helper.queue_message ).to eql(queue_message)
42
+ end
43
+
44
+ describe '#try_again?' do
45
+ it 'should return false if transaction.retry_count is greater than 2' do
46
+ @helper.acc_handler.transaction.retry_count = 5
47
+ expect( @helper.try_again?(nil) ).to eql(false)
48
+ end
49
+
50
+ it 'should return true if it is an a retryable exception' do
51
+ expect( @helper.try_again?({:retry_action => true}) ).to eql(true)
52
+ end
53
+
54
+ it 'should return false if it isn\'t an a retryable exception' do
55
+ expect( @helper.try_again?({:retry_action => false}) ).to eql(false)
56
+ end
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,206 @@
1
+ require 'spec_helper'
2
+
3
+ describe SidekiqStrategies::PollingStrategy do
4
+
5
+ before(:each) do
6
+ @logger = create_double_logger
7
+ @airbrake_notifier = create_double_airbrake
8
+
9
+ @acc_handler = SidekiqStrategies::AccountHandler.new(120, 250, :query, 0, Spool::Publisher)
10
+ @helper = SidekiqStrategies::Helper.new(@acc_handler, Rails.application.routes.url_helpers)
11
+ @strategy = SidekiqStrategies::PollingStrategy.new(nil, nil, nil, nil, nil)
12
+ end
13
+
14
+ describe '#new' do
15
+
16
+ it 'return an instance of PollingStrategy object' do
17
+ expect( @strategy ).to be_an(SidekiqStrategies::PollingStrategy)
18
+ end
19
+
20
+ it 'should respond to #perform' do
21
+ expect( @strategy.respond_to?('perform') ).to be(true)
22
+ end
23
+
24
+ it 'should respond to #retries_exhausted' do
25
+ expect( @strategy.respond_to?('retries_exhausted') ).to be(true)
26
+ end
27
+
28
+ it 'should expect 4 params on constructor' do
29
+ expect{
30
+ SidekiqStrategies::PollingStrategy.new
31
+ }.to raise_error
32
+
33
+ expect{
34
+ SidekiqStrategies::PollingStrategy.new(nil, nil, nil, nil, nil)
35
+ }.to_not raise_error
36
+ end
37
+
38
+ end
39
+
40
+ describe '#perform' do
41
+
42
+ context 'when Beanstalkd service is not reachable' do
43
+ before(:each) do
44
+ pool = create_double_beaneater_pool
45
+ allow(pool).to receive(:tubes).and_raise(Beaneater::NotConnected)
46
+
47
+ @bns_handler = SidekiqStrategies::BeanstalkdHandler.new(pool)
48
+ @strategy = SidekiqStrategies::PollingStrategy.new(@acc_handler, @bns_handler, @logger, @airbrake_notifier, @helper)
49
+ end
50
+
51
+ it 'should raise XBP::Error::MessageQueueNotReachable error' do
52
+ expect{
53
+ @strategy.perform('abc123')
54
+ }.to raise_error(XBP::Error::MessageQueueNotReachable)
55
+ end
56
+
57
+ it 'should set account state to awaiting_retry' do
58
+ begin
59
+ @strategy.perform('abc123')
60
+ rescue XBP::Error::MessageQueueNotReachable=>e
61
+ expect( @acc_handler.account.state ).to eql('awaiting_retry')
62
+ end
63
+ end
64
+ end
65
+
66
+ context 'when there are no workers available' do
67
+ before(:each) do
68
+ request_tube_stats = create_stats({:current_watching=>0})
69
+ request_tube = create_double_beaneater_tube(:name=>'pronet', :stats=>request_tube_stats)
70
+ tubes = {'pronet'=>request_tube}
71
+ pool = create_double_beaneater_pool({:tubes=>tubes})
72
+
73
+ @bns_handler = SidekiqStrategies::BeanstalkdHandler.new(pool)
74
+ @strategy = SidekiqStrategies::PollingStrategy.new(@acc_handler, @bns_handler, @logger, @airbrake_notifier, @helper)
75
+ end
76
+
77
+ it 'should raise XBP::Error::WorkersUnavailable error' do
78
+ expect{
79
+ @strategy.perform('abc123')
80
+ }.to raise_error(XBP::Error::WorkersUnavailable)
81
+ end
82
+
83
+ it 'should set account state to awaiting_retry' do
84
+ begin
85
+ @strategy.perform('abc123')
86
+ rescue XBP::Error::WorkersUnavailable=>e
87
+ expect( @acc_handler.account.state ).to eql('awaiting_retry')
88
+ end
89
+ end
90
+ end
91
+
92
+ context 'when account state is not included in [reserved, awaiting_retry, waiting_at_worker]' do
93
+ context 'when there is no previous data' do
94
+ before(:each) do
95
+ @acc_handler.account.state = 'querying'
96
+
97
+ request_tube = create_double_beaneater_tube(:name=>'pronet')
98
+ tubes = {'pronet'=>request_tube}
99
+ pool = create_double_beaneater_pool({:tubes=>tubes})
100
+
101
+ @bns_handler = SidekiqStrategies::BeanstalkdHandler.new(pool)
102
+ @strategy = SidekiqStrategies::PollingStrategy.new(@acc_handler, @bns_handler, @logger, @airbrake_notifier, @helper)
103
+ end
104
+
105
+ it 'should not raise error' do
106
+ expect{
107
+ @strategy.perform('abc123')
108
+ }.to_not raise_error
109
+ end
110
+
111
+ it 'should set account state to error' do
112
+ @strategy.perform('abc123')
113
+ expect( @acc_handler.account.state ).to eql('error')
114
+ end
115
+ end
116
+ end
117
+
118
+ context 'when response is never received' do
119
+ before(:each) do
120
+ request_tube_stats = create_stats({:current_watching=>1})
121
+ reply_tube_stats = create_stats({:state=>'ready'})
122
+ request_tube = create_double_beaneater_tube(:name=>'pronet', :stats=>request_tube_stats, :put_response=>{:id=>1})
123
+ reply_tube = create_double_beaneater_tube({:name=>'gt-120'})
124
+ tubes = {'pronet'=>request_tube, 'gt-120'=>reply_tube}
125
+ request_job_stats = create_stats({:state=>'ready'})
126
+ request_job = create_double_beaneater_job({:stats=>request_job_stats})
127
+ jobs = create_double_beaneater_jobs({1=>request_job})
128
+ pool = create_double_beaneater_pool({:tubes=>tubes, :jobs=>jobs})
129
+
130
+ allow(reply_tube).to receive(:reserve).with(1).and_raise(Beaneater::TimedOutError.new(nil, nil))
131
+
132
+ @bns_handler = SidekiqStrategies::BeanstalkdHandler.new(pool)
133
+ @strategy = SidekiqStrategies::PollingStrategy.new(@acc_handler, @bns_handler, @logger, @airbrake_notifier, @helper)
134
+
135
+ @strategy.poll_tries_before_airbrake = 10
136
+ @strategy.poll_max_tries = 20
137
+ end
138
+
139
+ it 'should set account state to error' do
140
+ @strategy.perform('abc123')
141
+ expect( @acc_handler.account.state ).to eql('error')
142
+ end
143
+
144
+ it 'should send an airbrake when 10 seconds of polling has been reached' do
145
+ expect( @airbrake_notifier ).to receive(:notify).with(:error_message => "Polling is taking more than 10 seconds.")
146
+ @strategy.perform('abc123')
147
+ end
148
+
149
+ it 'should send an airbrake when 20 seconds of polling has been reached' do
150
+ expect( @airbrake_notifier ).to receive(:notify).with(:error_message => "Queue gt-120 time out. Waited 20 seconds.")
151
+ @strategy.perform('abc123')
152
+ end
153
+ end
154
+
155
+ context 'when response is received' do
156
+ context 'when is success' do
157
+ before(:each) do
158
+ request_tube_stats = create_stats({:current_watching=>1})
159
+ request_tube = create_double_beaneater_tube(:name=>'pronet', :stats=>request_tube_stats, :put_response=>{:id=>1})
160
+ reply_tube = create_double_beaneater_tube({:name=>'gt-120'})
161
+ tubes = {'pronet'=>request_tube, 'gt-120'=>reply_tube}
162
+ request_job_stats = create_stats({:state=>'ready'})
163
+ request_job = create_double_beaneater_job({:stats=>request_job_stats})
164
+ reply_job = create_double_beaneater_job({:body=>Oj.dump(create_worker_response)})
165
+ jobs = create_double_beaneater_jobs({1=>request_job})
166
+ pool = create_double_beaneater_pool({:tubes=>tubes, :jobs=>jobs})
167
+
168
+ allow(reply_tube).to receive(:reserve).with(1).and_return(reply_job)
169
+
170
+ @bns_handler = SidekiqStrategies::BeanstalkdHandler.new(pool)
171
+ @strategy = SidekiqStrategies::PollingStrategy.new(@acc_handler, @bns_handler, @logger, @airbrake_notifier, @helper)
172
+ end
173
+
174
+ it 'should set account state to ready' do
175
+ @strategy.perform('abc123')
176
+ expect( @acc_handler.account.state ).to eql('ready')
177
+ end
178
+ end
179
+
180
+ context 'when is error' do
181
+ before(:each) do
182
+ request_tube_stats = create_stats({:current_watching=>1})
183
+ request_tube = create_double_beaneater_tube(:name=>'pronet', :stats=>request_tube_stats, :put_response=>{:id=>1})
184
+ reply_tube = create_double_beaneater_tube({:name=>'gt-120'})
185
+ tubes = {'pronet'=>request_tube, 'gt-120'=>reply_tube}
186
+ request_job_stats = create_stats({:state=>'ready'})
187
+ request_job = create_double_beaneater_job({:stats=>request_job_stats})
188
+ reply_job = create_double_beaneater_job({:body=>Oj.dump({:exception=>create_worker_exception})})
189
+ jobs = create_double_beaneater_jobs({1=>request_job})
190
+ pool = create_double_beaneater_pool({:tubes=>tubes, :jobs=>jobs})
191
+
192
+ allow(reply_tube).to receive(:reserve).with(1).and_return(reply_job)
193
+
194
+ @bns_handler = SidekiqStrategies::BeanstalkdHandler.new(pool)
195
+ @strategy = SidekiqStrategies::PollingStrategy.new(@acc_handler, @bns_handler, @logger, @airbrake_notifier, @helper)
196
+ end
197
+
198
+ it 'should set account state to error' do
199
+ @strategy.perform('abc123')
200
+ expect( @acc_handler.account.state ).to eql('error')
201
+ end
202
+ end
203
+ end
204
+ end
205
+
206
+ end