rapns_rails_2 3.5.1 → 3.6.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.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +2 -0
  3. data/lib/rapns/daemon/gcm/delivery.rb +4 -3
  4. data/lib/rapns/version.rb +1 -1
  5. metadata +46 -163
  6. data/config/database.yml +0 -44
  7. data/spec/support/cert_with_password.pem +0 -90
  8. data/spec/support/cert_without_password.pem +0 -59
  9. data/spec/support/simplecov_helper.rb +0 -13
  10. data/spec/support/simplecov_quality_formatter.rb +0 -8
  11. data/spec/tmp/.gitkeep +0 -0
  12. data/spec/unit/apns/app_spec.rb +0 -29
  13. data/spec/unit/apns/feedback_spec.rb +0 -9
  14. data/spec/unit/apns/notification_spec.rb +0 -215
  15. data/spec/unit/apns_feedback_spec.rb +0 -21
  16. data/spec/unit/app_spec.rb +0 -16
  17. data/spec/unit/configuration_spec.rb +0 -55
  18. data/spec/unit/daemon/apns/app_runner_spec.rb +0 -45
  19. data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +0 -11
  20. data/spec/unit/daemon/apns/connection_spec.rb +0 -287
  21. data/spec/unit/daemon/apns/delivery_handler_spec.rb +0 -59
  22. data/spec/unit/daemon/apns/delivery_spec.rb +0 -101
  23. data/spec/unit/daemon/apns/disconnection_error_spec.rb +0 -18
  24. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +0 -134
  25. data/spec/unit/daemon/app_runner_shared.rb +0 -83
  26. data/spec/unit/daemon/app_runner_spec.rb +0 -170
  27. data/spec/unit/daemon/batch_spec.rb +0 -219
  28. data/spec/unit/daemon/delivery_error_spec.rb +0 -13
  29. data/spec/unit/daemon/delivery_handler_collection_spec.rb +0 -37
  30. data/spec/unit/daemon/delivery_handler_shared.rb +0 -45
  31. data/spec/unit/daemon/feeder_spec.rb +0 -89
  32. data/spec/unit/daemon/gcm/app_runner_spec.rb +0 -19
  33. data/spec/unit/daemon/gcm/delivery_handler_spec.rb +0 -44
  34. data/spec/unit/daemon/gcm/delivery_spec.rb +0 -289
  35. data/spec/unit/daemon/interruptible_sleep_spec.rb +0 -68
  36. data/spec/unit/daemon/reflectable_spec.rb +0 -27
  37. data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +0 -114
  38. data/spec/unit/daemon/store/active_record_spec.rb +0 -281
  39. data/spec/unit/daemon_spec.rb +0 -157
  40. data/spec/unit/deprecatable_spec.rb +0 -32
  41. data/spec/unit/deprecation_spec.rb +0 -15
  42. data/spec/unit/embed_spec.rb +0 -50
  43. data/spec/unit/gcm/app_spec.rb +0 -4
  44. data/spec/unit/gcm/notification_spec.rb +0 -52
  45. data/spec/unit/logger_spec.rb +0 -180
  46. data/spec/unit/notification_shared.rb +0 -45
  47. data/spec/unit/notification_spec.rb +0 -4
  48. data/spec/unit/notifier_spec.rb +0 -52
  49. data/spec/unit/push_spec.rb +0 -44
  50. data/spec/unit/rapns_spec.rb +0 -9
  51. data/spec/unit/reflection_spec.rb +0 -30
  52. data/spec/unit/upgraded_spec.rb +0 -40
  53. data/spec/unit_spec_helper.rb +0 -137
@@ -1,289 +0,0 @@
1
- require File.expand_path("spec/unit_spec_helper")
2
-
3
- describe Rapns::Daemon::Gcm::Delivery do
4
- let(:app) { Rapns::Gcm::App.new(:name => 'MyApp', :auth_key => 'abc123') }
5
- let(:notification) { Rapns::Gcm::Notification.create!(:app => app, :registration_ids => ['xyz'], :deliver_after => Time.now) }
6
- let(:logger) { double(:error => nil, :info => nil, :warn => nil) }
7
- let(:response) { double(:code => 200, :header => {}) }
8
- let(:http) { double(:shutdown => nil, :request => response)}
9
- let(:now) { Time.parse('2012-10-14 00:00:00') }
10
- let(:batch) { double(:mark_failed => nil, :mark_delivered => nil, :mark_retryable => nil) }
11
- let(:delivery) { Rapns::Daemon::Gcm::Delivery.new(app, http, notification, batch) }
12
- let(:store) { double(:create_gcm_notification => double(:id => 2)) }
13
-
14
- def perform
15
- delivery.perform
16
- end
17
-
18
- before do
19
- delivery.stub(:reflect => nil)
20
- Rapns::Daemon.stub(:store => store)
21
- Time.stub(:now => now)
22
- Rapns.stub(:logger => logger)
23
- end
24
-
25
- shared_examples_for 'an notification with some delivery failures' do
26
- let(:new_notification) { Rapns::Gcm::Notification.where('id != ?', notification.id).first }
27
-
28
- before { response.stub(:body => MultiJson.dump(body) ) }
29
-
30
- it 'marks the original notification as failed' do
31
- batch.should_receive(:mark_failed).with(notification, nil, error_description)
32
- perform rescue Rapns::DeliveryError
33
- end
34
-
35
- it 'creates a new notification for the unavailable devices' do
36
- notification.update_attributes(:registration_ids => ['id_0', 'id_1', 'id_2'], :data => {'one' => 1}, :collapse_key => 'thing', :delay_while_idle => true)
37
- response.stub(:header => { 'retry-after' => 10 })
38
- attrs = { 'collapse_key' => 'thing', 'delay_while_idle' => true, 'app_id' => app.id }
39
- store.should_receive(:create_gcm_notification).with(attrs, notification.data,
40
- ['id_0', 'id_2'], now + 10.seconds, notification.app)
41
- perform rescue Rapns::DeliveryError
42
- end
43
-
44
- it 'raises a DeliveryError' do
45
- expect { perform }.to raise_error(Rapns::DeliveryError)
46
- end
47
- end
48
-
49
- describe 'an 200 response' do
50
- before do
51
- response.stub(:code => 200)
52
- end
53
-
54
- it 'marks the notification as delivered if delivered successfully to all devices' do
55
- response.stub(:body => MultiJson.dump({ 'failure' => 0 }))
56
- batch.should_receive(:mark_delivered).with(notification)
57
- perform
58
- end
59
-
60
- it 'logs that the notification was delivered' do
61
- response.stub(:body => MultiJson.dump({ 'failure' => 0 }))
62
- logger.should_receive(:info).with("[MyApp] #{notification.id} sent to xyz")
63
- perform
64
- end
65
-
66
- it 'marks a notification as failed if any deliveries failed that cannot be retried.' do
67
- body = {
68
- 'failure' => 1,
69
- 'success' => 1,
70
- 'results' => [
71
- { 'message_id' => '1:000' },
72
- { 'error' => 'InvalidDataKey' }
73
- ]}
74
- response.stub(:body => MultiJson.dump(body))
75
- batch.should_receive(:mark_failed).with(notification, nil, "Failed to deliver to all recipients. Errors: InvalidDataKey.")
76
- perform rescue Rapns::DeliveryError
77
- end
78
-
79
- it 'reflects on canonical IDs' do
80
- body = {
81
- 'failure' => 0,
82
- 'success' => 3,
83
- 'canonical_ids' => 1,
84
- 'results' => [
85
- { 'message_id' => '1:000' },
86
- { 'message_id' => '1:000', 'registration_id' => 'canonical123' },
87
- { 'message_id' => '1:000' },
88
- ]}
89
-
90
- response.stub(:body => MultiJson.dump(body))
91
- notification.stub(:registration_ids => ['1', '2', '3'])
92
- delivery.should_receive(:reflect).with(:gcm_canonical_id, '2', 'canonical123')
93
- perform
94
- end
95
-
96
- it 'reflects on invalid IDs' do
97
- body = {
98
- 'failure' => 1,
99
- 'success' => 2,
100
- 'canonical_ids' => 0,
101
- 'results' => [
102
- { 'message_id' => '1:000' },
103
- { 'error' => 'NotRegistered' },
104
- { 'message_id' => '1:000' },
105
- ]}
106
-
107
- response.stub(:body => MultiJson.dump(body))
108
- notification.stub(:registration_ids => ['1', '2', '3'])
109
- delivery.should_receive(:reflect).with(:gcm_invalid_registration_id, app, 'NotRegistered', '2')
110
- perform
111
- end
112
-
113
- it 'does marks a notification as failed if any ids are invalid.' do
114
- body = {
115
- 'failure' => 1,
116
- 'success' => 2,
117
- 'canonical_ids' => 0,
118
- 'results' => [
119
- { 'message_id' => '1:000' },
120
- { 'error' => 'NotRegistered' },
121
- { 'message_id' => '1:000' },
122
- ]}
123
-
124
- response.stub(:body => MultiJson.dump(body))
125
- batch.should_receive(:mark_failed)
126
- batch.should_not_receive(:mark_retryable)
127
- store.should_not_receive(:create_gcm_notification)
128
- perform
129
- end
130
-
131
- describe 'all deliveries returned Unavailable or InternalServerError' do
132
- let(:body) {{
133
- 'failure' => 2,
134
- 'success' => 0,
135
- 'results' => [
136
- { 'error' => 'Unavailable' },
137
- { 'error' => 'Unavailable' }
138
- ]}}
139
-
140
- before { response.stub(:body => MultiJson.dump(body)) }
141
-
142
- it 'retries the notification respecting the Retry-After header' do
143
- response.stub(:header => { 'retry-after' => 10 })
144
- batch.should_receive(:mark_retryable).with(notification, now + 10.seconds)
145
- perform
146
- end
147
-
148
- it 'retries the notification using exponential back-off if the Retry-After header is not present' do
149
- batch.should_receive(:mark_retryable).with(notification, now + 2)
150
- perform
151
- end
152
-
153
- it 'does not mark the notification as failed' do
154
- batch.should_not_receive(:mark_failed)
155
- perform
156
- end
157
-
158
- it 'logs that the notification will be retried' do
159
- notification.retries = 1
160
- notification.deliver_after = now + 2
161
- Rapns.logger.should_receive(:warn).with("All recipients unavailable. Notification #{notification.id} will be retried after 2012-10-14 00:00:02 (retry 1).")
162
- perform
163
- end
164
- end
165
-
166
- shared_examples_for 'an notification with some delivery failures (200)' do
167
- let(:new_notification) { Rapns::Gcm::Notification.where('id != ?', notification.id).first }
168
-
169
- before { response.stub(:body => MultiJson.dump(body)) }
170
-
171
- it 'marks the original notification as failed' do
172
- batch.should_receive(:mark_failed).with(notification, nil, error_description)
173
- perform rescue Rapns::DeliveryError
174
- end
175
-
176
- it 'creates a new notification for the unavailable devices' do
177
- notification.update_attributes(:registration_ids => ['id_0', 'id_1', 'id_2'], :data => {'one' => 1}, :collapse_key => 'thing', :delay_while_idle => true)
178
- response.stub(:header => { 'retry-after' => 10 })
179
- attrs = { 'collapse_key' => 'thing', 'delay_while_idle' => true, 'app_id' => app.id }
180
- store.should_receive(:create_gcm_notification).with(attrs, notification.data,
181
- ['id_0', 'id_2'], now + 10.seconds, notification.app)
182
- perform rescue Rapns::DeliveryError
183
- end
184
-
185
- it 'raises a DeliveryError' do
186
- expect { perform }.to raise_error(Rapns::DeliveryError)
187
- end
188
- end
189
-
190
- describe 'all deliveries failed with some as Unavailable or InternalServerError' do
191
- let(:body) {{
192
- 'failure' => 3,
193
- 'success' => 0,
194
- 'results' => [
195
- { 'error' => 'Unavailable' },
196
- { 'error' => 'InvalidDataKey' },
197
- { 'error' => 'Unavailable' }
198
- ]}}
199
- let(:error_description) { /#{Regexp.escape("Failed to deliver to recipients 0, 1, 2. Errors: Unavailable, InvalidDataKey, Unavailable. 0, 2 will be retried as notification")} [\d]+\./ }
200
- it_should_behave_like 'an notification with some delivery failures (200)'
201
- end
202
- end
203
-
204
- describe 'some deliveries failed with Unavailable or InternalServerError' do
205
- let(:body) {{
206
- 'failure' => 2,
207
- 'success' => 1,
208
- 'results' => [
209
- { 'error' => 'Unavailable' },
210
- { 'message_id' => '1:000' },
211
- { 'error' => 'InternalServerError' }
212
- ]}}
213
- let(:error_description) { /#{Regexp.escape("Failed to deliver to recipients 0, 2. Errors: Unavailable, InternalServerError. 0, 2 will be retried as notification")} [\d]+\./ }
214
- it_should_behave_like 'an notification with some delivery failures'
215
- end
216
-
217
- describe 'an 503 response' do
218
- before { response.stub(:code => 503) }
219
-
220
- it 'logs a warning that the notification will be retried.' do
221
- notification.retries = 1
222
- notification.deliver_after = now + 2
223
- logger.should_receive(:warn).with("GCM responded with an Service Unavailable Error. Notification #{notification.id} will be retried after 2012-10-14 00:00:02 (retry 1).")
224
- perform
225
- end
226
-
227
- it 'respects an integer Retry-After header' do
228
- response.stub(:header => { 'retry-after' => 10 })
229
- batch.should_receive(:mark_retryable).with(notification, now + 10.seconds)
230
- perform
231
- end
232
-
233
- it 'respects a HTTP-date Retry-After header' do
234
- response.stub(:header => { 'retry-after' => 'Wed, 03 Oct 2012 20:55:11 GMT' })
235
- batch.should_receive(:mark_retryable).with(notification, Time.parse('Wed, 03 Oct 2012 20:55:11 GMT'))
236
- perform
237
- end
238
-
239
- it 'defaults to exponential back-off if the Retry-After header is not present' do
240
- batch.should_receive(:mark_retryable).with(notification, now + 2 ** 1)
241
- perform
242
- end
243
- end
244
-
245
- describe 'an 500 response' do
246
- before do
247
- notification.update_attribute(:retries, 2)
248
- response.stub(:code => 500)
249
- end
250
-
251
- it 'logs a warning that the notification has been re-queued.' do
252
- notification.retries = 3
253
- notification.deliver_after = now + 2 ** 3
254
- Rapns.logger.should_receive(:warn).with("GCM responded with an Internal Error. Notification #{notification.id} will be retried after #{(now + 2 ** 3).strftime("%Y-%m-%d %H:%M:%S")} (retry 3).")
255
- perform
256
- end
257
-
258
- it 'retries the notification in accordance with the exponential back-off strategy.' do
259
- batch.should_receive(:mark_retryable).with(notification, now + 2 ** 3)
260
- perform
261
- end
262
- end
263
-
264
- describe 'an 401 response' do
265
- before { response.stub(:code => 401) }
266
-
267
- it 'raises an error' do
268
- expect { perform }.to raise_error(Rapns::DeliveryError)
269
- end
270
- end
271
-
272
- describe 'an 400 response' do
273
- before { response.stub(:code => 400) }
274
-
275
- it 'marks the notification as failed' do
276
- batch.should_receive(:mark_failed).with(notification, 400, 'GCM failed to parse the JSON request. Possibly an rapns bug, please open an issue.')
277
- perform rescue Rapns::DeliveryError
278
- end
279
- end
280
-
281
- describe 'an un-handled response' do
282
- before { response.stub(:code => 418) }
283
-
284
- it 'marks the notification as failed' do
285
- batch.should_receive(:mark_failed).with(notification, 418, "I'm a Teapot")
286
- perform rescue Rapns::DeliveryError
287
- end
288
- end
289
- end
@@ -1,68 +0,0 @@
1
- require File.expand_path("spec/unit_spec_helper")
2
-
3
- describe Rapns::Daemon::InterruptibleSleep do
4
-
5
- let(:rd) { double(:close => nil) }
6
- let(:wr) { double(:close => nil) }
7
-
8
- subject { Rapns::Daemon::InterruptibleSleep.new }
9
-
10
- it 'creates a new pipe' do
11
- IO.should_receive(:pipe)
12
- subject
13
- end
14
-
15
- it 'selects on the reader' do
16
- IO.stub(:pipe => [rd, wr])
17
- IO.should_receive(:select).with([rd], nil, nil, 1)
18
- subject.sleep(1)
19
- end
20
-
21
- it 'closes the writer' do
22
- IO.stub(:pipe => [rd, wr])
23
- rd.should_receive(:close)
24
- wr.should_receive(:close)
25
- subject.close
26
- end
27
-
28
- it 'returns false when timeout occurs' do
29
- subject.sleep(0.01).should be_false
30
- end
31
-
32
- it 'returns true when sleep does not timeout' do
33
- subject.interrupt_sleep
34
- subject.sleep(0.01).should be_true
35
- end
36
-
37
- context 'with UDP socket connected' do
38
- before :each do
39
- @host, @port = subject.enable_wake_on_udp('127.0.0.1', 0)
40
- end
41
-
42
- it 'times out with no udp activity' do
43
- subject.sleep(0.01).should be_false
44
- end
45
-
46
- it 'wakes on UDPSocket' do
47
- waker = UDPSocket.new
48
- waker.connect(@host, @port)
49
- waker.write('x')
50
- subject.sleep(0.01).should be_true
51
- waker.close
52
- end
53
-
54
- it 'consumes all data on udp socket' do
55
- waker = UDPSocket.new
56
- # waker.connect(@host, @port)
57
- waker.send('x', 0, @host, @port)
58
- waker.send('x', 0, @host, @port)
59
- waker.send('x', 0, @host, @port)
60
- # true since there is data to be read => no timeout
61
- subject.sleep(0.01).should be_true
62
- # false since data is consumed => wait for full timeout
63
- subject.sleep(0.01).should be_false
64
- waker.close
65
- end
66
- end
67
-
68
- end
@@ -1,27 +0,0 @@
1
- require File.expand_path("spec/unit_spec_helper")
2
-
3
- describe Rapns::Daemon::Reflectable do
4
- class TestReflectable
5
- include Rapns::Daemon::Reflectable
6
- end
7
-
8
- let(:logger) { double(:error => nil) }
9
- let(:test_reflectable) { TestReflectable.new }
10
-
11
- before do
12
- Rapns.reflections.stub(:__dispatch)
13
- Rapns.stub(:logger => logger)
14
- end
15
-
16
- it 'dispatches the given reflection' do
17
- Rapns.reflections.should_receive(:__dispatch).with(:error)
18
- test_reflectable.reflect(:error)
19
- end
20
-
21
- it 'logs errors raise by the reflection' do
22
- error = StandardError.new
23
- Rapns.reflections.stub(:__dispatch).and_raise(error)
24
- Rapns.logger.should_receive(:error).with(error)
25
- test_reflectable.reflect(:error)
26
- end
27
- end
@@ -1,114 +0,0 @@
1
- require File.expand_path("spec/unit_spec_helper")
2
- require 'rapns/daemon/store/active_record/reconnectable'
3
-
4
- describe Rapns::Daemon::Store::ActiveRecord::Reconnectable do
5
- class TestDouble
6
- include Rapns::Daemon::Store::ActiveRecord::Reconnectable
7
-
8
- attr_reader :name
9
-
10
- def initialize(error, max_calls)
11
- @error = error
12
- @max_calls = max_calls
13
- @calls = 0
14
- end
15
-
16
- def perform
17
- with_database_reconnect_and_retry do
18
- @calls += 1
19
- raise @error if @calls <= @max_calls
20
- end
21
- end
22
- end
23
-
24
- let(:adapter_error_class) do
25
- case $adapter
26
- when 'postgresql'
27
- PGError
28
- when 'mysql'
29
- Mysql::Error
30
- when 'mysql2'
31
- Mysql2::Error
32
- when 'jdbcpostgresql'
33
- ActiveRecord::JDBCError
34
- when 'jdbcmysql'
35
- ActiveRecord::JDBCError
36
- when 'jdbch2'
37
- ActiveRecord::JDBCError
38
- when 'sqlite3'
39
- SQLite3::Exception
40
- else
41
- raise "Please update #{__FILE__} for adapter #{$adapter}"
42
- end
43
- end
44
- let(:error) { adapter_error_class.new("db down!") }
45
- let(:test_double) { TestDouble.new(error, 1) }
46
-
47
- before do
48
- @logger = double("Logger", :info => nil, :error => nil, :warn => nil)
49
- Rapns.stub(:logger).and_return(@logger)
50
-
51
- ActiveRecord::Base.stub(:clear_all_connections!)
52
- ActiveRecord::Base.stub(:establish_connection)
53
- test_double.stub(:sleep)
54
- end
55
-
56
- it "should log the error raised" do
57
- Rapns.logger.should_receive(:error).with(error)
58
- test_double.perform
59
- end
60
-
61
- it "should log that the database is being reconnected" do
62
- Rapns.logger.should_receive(:warn).with("Lost connection to database, reconnecting...")
63
- test_double.perform
64
- end
65
-
66
- it "should log the reconnection attempt" do
67
- Rapns.logger.should_receive(:warn).with("Attempt 1")
68
- test_double.perform
69
- end
70
-
71
- it "should clear all connections" do
72
- ActiveRecord::Base.should_receive(:clear_all_connections!)
73
- test_double.perform
74
- end
75
-
76
- it "should establish a new connection" do
77
- ActiveRecord::Base.should_receive(:establish_connection)
78
- test_double.perform
79
- end
80
-
81
- it "should test out the new connection by performing a count" do
82
- Rapns::Notification.should_receive(:count)
83
- test_double.perform
84
- end
85
-
86
- context "when the reconnection attempt is not successful" do
87
- before do
88
- class << Rapns::Notification
89
- def count
90
- @count_calls += 1
91
- return if @count_calls == 2
92
- raise @error
93
- end
94
- end
95
- Rapns::Notification.instance_variable_set("@count_calls", 0)
96
- Rapns::Notification.instance_variable_set("@error", error)
97
- end
98
-
99
- it "should log the 2nd attempt" do
100
- Rapns.logger.should_receive(:warn).with("Attempt 2")
101
- test_double.perform
102
- end
103
-
104
- it "should log errors raised when the reconnection is not successful without notifying airbrake" do
105
- Rapns.logger.should_receive(:error).with(error, :airbrake_notify => false)
106
- test_double.perform
107
- end
108
-
109
- it "should sleep to avoid thrashing when the database is down" do
110
- test_double.should_receive(:sleep).with(2)
111
- test_double.perform
112
- end
113
- end
114
- end