rpush 1.0.0 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (193) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +13 -0
  3. data/README.md +12 -14
  4. data/bin/rpush +11 -2
  5. data/lib/generators/rpush_generator.rb +2 -0
  6. data/lib/generators/templates/add_adm.rb +5 -5
  7. data/lib/generators/templates/add_alert_is_json_to_rapns_notifications.rb +1 -1
  8. data/lib/generators/templates/add_app_to_rapns.rb +2 -2
  9. data/lib/generators/templates/add_fail_after_to_rpush_notifications.rb +1 -1
  10. data/lib/generators/templates/add_gcm.rb +32 -32
  11. data/lib/generators/templates/add_rpush.rb +67 -67
  12. data/lib/generators/templates/add_wpns.rb +2 -2
  13. data/lib/generators/templates/create_rapns_apps.rb +5 -5
  14. data/lib/generators/templates/create_rapns_feedback.rb +2 -2
  15. data/lib/generators/templates/create_rapns_notifications.rb +15 -15
  16. data/lib/generators/templates/rpush.rb +10 -7
  17. data/lib/generators/templates/rpush_2_0_0_updates.rb +23 -0
  18. data/lib/rpush.rb +4 -28
  19. data/lib/rpush/client/active_model.rb +21 -0
  20. data/lib/rpush/client/active_model/adm/app.rb +23 -0
  21. data/lib/rpush/client/active_model/adm/data_validator.rb +14 -0
  22. data/lib/rpush/client/active_model/adm/notification.rb +28 -0
  23. data/lib/rpush/client/active_model/apns/app.rb +37 -0
  24. data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +16 -0
  25. data/lib/rpush/client/active_model/apns/device_token_format_validator.rb +14 -0
  26. data/lib/rpush/client/active_model/apns/notification.rb +90 -0
  27. data/lib/rpush/client/active_model/gcm/app.rb +19 -0
  28. data/lib/rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +14 -0
  29. data/lib/rpush/client/active_model/gcm/notification.rb +31 -0
  30. data/lib/rpush/client/active_model/notification.rb +26 -0
  31. data/lib/rpush/client/active_model/payload_data_size_validator.rb +13 -0
  32. data/lib/rpush/client/active_model/registration_ids_count_validator.rb +13 -0
  33. data/lib/rpush/client/active_model/wpns/app.rb +13 -0
  34. data/lib/rpush/client/active_model/wpns/notification.rb +17 -0
  35. data/lib/rpush/client/active_record.rb +19 -0
  36. data/lib/rpush/client/active_record/adm/app.rb +11 -0
  37. data/lib/rpush/client/active_record/adm/notification.rb +11 -0
  38. data/lib/rpush/client/active_record/apns/app.rb +11 -0
  39. data/lib/rpush/client/active_record/apns/feedback.rb +20 -0
  40. data/lib/rpush/client/active_record/apns/notification.rb +46 -0
  41. data/lib/rpush/client/active_record/app.rb +17 -0
  42. data/lib/rpush/client/active_record/gcm/app.rb +11 -0
  43. data/lib/rpush/client/active_record/gcm/notification.rb +11 -0
  44. data/lib/rpush/client/active_record/notification.rb +38 -0
  45. data/lib/rpush/client/active_record/wpns/app.rb +11 -0
  46. data/lib/rpush/client/active_record/wpns/notification.rb +11 -0
  47. data/lib/rpush/client/redis.rb +35 -0
  48. data/lib/rpush/client/redis/adm/app.rb +14 -0
  49. data/lib/rpush/client/redis/adm/notification.rb +11 -0
  50. data/lib/rpush/client/redis/apns/app.rb +11 -0
  51. data/lib/rpush/client/redis/apns/feedback.rb +20 -0
  52. data/lib/rpush/client/redis/apns/notification.rb +11 -0
  53. data/lib/rpush/client/redis/app.rb +22 -0
  54. data/lib/rpush/client/redis/gcm/app.rb +11 -0
  55. data/lib/rpush/client/redis/gcm/notification.rb +11 -0
  56. data/lib/rpush/client/redis/notification.rb +68 -0
  57. data/lib/rpush/client/redis/wpns/app.rb +11 -0
  58. data/lib/rpush/client/redis/wpns/notification.rb +11 -0
  59. data/lib/rpush/configuration.rb +27 -6
  60. data/lib/rpush/daemon.rb +36 -56
  61. data/lib/rpush/daemon/adm/delivery.rb +50 -52
  62. data/lib/rpush/daemon/apns.rb +6 -5
  63. data/lib/rpush/daemon/apns/delivery.rb +20 -44
  64. data/lib/rpush/daemon/apns/feedback_receiver.rb +11 -8
  65. data/lib/rpush/daemon/app_runner.rb +67 -60
  66. data/lib/rpush/daemon/batch.rb +54 -40
  67. data/lib/rpush/daemon/delivery.rb +13 -3
  68. data/lib/rpush/daemon/delivery_error.rb +10 -2
  69. data/lib/rpush/daemon/dispatcher/apns_tcp.rb +106 -0
  70. data/lib/rpush/daemon/dispatcher/http.rb +3 -3
  71. data/lib/rpush/daemon/dispatcher/tcp.rb +3 -3
  72. data/lib/rpush/daemon/dispatcher_loop.rb +15 -6
  73. data/lib/rpush/daemon/errors.rb +18 -0
  74. data/lib/rpush/daemon/feeder.rb +28 -39
  75. data/lib/rpush/daemon/gcm/delivery.rb +19 -20
  76. data/lib/rpush/daemon/interruptible_sleep.rb +26 -45
  77. data/lib/rpush/daemon/loggable.rb +2 -4
  78. data/lib/rpush/daemon/proc_title.rb +16 -0
  79. data/lib/rpush/daemon/queue_payload.rb +12 -0
  80. data/lib/rpush/daemon/reflectable.rb +3 -5
  81. data/lib/rpush/daemon/retry_header_parser.rb +6 -6
  82. data/lib/rpush/daemon/ring_buffer.rb +16 -0
  83. data/lib/rpush/daemon/service_config_methods.rb +23 -7
  84. data/lib/rpush/daemon/signal_handler.rb +51 -0
  85. data/lib/rpush/daemon/store/active_record.rb +71 -38
  86. data/lib/rpush/daemon/store/active_record/reconnectable.rb +15 -15
  87. data/lib/rpush/daemon/store/interface.rb +19 -0
  88. data/lib/rpush/daemon/store/redis.rb +149 -0
  89. data/lib/rpush/daemon/tcp_connection.rb +6 -11
  90. data/lib/rpush/daemon/wpns/delivery.rb +21 -30
  91. data/lib/rpush/deprecatable.rb +4 -3
  92. data/lib/rpush/deprecation.rb +7 -10
  93. data/lib/rpush/embed.rb +7 -2
  94. data/lib/rpush/logger.rb +11 -15
  95. data/lib/rpush/push.rb +0 -1
  96. data/lib/rpush/reflection.rb +6 -12
  97. data/lib/rpush/version.rb +1 -1
  98. data/lib/tasks/quality.rake +34 -0
  99. data/spec/.rubocop.yml +4 -0
  100. data/spec/functional/adm_spec.rb +3 -6
  101. data/spec/functional/apns_spec.rb +118 -24
  102. data/spec/functional/embed_spec.rb +22 -20
  103. data/spec/functional/gcm_spec.rb +4 -7
  104. data/spec/functional/new_app_spec.rb +61 -0
  105. data/spec/functional/retry_spec.rb +46 -0
  106. data/spec/functional/wpns_spec.rb +3 -6
  107. data/spec/functional_spec_helper.rb +26 -0
  108. data/spec/integration/rpush_spec.rb +13 -0
  109. data/spec/integration/support/gcm_success_response.json +1 -0
  110. data/spec/spec_helper.rb +60 -0
  111. data/spec/support/active_record_setup.rb +48 -0
  112. data/{config → spec/support/config}/database.yml +0 -0
  113. data/spec/support/install.sh +43 -7
  114. data/spec/support/simplecov_helper.rb +9 -5
  115. data/spec/support/simplecov_quality_formatter.rb +10 -6
  116. data/spec/unit/apns_feedback_spec.rb +3 -3
  117. data/spec/unit/{adm → client/active_record/adm}/app_spec.rb +3 -3
  118. data/spec/unit/{adm → client/active_record/adm}/notification_spec.rb +5 -7
  119. data/spec/unit/client/active_record/apns/app_spec.rb +29 -0
  120. data/spec/unit/client/active_record/apns/feedback_spec.rb +9 -0
  121. data/spec/unit/client/active_record/apns/notification_spec.rb +231 -0
  122. data/spec/unit/client/active_record/app_spec.rb +30 -0
  123. data/spec/unit/client/active_record/gcm/app_spec.rb +4 -0
  124. data/spec/unit/{gcm → client/active_record/gcm}/notification_spec.rb +5 -7
  125. data/spec/unit/client/active_record/notification_spec.rb +15 -0
  126. data/spec/unit/client/active_record/wpns/app_spec.rb +4 -0
  127. data/spec/unit/client/active_record/wpns/notification_spec.rb +21 -0
  128. data/spec/unit/configuration_spec.rb +12 -5
  129. data/spec/unit/daemon/adm/delivery_spec.rb +57 -54
  130. data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +3 -3
  131. data/spec/unit/daemon/apns/delivery_spec.rb +90 -83
  132. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +24 -17
  133. data/spec/unit/daemon/app_runner_spec.rb +66 -123
  134. data/spec/unit/daemon/batch_spec.rb +52 -115
  135. data/spec/unit/daemon/delivery_spec.rb +15 -1
  136. data/spec/unit/daemon/dispatcher/http_spec.rb +3 -2
  137. data/spec/unit/daemon/dispatcher/tcp_spec.rb +10 -9
  138. data/spec/unit/daemon/dispatcher_loop_spec.rb +7 -12
  139. data/spec/unit/daemon/feeder_spec.rb +40 -39
  140. data/spec/unit/daemon/gcm/delivery_spec.rb +108 -89
  141. data/spec/unit/daemon/reflectable_spec.rb +2 -2
  142. data/spec/unit/daemon/retryable_error_spec.rb +1 -1
  143. data/spec/unit/daemon/service_config_methods_spec.rb +6 -3
  144. data/spec/unit/daemon/signal_handler_spec.rb +72 -0
  145. data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +9 -9
  146. data/spec/unit/daemon/store/active_record_spec.rb +38 -47
  147. data/spec/unit/daemon/tcp_connection_spec.rb +22 -34
  148. data/spec/unit/daemon/too_many_requests_error_spec.rb +1 -1
  149. data/spec/unit/daemon/wpns/delivery_spec.rb +61 -50
  150. data/spec/unit/daemon_spec.rb +46 -81
  151. data/spec/unit/embed_spec.rb +4 -2
  152. data/spec/unit/logger_spec.rb +30 -40
  153. data/spec/unit/notification_shared.rb +9 -79
  154. data/spec/unit/push_spec.rb +3 -8
  155. data/spec/unit/reflection_spec.rb +25 -25
  156. data/spec/unit/rpush_spec.rb +1 -2
  157. data/spec/unit_spec_helper.rb +33 -88
  158. metadata +119 -67
  159. data/lib/rpush/TODO +0 -3
  160. data/lib/rpush/adm/app.rb +0 -15
  161. data/lib/rpush/adm/data_validator.rb +0 -11
  162. data/lib/rpush/adm/notification.rb +0 -29
  163. data/lib/rpush/apns/app.rb +0 -29
  164. data/lib/rpush/apns/binary_notification_validator.rb +0 -12
  165. data/lib/rpush/apns/device_token_format_validator.rb +0 -12
  166. data/lib/rpush/apns/feedback.rb +0 -16
  167. data/lib/rpush/apns/notification.rb +0 -84
  168. data/lib/rpush/app.rb +0 -18
  169. data/lib/rpush/daemon/apns/certificate_expired_error.rb +0 -20
  170. data/lib/rpush/daemon/apns/disconnection_error.rb +0 -20
  171. data/lib/rpush/gcm/app.rb +0 -11
  172. data/lib/rpush/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +0 -11
  173. data/lib/rpush/gcm/notification.rb +0 -30
  174. data/lib/rpush/notification.rb +0 -69
  175. data/lib/rpush/notifier.rb +0 -52
  176. data/lib/rpush/payload_data_size_validator.rb +0 -10
  177. data/lib/rpush/railtie.rb +0 -11
  178. data/lib/rpush/registration_ids_count_validator.rb +0 -10
  179. data/lib/rpush/wpns/app.rb +0 -9
  180. data/lib/rpush/wpns/notification.rb +0 -26
  181. data/lib/tasks/cane.rake +0 -18
  182. data/lib/tasks/rpush.rake +0 -16
  183. data/spec/unit/apns/app_spec.rb +0 -29
  184. data/spec/unit/apns/feedback_spec.rb +0 -9
  185. data/spec/unit/apns/notification_spec.rb +0 -208
  186. data/spec/unit/app_spec.rb +0 -30
  187. data/spec/unit/daemon/apns/disconnection_error_spec.rb +0 -18
  188. data/spec/unit/daemon/interruptible_sleep_spec.rb +0 -68
  189. data/spec/unit/gcm/app_spec.rb +0 -4
  190. data/spec/unit/notification_spec.rb +0 -15
  191. data/spec/unit/notifier_spec.rb +0 -49
  192. data/spec/unit/wpns/app_spec.rb +0 -4
  193. data/spec/unit/wpns/notification_spec.rb +0 -30
@@ -16,7 +16,6 @@ describe Rpush::Daemon::Delivery do
16
16
  before { Time.stub(now: now) }
17
17
 
18
18
  describe 'mark_retryable' do
19
-
20
19
  it 'does not retry a notification with an expired fail_after' do
21
20
  batch.should_receive(:mark_failed).with(notification, nil, "Notification failed to be delivered before 2014-10-13 23:00:00.")
22
21
  notification.fail_after = Time.now - 1.hour
@@ -35,4 +34,19 @@ describe Rpush::Daemon::Delivery do
35
34
  delivery.mark_retryable(notification, Time.now + 1.hour)
36
35
  end
37
36
  end
37
+
38
+ describe 'mark_batch_delivered' do
39
+ it 'marks all notifications as delivered' do
40
+ batch.should_receive(:mark_all_delivered)
41
+ delivery.mark_batch_delivered
42
+ end
43
+ end
44
+
45
+ describe 'mark_batch_failed' do
46
+ it 'marks all notifications as delivered' do
47
+ error = Rpush::DeliveryError.new(1, 42, 'an error')
48
+ batch.should_receive(:mark_all_failed).with(1, 'Unable to deliver notification 42, received error 1 (an error)')
49
+ delivery.mark_batch_failed(error)
50
+ end
51
+ end
38
52
  end
@@ -6,9 +6,10 @@ describe Rpush::Daemon::Dispatcher::Http do
6
6
  let(:notification) { double }
7
7
  let(:batch) { double }
8
8
  let(:http) { double }
9
+ let(:queue_payload) { Rpush::Daemon::QueuePayload.new(batch, notification) }
9
10
  let(:dispatcher) { Rpush::Daemon::Dispatcher::Http.new(app, delivery_class) }
10
11
 
11
- before { Net::HTTP::Persistent.stub(:new => http) }
12
+ before { Net::HTTP::Persistent.stub(new: http) }
12
13
 
13
14
  it 'constructs a new persistent connection' do
14
15
  Net::HTTP::Persistent.should_receive(:new)
@@ -20,7 +21,7 @@ describe Rpush::Daemon::Dispatcher::Http do
20
21
  delivery = double
21
22
  delivery_class.should_receive(:new).with(app, http, notification, batch).and_return(delivery)
22
23
  delivery.should_receive(:perform)
23
- dispatcher.dispatch(notification, batch)
24
+ dispatcher.dispatch(queue_payload)
24
25
  end
25
26
  end
26
27
 
@@ -2,35 +2,36 @@ require 'unit_spec_helper'
2
2
 
3
3
  describe Rpush::Daemon::Dispatcher::Tcp do
4
4
  let(:app) { double }
5
- let(:delivery) { double(:perform => nil) }
6
- let(:delivery_class) { double(:new => delivery) }
5
+ let(:delivery) { double(perform: nil) }
6
+ let(:delivery_class) { double(new: delivery) }
7
7
  let(:notification) { double }
8
8
  let(:batch) { double }
9
- let(:connection) { double(Rpush::Daemon::TcpConnection, :connect => nil) }
9
+ let(:connection) { double(Rpush::Daemon::TcpConnection, connect: nil) }
10
10
  let(:host) { 'localhost' }
11
11
  let(:port) { 1234 }
12
- let(:host_proc) { Proc.new { |app| [host, port] } }
13
- let(:dispatcher) { Rpush::Daemon::Dispatcher::Tcp.new(app, delivery_class, :host => host_proc) }
12
+ let(:host_proc) { proc { [host, port] } }
13
+ let(:queue_payload) { Rpush::Daemon::QueuePayload.new(batch, notification) }
14
+ let(:dispatcher) { Rpush::Daemon::Dispatcher::Tcp.new(app, delivery_class, host: host_proc) }
14
15
 
15
- before { Rpush::Daemon::TcpConnection.stub(:new => connection) }
16
+ before { Rpush::Daemon::TcpConnection.stub(new: connection) }
16
17
 
17
18
  describe 'dispatch' do
18
19
  it 'lazily connects the socket' do
19
20
  Rpush::Daemon::TcpConnection.should_receive(:new).with(app, host, port).and_return(connection)
20
21
  connection.should_receive(:connect)
21
- dispatcher.dispatch(notification, batch)
22
+ dispatcher.dispatch(queue_payload)
22
23
  end
23
24
 
24
25
  it 'delivers the notification' do
25
26
  delivery_class.should_receive(:new).with(app, connection, notification, batch).and_return(delivery)
26
27
  delivery.should_receive(:perform)
27
- dispatcher.dispatch(notification, batch)
28
+ dispatcher.dispatch(queue_payload)
28
29
  end
29
30
  end
30
31
 
31
32
  describe 'cleanup' do
32
33
  it 'closes the connection' do
33
- dispatcher.dispatch(notification, batch) # lazily initialize connection
34
+ dispatcher.dispatch(queue_payload) # lazily initialize connection
34
35
  connection.should_receive(:close)
35
36
  dispatcher.cleanup
36
37
  end
@@ -9,20 +9,20 @@ describe Rpush::Daemon::DispatcherLoop do
9
9
  end
10
10
 
11
11
  let(:notification) { double }
12
- let(:batch) { double(:notification_dispatched => nil) }
12
+ let(:batch) { double(notification_processed: nil) }
13
13
  let(:queue) { Queue.new }
14
- let(:dispatcher) { double(:dispatch => nil, :cleanup => nil) }
14
+ let(:dispatcher) { double(dispatch: nil, cleanup: nil) }
15
15
  let(:dispatcher_loop) { Rpush::Daemon::DispatcherLoop.new(queue, dispatcher) }
16
- let(:store) { double(Rpush::Daemon::Store::ActiveRecord, release_connection: nil)}
16
+ let(:store) { double(Rpush::Daemon::Store::ActiveRecord, release_connection: nil) }
17
17
 
18
18
  before do
19
- Rpush::Daemon.stub(:store => store)
19
+ Rpush::Daemon.stub(store: store)
20
20
  queue.push([notification, batch])
21
21
  end
22
22
 
23
23
  it 'logs errors' do
24
24
  logger = double
25
- Rpush.stub(:logger => logger)
25
+ Rpush.stub(logger: logger)
26
26
  error = StandardError.new
27
27
  dispatcher.stub(:dispatch).and_raise(error)
28
28
  Rpush.logger.should_receive(:error).with(error)
@@ -30,19 +30,14 @@ describe Rpush::Daemon::DispatcherLoop do
30
30
  end
31
31
 
32
32
  it 'reflects an exception' do
33
- Rpush.stub(:logger => double(:error => nil))
33
+ Rpush.stub(logger: double(error: nil))
34
34
  error = StandardError.new
35
35
  dispatcher.stub(:dispatch).and_raise(error)
36
36
  dispatcher_loop.should_receive(:reflect).with(:error, error)
37
37
  run_dispatcher_loop
38
38
  end
39
39
 
40
- it 'instructs the batch that the notification has been processed' do
41
- batch.should_receive(:notification_dispatched)
42
- run_dispatcher_loop
43
- end
44
-
45
- it "instructs the queue to wakeup the thread when told to stop" do
40
+ it 'instructs the queue to wakeup the thread when told to stop' do
46
41
  queue.should_receive(:push).with(Rpush::Daemon::DispatcherLoop::WAKEUP).and_call_original
47
42
  run_dispatcher_loop
48
43
  end
@@ -1,25 +1,25 @@
1
1
  require "unit_spec_helper"
2
2
 
3
3
  describe Rpush::Daemon::Feeder do
4
- let(:config) { double(:batch_size => 5000,
5
- :push_poll => 0,
6
- :embedded => false,
7
- :push => false,
8
- :wakeup => nil) }
9
- let!(:app) { Rpush::Apns::App.create!(:name => 'my_app', :environment => 'development', :certificate => TEST_CERT) }
10
- let(:notification) { Rpush::Apns::Notification.create!(:device_token => "a" * 64, :app => app) }
4
+ let!(:app) { Rpush::Apns::App.create!(name: 'my_app', environment: 'development', certificate: TEST_CERT) }
5
+ let(:notification) { Rpush::Apns::Notification.create!(device_token: "a" * 64, app: app) }
11
6
  let(:logger) { double }
12
- let(:interruptible_sleep) { double(:sleep => nil, :interrupt_sleep => nil) }
13
- let(:store) { double(Rpush::Daemon::Store::ActiveRecord,
14
- deliverable_notifications: [notification], release_connection: nil) }
7
+ let(:interruptible_sleeper) { double(sleep: nil, stop: nil, start: nil) }
8
+ let(:store) do double(Rpush::Daemon::Store::ActiveRecord,
9
+ deliverable_notifications: [notification], release_connection: nil)
10
+ end
15
11
 
16
12
  before do
17
- Rpush.stub(:config => config,:logger => logger)
18
- Rpush::Daemon.stub(:store => store)
19
- Rpush::Daemon::Feeder.stub(:stop? => true)
20
- Rpush::Daemon::AppRunner.stub(:enqueue => nil, :idle => [double(:app => app)])
21
- Rpush::Daemon::InterruptibleSleep.stub(:new => interruptible_sleep)
22
- Rpush::Daemon::Feeder.instance_variable_set('@interruptible_sleeper', nil)
13
+ Rpush.configure do |config|
14
+ config.batch_size = 5000
15
+ config.push_poll = 0
16
+ config.push = false
17
+ end
18
+
19
+ Rpush.stub(logger: logger)
20
+ Rpush::Daemon.stub(store: store)
21
+ Rpush::Daemon::Feeder.stub(should_stop: true, interruptible_sleeper: interruptible_sleeper)
22
+ Rpush::Daemon::AppRunner.stub(enqueue: nil, num_queued: 0)
23
23
  end
24
24
 
25
25
  def start_and_stop
@@ -27,26 +27,26 @@ describe Rpush::Daemon::Feeder do
27
27
  Rpush::Daemon::Feeder.stop
28
28
  end
29
29
 
30
- it 'starts the loop in a new thread if embedded' do
31
- config.stub(:embedded => true)
32
- Thread.should_receive(:new).and_yield
33
- Rpush::Daemon::Feeder.should_receive(:feed_forever)
30
+ it 'loads deliverable notifications' do
31
+ Rpush::Daemon.store.should_receive(:deliverable_notifications).with(Rpush.config.batch_size)
34
32
  start_and_stop
35
33
  end
36
34
 
37
- it 'loads deliverable notifications' do
38
- Rpush::Daemon.store.should_receive(:deliverable_notifications).with([app])
35
+ it 'does not load more notifications if the total queue size is equal to the batch size' do
36
+ Rpush::Daemon::AppRunner.stub(num_queued: Rpush.config.batch_size)
37
+ Rpush::Daemon.store.should_not_receive(:deliverable_notifications)
39
38
  start_and_stop
40
39
  end
41
40
 
42
- it 'does not attempt to load deliverable notifications if there are no idle runners' do
43
- Rpush::Daemon::AppRunner.stub(:idle => [])
44
- Rpush::Daemon.store.should_not_receive(:deliverable_notifications)
41
+ it 'limits the batch size if some runners are still processing notifications' do
42
+ Rpush.config.stub(batch_size: 10)
43
+ Rpush::Daemon::AppRunner.stub(num_queued: 6)
44
+ Rpush::Daemon.store.should_receive(:deliverable_notifications).with(4)
45
45
  start_and_stop
46
46
  end
47
47
 
48
48
  it 'enqueues notifications without looping if in push mode' do
49
- config.stub(:push => true)
49
+ Rpush.config.push = true
50
50
  Rpush::Daemon::Feeder.should_not_receive(:feed_forever)
51
51
  Rpush::Daemon::Feeder.should_receive(:enqueue_notifications)
52
52
  start_and_stop
@@ -65,34 +65,35 @@ describe Rpush::Daemon::Feeder do
65
65
  end
66
66
 
67
67
  describe 'stop' do
68
- it 'interrupts sleep when stopped' do
69
- Rpush::Daemon::Feeder.should_receive(:interrupt_sleep)
68
+ it 'interrupts sleep' do
69
+ interruptible_sleeper.should_receive(:stop)
70
70
  start_and_stop
71
71
  end
72
72
 
73
- it 'releases the store connection when stopped' do
73
+ it 'releases the store connection' do
74
74
  Rpush::Daemon.store.should_receive(:release_connection)
75
75
  start_and_stop
76
76
  end
77
77
  end
78
78
 
79
- it "enqueues notifications when started" do
79
+ it 'enqueues notifications when started' do
80
80
  Rpush::Daemon::Feeder.should_receive(:enqueue_notifications).at_least(:once)
81
81
  Rpush::Daemon::Feeder.stub(:loop).and_yield
82
82
  start_and_stop
83
83
  end
84
84
 
85
- it "sleeps for the given period" do
86
- config.stub(:push_poll => 2)
87
- interruptible_sleep.should_receive(:sleep).with(2)
85
+ it 'sleeps' do
86
+ interruptible_sleeper.should_receive(:sleep)
88
87
  start_and_stop
89
88
  end
90
89
 
91
- it "creates the wakeup socket" do
92
- bind = '127.0.0.1'
93
- port = 12345
94
- config.stub(:wakeup => { :bind => bind, :port => port})
95
- interruptible_sleep.should_receive(:enable_wake_on_udp).with(bind, port)
96
- start_and_stop
90
+ describe 'wakeup' do
91
+ it 'interrupts sleep' do
92
+ interruptible_sleeper.should_receive(:wakeup)
93
+ Rpush::Daemon::Feeder.start
94
+ Rpush::Daemon::Feeder.wakeup
95
+ end
96
+
97
+ after { Rpush::Daemon::Feeder.stop }
97
98
  end
98
99
  end
@@ -1,44 +1,51 @@
1
1
  require 'unit_spec_helper'
2
2
 
3
3
  describe Rpush::Daemon::Gcm::Delivery do
4
- let(:app) { Rpush::Gcm::App.new(:name => 'MyApp', :auth_key => 'abc123') }
5
- let(:notification) { Rpush::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)}
4
+ let(:app) { Rpush::Gcm::App.create!(name: 'MyApp', auth_key: 'abc123') }
5
+ let(:notification) { Rpush::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
9
  let(:now) { Time.parse('2012-10-14 00:00:00') }
10
- let(:batch) { double(:mark_failed => nil, :mark_delivered => nil, :mark_retryable => nil) }
10
+ let(:batch) { double(mark_failed: nil, mark_delivered: nil, mark_retryable: nil, notification_processed: nil) }
11
11
  let(:delivery) { Rpush::Daemon::Gcm::Delivery.new(app, http, notification, batch) }
12
- let(:store) { double(:create_gcm_notification => double(:id => 2)) }
12
+ let(:store) { double(create_gcm_notification: double(id: 2)) }
13
13
 
14
14
  def perform
15
15
  delivery.perform
16
16
  end
17
17
 
18
+ def perform_with_rescue
19
+ expect { perform }.to raise_error
20
+ end
21
+
18
22
  before do
19
- delivery.stub(:reflect => nil)
20
- Rpush::Daemon.stub(:store => store)
21
- Time.stub(:now => now)
22
- Rpush.stub(:logger => logger)
23
+ delivery.stub(reflect: nil)
24
+ Rpush::Daemon.stub(store: store)
25
+ Time.stub(now: now)
26
+ Rpush.stub(logger: logger)
23
27
  end
24
28
 
25
29
  shared_examples_for 'a notification with some delivery failures' do
26
30
  let(:new_notification) { Rpush::Gcm::Notification.where('id != ?', notification.id).first }
27
31
 
28
- before { response.stub(:body => JSON.dump(body)) }
32
+ before { response.stub(body: JSON.dump(body)) }
29
33
 
30
34
  it 'marks the original notification as failed' do
31
- delivery.should_receive(:mark_failed).with(nil, error_description)
32
- perform rescue Rpush::DeliveryError
35
+ # error = Rpush::DeliveryError.new(nil, notification.id, error_description)
36
+ delivery.should_receive(:mark_failed) do |error|
37
+ error.to_s.should =~ error_description
38
+ end
39
+ perform_with_rescue
33
40
  end
34
41
 
35
42
  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 })
43
+ notification.update_attributes(registration_ids: %w(id_0 id_1 id_2), data: { 'one' => 1 }, collapse_key: 'thing', delay_while_idle: true)
44
+ response.stub(header: { 'retry-after' => 10 })
38
45
  attrs = { 'collapse_key' => 'thing', 'delay_while_idle' => true, 'app_id' => app.id }
39
46
  store.should_receive(:create_gcm_notification).with(attrs, notification.data,
40
- ['id_0', 'id_2'], now + 10.seconds, notification.app)
41
- perform rescue Rpush::DeliveryError
47
+ %w(id_0 id_2), now + 10.seconds, notification.app)
48
+ perform_with_rescue
42
49
  end
43
50
 
44
51
  it 'raises a DeliveryError' do
@@ -48,7 +55,7 @@ describe Rpush::Daemon::Gcm::Delivery do
48
55
 
49
56
  describe 'a 200 response' do
50
57
  before do
51
- response.stub(:code => 200)
58
+ response.stub(code: 200)
52
59
  end
53
60
 
54
61
  it 'reflects on any IDs which successfully received the notification' do
@@ -61,11 +68,11 @@ describe Rpush::Daemon::Gcm::Delivery do
61
68
  ]
62
69
  }
63
70
 
64
- response.stub(:body => JSON.dump(body))
65
- notification.stub(:registration_ids => ['1', '2'])
71
+ response.stub(body: JSON.dump(body))
72
+ notification.stub(registration_ids: %w(1 2))
66
73
  delivery.should_receive(:reflect).with(:gcm_delivered_to_recipient, notification, '1')
67
74
  delivery.should_not_receive(:reflect).with(:gcm_delivered_to_recipient, notification, '2')
68
- perform rescue Rpush::DeliveryError
75
+ perform_with_rescue
69
76
  end
70
77
 
71
78
  it 'reflects on any IDs which failed to receive the notification' do
@@ -78,11 +85,11 @@ describe Rpush::Daemon::Gcm::Delivery do
78
85
  ]
79
86
  }
80
87
 
81
- response.stub(:body => JSON.dump(body))
82
- notification.stub(:registration_ids => ['1', '2'])
88
+ response.stub(body: JSON.dump(body))
89
+ notification.stub(registration_ids: %w(1 2))
83
90
  delivery.should_receive(:reflect).with(:gcm_failed_to_recipient, notification, 'Err', '1')
84
91
  delivery.should_not_receive(:reflect).with(:gcm_failed_to_recipient, notification, anything, '2')
85
- perform rescue Rpush::DeliveryError
92
+ perform_with_rescue
86
93
  end
87
94
 
88
95
  it 'reflects on canonical IDs' do
@@ -93,40 +100,43 @@ describe Rpush::Daemon::Gcm::Delivery do
93
100
  'results' => [
94
101
  { 'message_id' => '1:000' },
95
102
  { 'message_id' => '1:000', 'registration_id' => 'canonical123' },
96
- { 'message_id' => '1:000' },
97
- ]}
103
+ { 'message_id' => '1:000' }
104
+ ] }
98
105
 
99
- response.stub(:body => JSON.dump(body))
100
- notification.stub(:registration_ids => ['1', '2', '3'])
106
+ response.stub(body: JSON.dump(body))
107
+ notification.stub(registration_ids: %w(1 2 3))
101
108
  delivery.should_receive(:reflect).with(:gcm_canonical_id, '2', 'canonical123')
102
109
  perform
103
110
  end
104
111
 
105
112
  it 'reflects on invalid IDs' do
106
113
  body = {
107
- 'failure' => 1,
108
- 'success' => 2,
109
- 'canonical_ids' => 0,
110
- 'results' => [
111
- { 'message_id' => '1:000' },
112
- { 'error' => 'NotRegistered' },
113
- { 'message_id' => '1:000' },
114
- ]}
114
+ 'failure' => 1,
115
+ 'success' => 2,
116
+ 'canonical_ids' => 0,
117
+ 'results' => [
118
+ { 'message_id' => '1:000' },
119
+ { 'error' => 'NotRegistered' },
120
+ { 'message_id' => '1:000' }
121
+ ]
122
+ }
115
123
 
116
- response.stub(:body => JSON.dump(body))
117
- notification.stub(:registration_ids => ['1', '2', '3'])
124
+ response.stub(body: JSON.dump(body))
125
+ notification.stub(registration_ids: %w(1 2 3))
118
126
  delivery.should_receive(:reflect).with(:gcm_invalid_registration_id, app, 'NotRegistered', '2')
119
- perform rescue Rpush::DeliveryError
127
+ perform_with_rescue
120
128
  end
121
129
 
122
130
  describe 'when delivered successfully to all devices' do
123
- let(:body) {{
124
- 'failure' => 0,
125
- 'success' => 1,
126
- 'results' => [{ 'message_id' => '1:000'}]
127
- }}
131
+ let(:body) do
132
+ {
133
+ 'failure' => 0,
134
+ 'success' => 1,
135
+ 'results' => [{ 'message_id' => '1:000' }]
136
+ }
137
+ end
128
138
 
129
- before { response.stub(:body => JSON.dump(body)) }
139
+ before { response.stub(body: JSON.dump(body)) }
130
140
 
131
141
  it 'marks the notification as delivered' do
132
142
  delivery.should_receive(:mark_delivered)
@@ -141,20 +151,21 @@ describe Rpush::Daemon::Gcm::Delivery do
141
151
 
142
152
  it 'marks a notification as failed if any ids are invalid' do
143
153
  body = {
144
- 'failure' => 1,
145
- 'success' => 2,
146
- 'canonical_ids' => 0,
147
- 'results' => [
148
- { 'message_id' => '1:000' },
149
- { 'error' => 'NotRegistered' },
150
- { 'message_id' => '1:000' },
151
- ]}
154
+ 'failure' => 1,
155
+ 'success' => 2,
156
+ 'canonical_ids' => 0,
157
+ 'results' => [
158
+ { 'message_id' => '1:000' },
159
+ { 'error' => 'NotRegistered' },
160
+ { 'message_id' => '1:000' }
161
+ ]
162
+ }
152
163
 
153
- response.stub(:body => JSON.dump(body))
164
+ response.stub(body: JSON.dump(body))
154
165
  delivery.should_receive(:mark_failed)
155
166
  delivery.should_not_receive(:mark_retryable)
156
167
  store.should_not_receive(:create_gcm_notification)
157
- perform rescue Rpush::DeliveryError
168
+ perform_with_rescue
158
169
  end
159
170
 
160
171
  it 'marks a notification as failed if any deliveries failed that cannot be retried' do
@@ -164,28 +175,32 @@ describe Rpush::Daemon::Gcm::Delivery do
164
175
  'results' => [
165
176
  { 'message_id' => '1:000' },
166
177
  { 'error' => 'InvalidDataKey' }
167
- ]}
168
- response.stub(:body => JSON.dump(body))
169
- delivery.should_receive(:mark_failed).with(nil, "Failed to deliver to all recipients. Errors: InvalidDataKey.")
170
- perform rescue Rpush::DeliveryError
178
+ ] }
179
+ response.stub(body: JSON.dump(body))
180
+ error = Rpush::DeliveryError.new(nil, notification.id, 'Failed to deliver to all recipients. Errors: InvalidDataKey.')
181
+ delivery.should_receive(:mark_failed).with(error)
182
+ perform_with_rescue
171
183
  end
172
184
 
173
185
  describe 'all deliveries failed with Unavailable or InternalServerError' do
174
- let(:body) {{
175
- 'failure' => 2,
176
- 'success' => 0,
177
- 'results' => [
178
- { 'error' => 'Unavailable' },
179
- { 'error' => 'Unavailable' }
180
- ]}}
186
+ let(:body) do
187
+ {
188
+ 'failure' => 2,
189
+ 'success' => 0,
190
+ 'results' => [
191
+ { 'error' => 'Unavailable' },
192
+ { 'error' => 'Unavailable' }
193
+ ]
194
+ }
195
+ end
181
196
 
182
197
  before do
183
- response.stub(:body => JSON.dump(body))
184
- notification.stub(:registration_ids => ['1', '2'])
198
+ response.stub(body: JSON.dump(body))
199
+ notification.stub(registration_ids: %w(1 2))
185
200
  end
186
201
 
187
202
  it 'retries the notification respecting the Retry-After header' do
188
- response.stub(:header => { 'retry-after' => 10 })
203
+ response.stub(header: { 'retry-after' => 10 })
189
204
  delivery.should_receive(:mark_retryable).with(notification, now + 10.seconds)
190
205
  perform
191
206
  end
@@ -209,34 +224,36 @@ describe Rpush::Daemon::Gcm::Delivery do
209
224
  end
210
225
 
211
226
  describe 'all deliveries failed with some as Unavailable or InternalServerError' do
212
- let(:body) {{
227
+ let(:body) do{
213
228
  'failure' => 3,
214
229
  'success' => 0,
215
230
  'results' => [
216
231
  { 'error' => 'Unavailable' },
217
232
  { 'error' => 'InvalidDataKey' },
218
233
  { 'error' => 'Unavailable' }
219
- ]}}
234
+ ] }
235
+ end
220
236
  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]+\./ }
221
237
  it_should_behave_like 'a notification with some delivery failures'
222
238
  end
223
239
 
224
240
  describe 'some deliveries failed with Unavailable or InternalServerError' do
225
- let(:body) {{
241
+ let(:body) do{
226
242
  'failure' => 2,
227
243
  'success' => 1,
228
244
  'results' => [
229
245
  { 'error' => 'Unavailable' },
230
246
  { 'message_id' => '1:000' },
231
247
  { 'error' => 'InternalServerError' }
232
- ]}}
248
+ ] }
249
+ end
233
250
  let(:error_description) { /#{Regexp.escape("Failed to deliver to recipients 0, 2. Errors: Unavailable, InternalServerError. 0, 2 will be retried as notification")} [\d]+\./ }
234
251
  it_should_behave_like 'a notification with some delivery failures'
235
252
  end
236
253
  end
237
254
 
238
255
  describe 'a 503 response' do
239
- before { response.stub(:code => 503) }
256
+ before { response.stub(code: 503) }
240
257
 
241
258
  it 'logs a warning that the notification will be retried.' do
242
259
  notification.retries = 1
@@ -246,19 +263,19 @@ describe Rpush::Daemon::Gcm::Delivery do
246
263
  end
247
264
 
248
265
  it 'respects an integer Retry-After header' do
249
- response.stub(:header => { 'retry-after' => 10 })
266
+ response.stub(header: { 'retry-after' => 10 })
250
267
  delivery.should_receive(:mark_retryable).with(notification, now + 10.seconds)
251
268
  perform
252
269
  end
253
270
 
254
271
  it 'respects a HTTP-date Retry-After header' do
255
- response.stub(:header => { 'retry-after' => 'Wed, 03 Oct 2012 20:55:11 GMT' })
272
+ response.stub(header: { 'retry-after' => 'Wed, 03 Oct 2012 20:55:11 GMT' })
256
273
  delivery.should_receive(:mark_retryable).with(notification, Time.parse('Wed, 03 Oct 2012 20:55:11 GMT'))
257
274
  perform
258
275
  end
259
276
 
260
277
  it 'defaults to exponential back-off if the Retry-After header is not present' do
261
- delivery.should_receive(:mark_retryable).with(notification, now + 2 ** 1)
278
+ delivery.should_receive(:mark_retryable).with(notification, now + 2**1)
262
279
  perform
263
280
  end
264
281
  end
@@ -266,24 +283,24 @@ describe Rpush::Daemon::Gcm::Delivery do
266
283
  describe 'a 500 response' do
267
284
  before do
268
285
  notification.update_attribute(:retries, 2)
269
- response.stub(:code => 500)
286
+ response.stub(code: 500)
270
287
  end
271
288
 
272
289
  it 'logs a warning that the notification has been re-queued.' do
273
290
  notification.retries = 3
274
- notification.deliver_after = now + 2 ** 3
275
- Rpush.logger.should_receive(:warn).with("[MyApp] 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).")
291
+ notification.deliver_after = now + 2**3
292
+ Rpush.logger.should_receive(:warn).with("[MyApp] 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).")
276
293
  perform
277
294
  end
278
295
 
279
296
  it 'retries the notification in accordance with the exponential back-off strategy.' do
280
- delivery.should_receive(:mark_retryable).with(notification, now + 2 ** 3)
297
+ delivery.should_receive(:mark_retryable).with(notification, now + 2**3)
281
298
  perform
282
299
  end
283
300
  end
284
301
 
285
302
  describe 'a 401 response' do
286
- before { response.stub(:code => 401) }
303
+ before { response.stub(code: 401) }
287
304
 
288
305
  it 'raises an error' do
289
306
  expect { perform }.to raise_error(Rpush::DeliveryError)
@@ -291,20 +308,22 @@ describe Rpush::Daemon::Gcm::Delivery do
291
308
  end
292
309
 
293
310
  describe 'a 400 response' do
294
- before { response.stub(:code => 400) }
311
+ before { response.stub(code: 400) }
295
312
 
296
313
  it 'marks the notification as failed' do
297
- delivery.should_receive(:mark_failed).with(400, 'GCM failed to parse the JSON request. Possibly an Rpush bug, please open an issue.')
298
- perform rescue Rpush::DeliveryError
314
+ error = Rpush::DeliveryError.new(400, notification.id, 'GCM failed to parse the JSON request. Possibly an Rpush bug, please open an issue.')
315
+ delivery.should_receive(:mark_failed).with(error)
316
+ perform_with_rescue
299
317
  end
300
318
  end
301
319
 
302
320
  describe 'an un-handled response' do
303
- before { response.stub(:code => 418) }
321
+ before { response.stub(code: 418) }
304
322
 
305
323
  it 'marks the notification as failed' do
306
- delivery.should_receive(:mark_failed).with(418, "I'm a Teapot")
307
- perform rescue Rpush::DeliveryError
324
+ error = Rpush::DeliveryError.new(418, notification.id, "I'm a Teapot")
325
+ delivery.should_receive(:mark_failed).with(error)
326
+ perform_with_rescue
308
327
  end
309
328
  end
310
329
  end