rapns 3.2.0 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/CHANGELOG.md +5 -0
  2. data/README.md +9 -18
  3. data/lib/generators/templates/rapns.rb +5 -0
  4. data/lib/rapns.rb +4 -0
  5. data/lib/rapns/apns_feedback.rb +1 -0
  6. data/lib/rapns/configuration.rb +4 -3
  7. data/lib/rapns/daemon.rb +20 -4
  8. data/lib/rapns/daemon/apns/feedback_receiver.rb +9 -11
  9. data/lib/rapns/daemon/delivery.rb +3 -20
  10. data/lib/rapns/daemon/delivery_queue.rb +2 -2
  11. data/lib/rapns/daemon/feeder.rb +5 -10
  12. data/lib/rapns/daemon/gcm/delivery.rb +19 -9
  13. data/lib/rapns/daemon/store/active_record.rb +74 -0
  14. data/lib/rapns/daemon/store/active_record/reconnectable.rb +61 -0
  15. data/lib/rapns/gcm/notification.rb +5 -4
  16. data/lib/rapns/gcm/registration_ids_count_validator.rb +1 -1
  17. data/lib/rapns/logger.rb +6 -2
  18. data/lib/rapns/push.rb +1 -0
  19. data/lib/rapns/reflection.rb +1 -1
  20. data/lib/rapns/version.rb +1 -1
  21. data/spec/unit/apns/notification_spec.rb +2 -0
  22. data/spec/unit/apns_feedback_spec.rb +5 -0
  23. data/spec/unit/configuration_spec.rb +1 -1
  24. data/spec/unit/daemon/apns/delivery_spec.rb +7 -64
  25. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +2 -2
  26. data/spec/unit/daemon/feeder_spec.rb +6 -58
  27. data/spec/unit/daemon/gcm/delivery_spec.rb +49 -57
  28. data/spec/unit/daemon/{database_reconnectable_spec.rb → store/active_record/reconnectable_spec.rb} +4 -3
  29. data/spec/unit/daemon/store/active_record_spec.rb +181 -0
  30. data/spec/unit/daemon_spec.rb +27 -7
  31. data/spec/unit/gcm/notification_spec.rb +2 -9
  32. data/spec/unit/push_spec.rb +5 -0
  33. data/spec/unit/reflection_spec.rb +0 -4
  34. data/spec/unit_spec_helper.rb +4 -1
  35. metadata +10 -7
  36. data/lib/rapns/daemon/database_reconnectable.rb +0 -57
@@ -19,10 +19,11 @@ module Rapns
19
19
  }
20
20
 
21
21
  if collapse_key
22
- json.merge!({
23
- 'collapse_key' => collapse_key,
24
- 'time_to_live' => expiry
25
- })
22
+ json['collapse_key'] = collapse_key
23
+ end
24
+
25
+ if expiry
26
+ json['time_to_live'] = expiry
26
27
  end
27
28
 
28
29
  json
@@ -5,7 +5,7 @@ module Rapns
5
5
 
6
6
  def validate(record)
7
7
  if record.registration_ids && record.registration_ids.size > LIMIT
8
- record.errors[:base] << "GCM notification num of registration_ids cannot be larger than #{LIMIT}."
8
+ record.errors[:base] << "GCM notification number of registration_ids cannot be larger than #{LIMIT}."
9
9
  end
10
10
  end
11
11
  end
@@ -6,8 +6,12 @@ module Rapns
6
6
  begin
7
7
  log = File.open(File.join(Rails.root, 'log', 'rapns.log'), 'a')
8
8
  log.sync = true
9
- @logger = ActiveSupport::BufferedLogger.new(log, Rails.logger.level)
10
- @logger.auto_flushing = Rails.logger.respond_to?(:auto_flushing) ? Rails.logger.auto_flushing : true
9
+ if defined?(ActiveSupport::BufferedLogger)
10
+ @logger = ActiveSupport::BufferedLogger.new(log, Rails.logger.level)
11
+ @logger.auto_flushing = Rails.logger.respond_to?(:auto_flushing) ? Rails.logger.auto_flushing : true
12
+ else
13
+ @logger = ActiveSupport::Logger.new(log, Rails.logger.level)
14
+ end
11
15
  rescue Errno::ENOENT, Errno::EPERM => e
12
16
  @logger = nil
13
17
  error(e)
@@ -8,6 +8,7 @@ module Rapns
8
8
  Rapns.config.update(config)
9
9
 
10
10
  Upgraded.check(:exit => false)
11
+ Rapns::Daemon.initialize_store
11
12
  Rapns::Daemon::AppRunner.sync
12
13
  Rapns::Daemon::Feeder.start
13
14
  Rapns::Daemon::AppRunner.wait
@@ -13,7 +13,7 @@ module Rapns
13
13
  REFLECTIONS = [
14
14
  :apns_feedback, :notification_enqueued, :notification_delivered,
15
15
  :notification_failed, :notification_will_retry, :apns_connection_lost,
16
- :error
16
+ :gcm_canonical_id, :error
17
17
  ]
18
18
 
19
19
  REFLECTIONS.each do |reflection|
@@ -1,3 +1,3 @@
1
1
  module Rapns
2
- VERSION = '3.2.0'
2
+ VERSION = '3.3.0'
3
3
  end
@@ -1,3 +1,5 @@
1
+ # encoding: US-ASCII
2
+
1
3
  require "unit_spec_helper"
2
4
  require 'unit/notification_shared.rb'
3
5
 
@@ -8,6 +8,11 @@ describe Rapns, 'apns_feedback' do
8
8
  Rapns::Daemon::Apns::FeedbackReceiver.stub(:new => receiver)
9
9
  end
10
10
 
11
+ it 'initializes the store' do
12
+ Rapns::Daemon.should_receive(:initialize_store)
13
+ Rapns.apns_feedback
14
+ end
15
+
11
16
  it 'checks feedback for each app' do
12
17
  Rapns::Daemon::Apns::FeedbackReceiver.should_receive(:new).with(app, 0).and_return(receiver)
13
18
  receiver.should_receive(:check_for_feedback)
@@ -40,7 +40,7 @@ describe Rapns::Configuration do
40
40
 
41
41
  it 'does not allow foreground to be set to false if the platform is JRuby' do
42
42
  config.foreground = true
43
- stub_const('Rapns::Configuration::JRUBY_VERSION', '1.7.1')
43
+ Rapns.stub(:jruby? => true)
44
44
  config.foreground = false
45
45
  config.foreground.should be_true
46
46
  end
@@ -7,6 +7,7 @@ describe Rapns::Daemon::Apns::Delivery do
7
7
  let(:config) { stub(:check_for_errors => true) }
8
8
  let(:connection) { stub(:select => false, :write => nil, :reconnect => nil, :close => nil, :connect => nil) }
9
9
  let(:delivery) { Rapns::Daemon::Apns::Delivery.new(app, connection, notification) }
10
+ let(:store) { stub(:mark_failed => nil, :mark_delivered => nil) }
10
11
 
11
12
  def perform
12
13
  begin
@@ -16,6 +17,7 @@ describe Rapns::Daemon::Apns::Delivery do
16
17
  end
17
18
 
18
19
  before do
20
+ Rapns::Daemon.stub(:store => store)
19
21
  Rapns.stub(:config => config, :logger => logger)
20
22
  end
21
23
 
@@ -32,7 +34,7 @@ describe Rapns::Daemon::Apns::Delivery do
32
34
  end
33
35
 
34
36
  it "marks the notification as delivered" do
35
- notification.should_receive(:delivered=).with(true)
37
+ store.should_receive(:mark_delivered).with(notification)
36
38
  perform
37
39
  end
38
40
 
@@ -41,23 +43,6 @@ describe Rapns::Daemon::Apns::Delivery do
41
43
  perform
42
44
  end
43
45
 
44
- it "sets the time the notification was delivered" do
45
- now = Time.now
46
- Time.stub(:now).and_return(now)
47
- notification.should_receive(:delivered_at=).with(now)
48
- perform
49
- end
50
-
51
- it "does not trigger validations when saving the notification" do
52
- notification.should_receive(:save!).with(:validate => false)
53
- perform
54
- end
55
-
56
- it "updates notification with the ability to reconnect the database" do
57
- delivery.should_receive(:with_database_reconnect_and_retry)
58
- perform
59
- end
60
-
61
46
  it 'does not check for errors if check_for_errors config option is false' do
62
47
  config.stub(:check_for_errors => false)
63
48
  delivery.should_not_receive(:check_for_error)
@@ -67,23 +52,8 @@ describe Rapns::Daemon::Apns::Delivery do
67
52
  describe "when delivery fails" do
68
53
  before { connection.stub(:select => true, :read => [8, 4, 69].pack("ccN")) }
69
54
 
70
- it "updates notification with the ability to reconnect the database" do
71
- delivery.should_receive(:with_database_reconnect_and_retry)
72
- perform
73
- end
74
-
75
- it "sets the notification as not delivered" do
76
- notification.should_receive(:delivered=).with(false)
77
- perform
78
- end
79
-
80
- it "sets the notification delivered_at timestamp to nil" do
81
- notification.should_receive(:delivered_at=).with(nil)
82
- perform
83
- end
84
-
85
- it "sets the notification as failed" do
86
- notification.should_receive(:failed=).with(true)
55
+ it "marks the notification as failed" do
56
+ store.should_receive(:mark_failed).with(notification, 4, "Missing payload")
87
57
  perform
88
58
  end
89
59
 
@@ -92,18 +62,6 @@ describe Rapns::Daemon::Apns::Delivery do
92
62
  perform
93
63
  end
94
64
 
95
- it "sets the notification failed_at timestamp" do
96
- now = Time.now
97
- Time.stub(:now).and_return(now)
98
- notification.should_receive(:failed_at=).with(now)
99
- perform
100
- end
101
-
102
- it "sets the notification error code" do
103
- notification.should_receive(:error_code=).with(4)
104
- perform
105
- end
106
-
107
65
  it "logs the delivery error" do
108
66
  # checking for the stubbed error doesn't work in jruby, but checking
109
67
  # for the exception by class does.
@@ -115,16 +73,6 @@ describe Rapns::Daemon::Apns::Delivery do
115
73
  expect { delivery.perform }.to raise_error(Rapns::DeliveryError)
116
74
  end
117
75
 
118
- it "sets the notification error description" do
119
- notification.should_receive(:error_description=).with("Missing payload")
120
- perform
121
- end
122
-
123
- it "skips validation when saving the notification" do
124
- notification.should_receive(:save!).with(:validate => false)
125
- perform
126
- end
127
-
128
76
  it "reads 6 bytes from the socket" do
129
77
  connection.should_receive(:read).with(6).and_return(nil)
130
78
  perform
@@ -155,13 +103,8 @@ describe Rapns::Daemon::Apns::Delivery do
155
103
  expect { delivery.perform }.to raise_error(Rapns::Apns::DisconnectionError)
156
104
  end
157
105
 
158
- it 'does not set the error code on the notification' do
159
- notification.should_receive(:error_code=).with(nil)
160
- perform
161
- end
162
-
163
- it 'sets the error description on the notification' do
164
- notification.should_receive(:error_description=).with("APNs disconnected without returning an error.")
106
+ it 'marks the notification as failed' do
107
+ store.should_receive(:mark_failed).with(notification, nil, "APNs disconnected without returning an error.")
165
108
  perform
166
109
  end
167
110
  end
@@ -16,8 +16,8 @@ describe Rapns::Daemon::Apns::FeedbackReceiver, 'check_for_feedback' do
16
16
  receiver.stub(:interruptible_sleep)
17
17
  Rapns.stub(:logger => logger)
18
18
  Rapns::Daemon::Apns::Connection.stub(:new => connection)
19
- Rapns::Apns::Feedback.stub(:create! => feedback)
20
19
  receiver.instance_variable_set("@stop", false)
20
+ Rapns::Daemon.stub(:store => stub(:create_apns_feedback => feedback))
21
21
  end
22
22
 
23
23
  def stub_connection_read_with_tuple
@@ -58,8 +58,8 @@ describe Rapns::Daemon::Apns::FeedbackReceiver, 'check_for_feedback' do
58
58
  end
59
59
 
60
60
  it 'creates the feedback' do
61
+ Rapns::Daemon.store.should_receive(:create_apns_feedback).with(Time.at(1323533325), '834f786655eb9f84614a05ad7d00af31e5cfe93ac3ea078f1da44d2a4eb0ce17', app)
61
62
  stub_connection_read_with_tuple
62
- Rapns::Apns::Feedback.should_receive(:create!).with(:failed_at => Time.at(1323533325), :device_token => '834f786655eb9f84614a05ad7d00af31e5cfe93ac3ea078f1da44d2a4eb0ce17', :app => app)
63
63
  receiver.check_for_feedback
64
64
  end
65
65
 
@@ -8,10 +8,10 @@ describe Rapns::Daemon::Feeder do
8
8
  let(:logger) { stub }
9
9
 
10
10
  before do
11
- Rapns.stub(:config => config)
11
+ Rapns.stub(:config => config,:logger => logger)
12
+ Rapns::Daemon.stub(:store => stub(:deliverable_notifications => [notification]))
12
13
  Rapns::Daemon::Feeder.stub(:stop? => true)
13
- Rapns::Daemon::AppRunner.stub(:idle => [stub(:app => app)])
14
- Rapns.stub(:logger => logger)
14
+ Rapns::Daemon::AppRunner.stub(:enqueue => nil, :idle => [stub(:app => app)])
15
15
  end
16
16
 
17
17
  def start
@@ -25,8 +25,8 @@ describe Rapns::Daemon::Feeder do
25
25
  start
26
26
  end
27
27
 
28
- it "checks for new notifications with the ability to reconnect the database" do
29
- Rapns::Daemon::Feeder.should_receive(:with_database_reconnect_and_retry)
28
+ it 'loads deliverable notifications' do
29
+ Rapns::Daemon.store.should_receive(:deliverable_notifications).with([app])
30
30
  start
31
31
  end
32
32
 
@@ -37,72 +37,20 @@ describe Rapns::Daemon::Feeder do
37
37
  start
38
38
  end
39
39
 
40
- it 'loads notifications in batches' do
41
- relation = stub.as_null_object
42
- relation.should_receive(:limit).with(5000)
43
- Rapns::Notification.stub(:ready_for_delivery => relation)
44
- start
45
- end
46
-
47
- it 'does not load notification in batches if in push mode' do
48
- config.stub(:push => true)
49
- relation = stub.as_null_object
50
- relation.should_not_receive(:limit)
51
- Rapns::Notification.stub(:ready_for_delivery => relation)
52
- start
53
- end
54
-
55
40
  it "enqueues the notification" do
56
- notification.update_attributes!(:delivered => false)
57
41
  Rapns::Daemon::AppRunner.should_receive(:enqueue).with(notification)
58
42
  start
59
43
  end
60
44
 
61
45
  it 'reflects the notification has been enqueued' do
62
- notification.update_attributes!(:delivered => false)
63
46
  Rapns::Daemon::AppRunner.stub(:enqueue)
64
47
  Rapns::Daemon::Feeder.should_receive(:reflect).with(:notification_enqueued, notification)
65
48
  start
66
49
  end
67
50
 
68
- it 'does not enqueue the notification if the app runner is still processing the previous batch' do
69
- Rapns::Daemon::AppRunner.should_not_receive(:enqueue)
70
- start
71
- end
72
-
73
- it "enqueues an undelivered notification without deliver_after set" do
74
- notification.update_attributes!(:delivered => false, :deliver_after => nil)
75
- Rapns::Daemon::AppRunner.should_receive(:enqueue).with(notification)
76
- start
77
- end
78
-
79
- it "enqueues a notification with a deliver_after time in the past" do
80
- notification.update_attributes!(:delivered => false, :deliver_after => 1.hour.ago)
81
- Rapns::Daemon::AppRunner.should_receive(:enqueue).with(notification)
82
- start
83
- end
84
-
85
- it "does not enqueue a notification with a deliver_after time in the future" do
86
- notification.update_attributes!(:delivered => false, :deliver_after => 1.hour.from_now)
87
- Rapns::Daemon::AppRunner.should_not_receive(:enqueue)
88
- start
89
- end
90
-
91
- it "does not enqueue a previously delivered notification" do
92
- notification.update_attributes!(:delivered => true, :delivered_at => Time.now)
93
- Rapns::Daemon::AppRunner.should_not_receive(:enqueue)
94
- start
95
- end
96
-
97
- it "does not enqueue a notification that has previously failed delivery" do
98
- notification.update_attributes!(:delivered => false, :failed => true)
99
- Rapns::Daemon::AppRunner.should_not_receive(:enqueue)
100
- start
101
- end
102
-
103
51
  it "logs errors" do
104
52
  e = StandardError.new("bork")
105
- Rapns::Notification.stub(:ready_for_delivery).and_raise(e)
53
+ Rapns::Daemon.store.stub(:deliverable_notifications).and_raise(e)
106
54
  Rapns.logger.should_receive(:error).with(e)
107
55
  start
108
56
  end
@@ -2,18 +2,21 @@ require 'unit_spec_helper'
2
2
 
3
3
  describe Rapns::Daemon::Gcm::Delivery do
4
4
  let(:app) { Rapns::Gcm::App.new(:name => 'MyApp', :auth_key => 'abc123') }
5
- let(:notification) { Rapns::Gcm::Notification.create!(:app => app, :registration_ids => ['xyz']) }
5
+ let(:notification) { Rapns::Gcm::Notification.create!(:app => app, :registration_ids => ['xyz'], :deliver_after => Time.now) }
6
6
  let(:logger) { stub(:error => nil, :info => nil, :warn => nil) }
7
7
  let(:response) { stub(:code => 200, :header => {}) }
8
8
  let(:http) { stub(:shutdown => nil, :request => response)}
9
9
  let(:now) { Time.parse('2012-10-14 00:00:00') }
10
10
  let(:delivery) { Rapns::Daemon::Gcm::Delivery.new(app, http, notification) }
11
+ let(:store) { stub(:mark_failed => nil, :mark_delivered => nil, :retry_after => nil, :create_gcm_notification => stub(:id => 2)) }
11
12
 
12
13
  def perform
13
14
  delivery.perform
14
15
  end
15
16
 
16
17
  before do
18
+ delivery.stub(:reflect => nil)
19
+ Rapns::Daemon.stub(:store => store)
17
20
  Time.stub(:now => now)
18
21
  Rapns.stub(:logger => logger)
19
22
  end
@@ -25,9 +28,8 @@ describe Rapns::Daemon::Gcm::Delivery do
25
28
 
26
29
  it 'marks the notification as delivered if delivered successfully to all devices' do
27
30
  response.stub(:body => JSON.dump({ 'failure' => 0 }))
28
- expect do
29
- perform
30
- end.to change(notification, :delivered).to(true)
31
+ store.should_receive(:mark_delivered).with(notification)
32
+ perform
31
33
  end
32
34
 
33
35
  it 'reflects the notification was delivered' do
@@ -51,11 +53,25 @@ describe Rapns::Daemon::Gcm::Delivery do
51
53
  { 'error' => 'NotRegistered' }
52
54
  ]}
53
55
  response.stub(:body => JSON.dump(body))
56
+ store.should_receive(:mark_failed).with(notification, nil, "Failed to deliver to all recipients. Errors: NotRegistered.")
54
57
  perform rescue Rapns::DeliveryError
55
- notification.reload
56
- notification.failed.should be_true
57
- notification.error_code = nil
58
- notification.error_description = "Weee"
58
+ end
59
+
60
+ it 'reflects on canonical IDs' do
61
+ body = {
62
+ 'failure' => 0,
63
+ 'success' => 3,
64
+ 'canonical_ids' => 1,
65
+ 'results' => [
66
+ { 'message_id' => '1:000' },
67
+ { 'message_id' => '1:000', 'registration_id' => 'canonical123' },
68
+ { 'message_id' => '1:000' },
69
+ ]}
70
+
71
+ response.stub(:body => JSON.dump(body))
72
+ notification.stub(:registration_ids => ['1', '2', '3'])
73
+ delivery.should_receive(:reflect).with(:gcm_canonical_id, '2', 'canonical123')
74
+ perform
59
75
  end
60
76
 
61
77
  describe 'all deliveries returned Unavailable or InternalServerError' do
@@ -71,28 +87,23 @@ describe Rapns::Daemon::Gcm::Delivery do
71
87
 
72
88
  it 'retries the notification respecting the Retry-After header' do
73
89
  response.stub(:header => { 'retry-after' => 10 })
90
+ store.should_receive(:retry_after).with(notification, now + 10.seconds)
74
91
  perform
75
- notification.reload
76
- notification.retries.should == 1
77
- notification.deliver_after.should == now + 10.seconds
78
92
  end
79
93
 
80
94
  it 'retries the notification using exponential back-off if the Retry-After header is not present' do
81
- notification.update_attribute(:retries, 8)
95
+ store.should_receive(:retry_after).with(notification, now + 2)
82
96
  perform
83
- notification.reload
84
- notification.retries.should == 9
85
- notification.deliver_after.should == now + 2 ** 9
86
97
  end
87
98
 
88
99
  it 'does not mark the notification as failed' do
89
- expect do
90
- perform
91
- notification.reload
92
- end.to_not change(notification, :failed).to(true)
100
+ store.should_not_receive(:mark_failed)
101
+ perform
93
102
  end
94
103
 
95
104
  it 'logs that the notification will be retried' do
105
+ notification.retries = 1
106
+ notification.deliver_after = now + 2
96
107
  Rapns.logger.should_receive(:warn).with("All recipients unavailable. Notification #{notification.id} will be retired after 2012-10-14 00:00:02 (retry 1).")
97
108
  perform
98
109
  end
@@ -104,12 +115,8 @@ describe Rapns::Daemon::Gcm::Delivery do
104
115
  before { response.stub(:body => JSON.dump(body)) }
105
116
 
106
117
  it 'marks the original notification as failed' do
118
+ store.should_receive(:mark_failed).with(notification, nil, error_description)
107
119
  perform rescue Rapns::DeliveryError
108
- notification.reload
109
- notification.failed.should be_true
110
- notification.failed_at = now
111
- notification.error_code.should be_nil
112
- notification.error_description.should == error_description
113
120
  end
114
121
 
115
122
  it 'reflects the notification delivery failed' do
@@ -119,17 +126,11 @@ describe Rapns::Daemon::Gcm::Delivery do
119
126
 
120
127
  it 'creates a new notification for the unavailable devices' do
121
128
  notification.update_attributes(:registration_ids => ['id_0', 'id_1', 'id_2'], :data => {'one' => 1}, :collapse_key => 'thing', :delay_while_idle => true)
122
- perform rescue Rapns::DeliveryError
123
- new_notification.registration_ids.should == ['id_0', 'id_2']
124
- new_notification.data.should == {'one' => 1}
125
- new_notification.collapse_key.should == 'thing'
126
- new_notification.delay_while_idle.should be_true
127
- end
128
-
129
- it 'sets the delivery time on the new notification to respect the Retry-After header' do
130
129
  response.stub(:header => { 'retry-after' => 10 })
130
+ attrs = { 'collapse_key' => 'thing', 'delay_while_idle' => true, 'app_id' => app.id }
131
+ store.should_receive(:create_gcm_notification).with(attrs, notification.data,
132
+ ['id_0', 'id_2'], now + 10.seconds, notification.app)
131
133
  perform rescue Rapns::DeliveryError
132
- new_notification.deliver_after.should == now + 10.seconds
133
134
  end
134
135
 
135
136
  it 'raises a DeliveryError' do
@@ -168,28 +169,27 @@ describe Rapns::Daemon::Gcm::Delivery do
168
169
  before { response.stub(:code => 503) }
169
170
 
170
171
  it 'logs a warning that the notification will be retried.' do
172
+ notification.retries = 1
173
+ notification.deliver_after = now + 2
171
174
  logger.should_receive(:warn).with("GCM responded with an Service Unavailable Error. Notification #{notification.id} will be retired after 2012-10-14 00:00:02 (retry 1).")
172
175
  perform
173
176
  end
174
177
 
175
178
  it 'respects an integer Retry-After header' do
176
179
  response.stub(:header => { 'retry-after' => 10 })
177
- expect do
178
- perform
179
- end.to change(notification, :deliver_after).to(now + 10)
180
+ store.should_receive(:retry_after).with(notification, now + 10.seconds)
181
+ perform
180
182
  end
181
183
 
182
184
  it 'respects a HTTP-date Retry-After header' do
183
185
  response.stub(:header => { 'retry-after' => 'Wed, 03 Oct 2012 20:55:11 GMT' })
184
- expect do
185
- perform
186
- end.to change(notification, :deliver_after).to(Time.parse('Wed, 03 Oct 2012 20:55:11 GMT'))
186
+ store.should_receive(:retry_after).with(notification, Time.parse('Wed, 03 Oct 2012 20:55:11 GMT'))
187
+ perform
187
188
  end
188
189
 
189
190
  it 'defaults to exponential back-off if the Retry-After header is not present' do
190
- expect do
191
- perform
192
- end.to change(notification, :deliver_after).to(now + 2 ** 1)
191
+ store.should_receive(:retry_after).with(notification, now + 2 ** 1)
192
+ perform
193
193
  end
194
194
 
195
195
  it 'reflects the notification will be retried' do
@@ -205,15 +205,15 @@ describe Rapns::Daemon::Gcm::Delivery do
205
205
  end
206
206
 
207
207
  it 'logs a warning that the notification has been re-queued.' do
208
+ notification.retries = 3
209
+ notification.deliver_after = now + 2 ** 3
208
210
  Rapns.logger.should_receive(:warn).with("GCM responded with an Internal Error. Notification #{notification.id} will be retired after #{(now + 2 ** 3).strftime("%Y-%m-%d %H:%M:%S")} (retry 3).")
209
211
  perform
210
212
  end
211
213
 
212
- it 'sets deliver_after on the notification in accordance with the exponential back-off strategy.' do
213
- expect do
214
- perform
215
- notification.reload
216
- end.to change(notification, :deliver_after).to(now + 2 ** 3)
214
+ it 'retries the notification in accordance with the exponential back-off strategy.' do
215
+ store.should_receive(:retry_after).with(notification, now + 2 ** 3)
216
+ perform
217
217
  end
218
218
 
219
219
  it 'reflects the notification will be retried' do
@@ -234,12 +234,8 @@ describe Rapns::Daemon::Gcm::Delivery do
234
234
  before { response.stub(:code => 400) }
235
235
 
236
236
  it 'marks the notification as failed' do
237
+ store.should_receive(:mark_failed).with(notification, 400, 'GCM failed to parse the JSON request. Possibly an rapns bug, please open an issue.')
237
238
  perform rescue Rapns::DeliveryError
238
- notification.reload
239
- notification.failed.should be_true
240
- notification.failed_at.should == now
241
- notification.error_code.should == 400
242
- notification.error_description.should == 'GCM failed to parse the JSON request. Possibly an rapns bug, please open an issue.'
243
239
  end
244
240
 
245
241
  it 'reflects the notification delivery failed' do
@@ -252,12 +248,8 @@ describe Rapns::Daemon::Gcm::Delivery do
252
248
  before { response.stub(:code => 418) }
253
249
 
254
250
  it 'marks the notification as failed' do
251
+ store.should_receive(:mark_failed).with(notification, 418, "I'm a Teapot")
255
252
  perform rescue Rapns::DeliveryError
256
- notification.reload
257
- notification.failed.should be_true
258
- notification.failed_at.should == now
259
- notification.error_code.should == 418
260
- notification.error_description.should == "I'm a Teapot"
261
253
  end
262
254
 
263
255
  it 'reflects the notification delivery failed' do