rpush 1.0.0 → 2.0.0.beta1

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 (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