sidekiq_strategies 0.0.1

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