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
@@ -0,0 +1,30 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Rpush::Client::ActiveRecord::App do
4
+ it 'validates the uniqueness of name within type and environment' do
5
+ Rpush::Client::ActiveRecord::Apns::App.create!(name: 'test', environment: 'production', certificate: TEST_CERT)
6
+ app = Rpush::Client::ActiveRecord::Apns::App.new(name: 'test', environment: 'production', certificate: TEST_CERT)
7
+ app.valid?.should be_false
8
+ app.errors[:name].should eq ['has already been taken']
9
+
10
+ app = Rpush::Client::ActiveRecord::Apns::App.new(name: 'test', environment: 'development', certificate: TEST_CERT)
11
+ app.valid?.should be_true
12
+
13
+ app = Rpush::Client::ActiveRecord::Gcm::App.new(name: 'test', environment: 'production', auth_key: TEST_CERT)
14
+ app.valid?.should be_true
15
+ end
16
+
17
+ context 'validating certificates' do
18
+ it 'rescues from certificate error' do
19
+ app = Rpush::Client::ActiveRecord::Apns::App.new(name: 'test', environment: 'development', certificate: 'bad')
20
+ expect { app.valid? }.not_to raise_error
21
+ expect(app.valid?).to be_false
22
+ end
23
+
24
+ it 'raises other errors' do
25
+ app = Rpush::Client::ActiveRecord::Apns::App.new(name: 'test', environment: 'development', certificate: 'bad')
26
+ OpenSSL::X509::Certificate.stub(:new).and_raise(NameError, 'simulating no openssl')
27
+ expect { app.valid? }.to raise_error(NameError)
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,4 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Rpush::Client::ActiveRecord::Gcm::App do
4
+ end
@@ -1,23 +1,21 @@
1
1
  require 'unit_spec_helper'
2
2
  require 'unit/notification_shared.rb'
3
3
 
4
- describe Rpush::Gcm::Notification do
4
+ describe Rpush::Client::ActiveRecord::Gcm::Notification do
5
5
  it_should_behave_like 'an Notification subclass'
6
6
 
7
- let(:app) { Rpush::Gcm::App.create!(:name => 'test', :auth_key => 'abc') }
8
- let(:notification_class) { Rpush::Gcm::Notification }
7
+ let(:app) { Rpush::Client::ActiveRecord::Gcm::App.create!(name: 'test', auth_key: 'abc') }
8
+ let(:notification_class) { Rpush::Client::ActiveRecord::Gcm::Notification }
9
9
  let(:notification) { notification_class.new }
10
- let(:data_setter) { 'data=' }
11
- let(:data_getter) { 'data' }
12
10
 
13
11
  it "has a 'data' payload limit of 4096 bytes" do
14
- notification.data = { :key => "a" * 4096 }
12
+ notification.data = { key: "a" * 4096 }
15
13
  notification.valid?.should be_false
16
14
  notification.errors[:base].should eq ["Notification payload data cannot be larger than 4096 bytes."]
17
15
  end
18
16
 
19
17
  it 'limits the number of registration ids to 1000' do
20
- notification.registration_ids = ['a']*(1000+1)
18
+ notification.registration_ids = ['a'] * (1000 + 1)
21
19
  notification.valid?.should be_false
22
20
  notification.errors[:base].should eq ["Number of registration_ids cannot be larger than 1000."]
23
21
  end
@@ -0,0 +1,15 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Rpush::Client::ActiveRecord::Notification do
4
+ let(:notification) { Rpush::Client::ActiveRecord::Notification.new }
5
+
6
+ it 'allows assignment of many registration IDs' do
7
+ notification.registration_ids = %w(a b)
8
+ notification.registration_ids.should eq %w(a b)
9
+ end
10
+
11
+ it 'allows assignment of a single registration ID' do
12
+ notification.registration_ids = 'a'
13
+ notification.registration_ids.should eq ['a']
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Rpush::Client::ActiveRecord::Wpns::App do
4
+ end
@@ -0,0 +1,21 @@
1
+ require 'unit_spec_helper'
2
+ require 'unit/notification_shared.rb'
3
+
4
+ describe Rpush::Client::ActiveRecord::Wpns::Notification do
5
+ it_should_behave_like 'an Notification subclass'
6
+ let(:app) { Rpush::Client::ActiveRecord::Wpns::App.create!(name: 'test', auth_key: 'abc') }
7
+ let(:notification_class) { Rpush::Client::ActiveRecord::Wpns::Notification }
8
+ let(:notification) { notification_class.new }
9
+
10
+ it "should have an url in the uri parameter" do
11
+ notification = Rpush::Client::ActiveRecord::Wpns::Notification.new(uri: "somthing")
12
+ notification.valid?
13
+ notification.errors[:uri].include?("is invalid").should be_true
14
+ end
15
+
16
+ it "should be invalid if there's no message" do
17
+ notification = Rpush::Client::ActiveRecord::Wpns::Notification.new(alert: "")
18
+ notification.valid?
19
+ notification.errors[:alert].include?("can't be blank").should be_true
20
+ end
21
+ end
@@ -1,11 +1,14 @@
1
1
  require 'unit_spec_helper'
2
2
 
3
3
  describe Rpush do
4
- let(:config) { double }
4
+ let(:config) { Rpush.config }
5
5
 
6
- before { Rpush.stub(:config => config) }
6
+ before do
7
+ Rpush.stub(require: nil)
8
+ Rpush.stub(config: config)
9
+ end
7
10
 
8
- it 'can yields a config block' do
11
+ it 'yields a configure block' do
9
12
  expect { |b| Rpush.configure(&b) }.to yield_with_args(config)
10
13
  end
11
14
  end
@@ -26,9 +29,8 @@ describe Rpush::Configuration do
26
29
  end
27
30
 
28
31
  it 'sets the pid_file relative if not absolute' do
29
- Rails.stub(:root => '/rails')
30
32
  config.pid_file = 'tmp/rpush.pid'
31
- config.pid_file.should eq '/rails/tmp/rpush.pid'
33
+ config.pid_file.should eq '/tmp/rails_root/tmp/rpush.pid'
32
34
  end
33
35
 
34
36
  it 'does not alter an absolute pid_file path' do
@@ -42,4 +44,9 @@ describe Rpush::Configuration do
42
44
  config.foreground = false
43
45
  config.foreground.should be_true
44
46
  end
47
+
48
+ it 'delegate redis_options to Modis' do
49
+ Rpush.config.redis_options = { hi: :mom }
50
+ Modis.redis_options.should eq(hi: :mom)
51
+ end
45
52
  end
@@ -1,15 +1,15 @@
1
1
  require 'unit_spec_helper'
2
2
 
3
3
  describe Rpush::Daemon::Adm::Delivery do
4
- let(:app) { Rpush::Adm::App.new(:name => 'MyApp', :client_id => 'CLIENT_ID', :client_secret => 'CLIENT_SECRET') }
5
- let(:notification) { Rpush::Adm::Notification.create!(:app => app, :registration_ids => ['xyz'], :deliver_after => Time.now, :data => {'message' => 'test'}) }
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::Adm::App.create!(name: 'MyApp', client_id: 'CLIENT_ID', client_secret: 'CLIENT_SECRET') }
5
+ let(:notification) { Rpush::Adm::Notification.create!(app: app, registration_ids: ['xyz'], deliver_after: Time.now, data: { 'message' => 'test' }) }
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::Adm::Delivery.new(app, http, notification, batch) }
12
- let(:store) { double(:create_adm_notification => double(:id => 2)) }
12
+ let(:store) { double(create_adm_notification: double(id: 2)) }
13
13
 
14
14
  def perform
15
15
  delivery.perform
@@ -19,44 +19,45 @@ describe Rpush::Daemon::Adm::Delivery do
19
19
  app.access_token = 'ACCESS_TOKEN'
20
20
  app.access_token_expiration = Time.now + 1.month
21
21
 
22
- delivery.stub(:reflect => nil)
23
- Rpush::Daemon.stub(:store => store)
24
- Time.stub(:now => now)
25
- Rpush.stub(:logger => logger)
22
+ delivery.stub(reflect: nil)
23
+ Rpush::Daemon.stub(store: store)
24
+ Time.stub(now: now)
25
+ Rpush.stub(logger: logger)
26
26
  end
27
27
 
28
28
  describe 'unknown error response' do
29
29
  before do
30
- response.stub(:code => 408)
30
+ response.stub(code: 408)
31
31
  end
32
32
 
33
33
  it 'marks the notification as failed because no successful delivery was made' do
34
- response.stub(:body => JSON.dump({ 'reason' => 'InvalidData' }))
35
- delivery.should_receive(:mark_failed).with(408, 'Request Timeout')
34
+ response.stub(body: JSON.dump('reason' => 'InvalidData'))
35
+ error = Rpush::DeliveryError.new(408, notification.id, 'Request Timeout')
36
+ delivery.should_receive(:mark_failed).with(error)
36
37
  expect { perform }.to raise_error(Rpush::DeliveryError)
37
38
  end
38
39
  end
39
40
 
40
41
  describe 'a 200 (Ok) response' do
41
42
  before do
42
- response.stub(:code => 200)
43
+ response.stub(code: 200)
43
44
  end
44
45
 
45
46
  it 'marks the notification as delivered if delivered successfully to all devices' do
46
- response.stub(:body => JSON.dump({ 'registrationID' => 'xyz' }))
47
+ response.stub(body: JSON.dump('registrationID' => 'xyz'))
47
48
  delivery.should_receive(:mark_delivered)
48
49
  perform
49
50
  end
50
51
 
51
52
  it 'logs that the notification was delivered' do
52
- response.stub(:body => JSON.dump({ 'registrationID' => 'xyz' }))
53
+ response.stub(body: JSON.dump('registrationID' => 'xyz'))
53
54
  logger.should_receive(:info).with("[MyApp] #{notification.id} sent to xyz")
54
55
  perform
55
56
  end
56
57
 
57
58
  it 'reflects on canonical IDs' do
58
- response.stub(:body => JSON.dump({'registrationID' => 'canonical123' }))
59
- notification.stub(:registration_ids => ['1'])
59
+ response.stub(body: JSON.dump('registrationID' => 'canonical123'))
60
+ notification.stub(registration_ids: ['1'])
60
61
  delivery.should_receive(:reflect).with(:adm_canonical_id, '1', 'canonical123')
61
62
  perform
62
63
  end
@@ -64,31 +65,32 @@ describe Rpush::Daemon::Adm::Delivery do
64
65
 
65
66
  describe 'a 400 (Bad Request) response' do
66
67
  before do
67
- response.stub(:code => 400)
68
+ response.stub(code: 400)
68
69
  end
69
70
 
70
71
  it 'marks the notification as failed because no successful delivery was made' do
71
- response.stub(:body => JSON.dump({ 'reason' => 'InvalidData' }))
72
- delivery.should_receive(:mark_failed).with(nil, 'Failed to deliver to all recipients.')
73
- expect { perform }.to raise_error(Rpush::DeliveryError)
72
+ response.stub(body: JSON.dump('reason' => 'InvalidData'))
73
+ error = Rpush::DeliveryError.new(nil, notification.id, 'Failed to deliver to all recipients.')
74
+ delivery.should_receive(:mark_failed).with(error)
75
+ expect { perform }.to raise_error(error)
74
76
  end
75
77
 
76
78
  it 'logs that the notification was not delivered' do
77
- response.stub(:body => JSON.dump({ 'reason' => 'InvalidRegistrationId' }))
79
+ response.stub(body: JSON.dump('reason' => 'InvalidRegistrationId'))
78
80
  logger.should_receive(:warn).with("[MyApp] bad_request: xyz (InvalidRegistrationId)")
79
- expect { perform }.to raise_error(Rpush::DeliveryError)
81
+ expect { perform }.to raise_error
80
82
  end
81
83
  end
82
84
 
83
85
  describe 'a 401 (Unauthorized) response' do
84
- let(:http) { double(:shutdown => nil)}
85
- let(:token_response) { double(:code => 200, :header => {}, :body => JSON.dump({'access_token' => 'ACCESS_TOKEN', 'expires_in' => 60})) }
86
+ let(:http) { double(shutdown: nil) }
87
+ let(:token_response) { double(code: 200, header: {}, body: JSON.dump('access_token' => 'ACCESS_TOKEN', 'expires_in' => 60)) }
86
88
 
87
89
  before do
88
- response.stub(:code => 401, :header => { 'retry-after' => 10 })
90
+ response.stub(code: 401, header: { 'retry-after' => 10 })
89
91
 
90
92
  # first request to deliver message that returns unauthorized response
91
- adm_uri = URI.parse(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL % [notification.registration_ids.first])
93
+ adm_uri = URI.parse(format(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL, notification.registration_ids.first))
92
94
  http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(response)
93
95
  end
94
96
 
@@ -116,7 +118,7 @@ describe Rpush::Daemon::Adm::Delivery do
116
118
  end
117
119
 
118
120
  it 'should log the error and stop retrying if new access token can\'t be retrieved' do
119
- token_response.stub(:code => 404, :body => "test")
121
+ token_response.stub(code: 404, body: "test")
120
122
  # request for access token
121
123
  http.should_receive(:request).with(Rpush::Daemon::Adm::Delivery::AMAZON_TOKEN_URI, instance_of(Net::HTTP::Post)).and_return(token_response)
122
124
 
@@ -130,15 +132,15 @@ describe Rpush::Daemon::Adm::Delivery do
130
132
  end
131
133
 
132
134
  describe 'a 429 (Too Many Request) response' do
133
- let(:http) { double(:shutdown => nil) }
134
- let(:notification) { Rpush::Adm::Notification.create!(:app => app, :registration_ids => ['abc','xyz'], :deliver_after => Time.now, :collapse_key => 'sync', :data => {'message' => 'test'}) }
135
- let(:too_many_request_response) { double(:code => 429, :header => { 'retry-after' => 3600 }) }
135
+ let(:http) { double(shutdown: nil) }
136
+ let(:notification) { Rpush::Adm::Notification.create!(app: app, registration_ids: %w(abc xyz), deliver_after: Time.now, collapse_key: 'sync', data: { 'message' => 'test' }) }
137
+ let(:too_many_request_response) { double(code: 429, header: { 'retry-after' => 3600 }) }
136
138
 
137
139
  it 'should retry the entire notification respecting the Retry-After header if none sent out yet' do
138
- response.stub(:code => 429, :header => { 'retry-after' => 3600 })
140
+ response.stub(code: 429, header: { 'retry-after' => 3600 })
139
141
 
140
142
  # first request to deliver message that returns too many request response
141
- adm_uri = URI.parse(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL % [notification.registration_ids.first])
143
+ adm_uri = URI.parse(format(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL, notification.registration_ids.first))
142
144
  http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(response)
143
145
 
144
146
  delivery.should_receive(:mark_retryable).with(notification, now + 1.hour)
@@ -146,25 +148,25 @@ describe Rpush::Daemon::Adm::Delivery do
146
148
  end
147
149
 
148
150
  it 'should retry the entire notification using exponential backoff' do
149
- response.stub(:code => 429, :header => {})
151
+ response.stub(code: 429, header: {})
150
152
 
151
153
  # first request to deliver message that returns too many request response
152
- adm_uri = URI.parse(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL % [notification.registration_ids.first])
154
+ adm_uri = URI.parse(format(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL, notification.registration_ids.first))
153
155
  http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(response)
154
156
 
155
- delivery.should_receive(:mark_retryable).with(notification, Time.now + 2 ** (notification.retries + 1))
157
+ delivery.should_receive(:mark_retryable).with(notification, Time.now + 2**(notification.retries + 1))
156
158
  perform
157
159
  end
158
160
 
159
161
  it 'should keep sent reg ids in original notification and create new notification with remaining reg ids for retry' do
160
- response.stub(:code => 200, :body => JSON.dump({ 'registrationID' => 'abc' }))
162
+ response.stub(code: 200, body: JSON.dump('registrationID' => 'abc'))
161
163
 
162
164
  # first request to deliver message succeeds
163
- adm_uri = URI.parse(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL % ['abc'])
165
+ adm_uri = URI.parse(format(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL, 'abc'))
164
166
  http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(response)
165
167
 
166
168
  # first request to deliver message that returns too many request response
167
- adm_uri = URI.parse(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL % ['xyz'])
169
+ adm_uri = URI.parse(format(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL, 'xyz'))
168
170
  http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(too_many_request_response)
169
171
 
170
172
  store.should_receive(:update_notification).with do |notif|
@@ -172,10 +174,10 @@ describe Rpush::Daemon::Adm::Delivery do
172
174
  notif.registration_ids.include?('xyz').should be_false
173
175
  end
174
176
 
175
- store.should_receive(:create_adm_notification).with do |attrs, notification_data, reg_ids, deliver_after, notification_app|
176
- attrs.has_key?('collapse_key').should be_true
177
- attrs.has_key?('delay_while_idle').should be_true
178
- attrs.has_key?('app_id').should be_true
177
+ store.should_receive(:create_adm_notification).with do |attrs, _notification_data, reg_ids, deliver_after, notification_app|
178
+ attrs.key?('collapse_key').should be_true
179
+ attrs.key?('delay_while_idle').should be_true
180
+ attrs.key?('app_id').should be_true
179
181
 
180
182
  reg_ids.should eq ['xyz']
181
183
  deliver_after.should eq now + 1.hour
@@ -190,11 +192,12 @@ describe Rpush::Daemon::Adm::Delivery do
190
192
 
191
193
  describe 'a 500 (Internal Server Error) response' do
192
194
  before do
193
- response.stub(:code => 500)
195
+ response.stub(code: 500)
194
196
  end
195
197
 
196
198
  it 'marks the notification as failed because no successful delivery was made' do
197
- delivery.should_receive(:mark_failed).with(nil, 'Failed to deliver to all recipients.')
199
+ error = Rpush::DeliveryError.new(nil, notification.id, 'Failed to deliver to all recipients.')
200
+ delivery.should_receive(:mark_failed).with(error)
198
201
  expect { perform }.to raise_error(Rpush::DeliveryError)
199
202
  end
200
203
 
@@ -206,7 +209,7 @@ describe Rpush::Daemon::Adm::Delivery do
206
209
 
207
210
  describe 'a 503 (Service Unavailable) response' do
208
211
  before do
209
- response.stub(:code => 503, :header => { 'retry-after' => 10 })
212
+ response.stub(code: 503, header: { 'retry-after' => 10 })
210
213
  end
211
214
 
212
215
  it 'should retry the notification respecting the Retry-After header' do
@@ -216,19 +219,19 @@ describe Rpush::Daemon::Adm::Delivery do
216
219
  end
217
220
 
218
221
  describe 'some registration ids succeeding and some failing' do
219
- let(:http) { double(:shutdown => nil) }
220
- let(:notification) { Rpush::Adm::Notification.create!(:app => app, :registration_ids => ['abc','xyz'], :deliver_after => Time.now, :collapse_key => 'sync', :data => {'message' => 'test'}) }
221
- let(:bad_request_response) { double(:code => 400, :body => JSON.dump({ 'reason' => 'InvalidData' })) }
222
+ let(:http) { double(shutdown: nil) }
223
+ let(:notification) { Rpush::Adm::Notification.create!(app: app, registration_ids: %w(abc xyz), deliver_after: Time.now, collapse_key: 'sync', data: { 'message' => 'test' }) }
224
+ let(:bad_request_response) { double(code: 400, body: JSON.dump('reason' => 'InvalidData')) }
222
225
 
223
226
  it 'should keep sent reg ids in original notification and create new notification with remaining reg ids for retry' do
224
- response.stub(:code => 200, :body => JSON.dump({ 'registrationID' => 'abc' }))
227
+ response.stub(code: 200, body: JSON.dump('registrationID' => 'abc'))
225
228
 
226
229
  # first request to deliver message succeeds
227
- adm_uri = URI.parse(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL % ['abc'])
230
+ adm_uri = URI.parse(format(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL, 'abc'))
228
231
  http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(response)
229
232
 
230
233
  # first request to deliver message that returns too many request response
231
- adm_uri = URI.parse(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL % ['xyz'])
234
+ adm_uri = URI.parse(format(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL, 'xyz'))
232
235
  http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(bad_request_response)
233
236
 
234
237
  store.should_receive(:update_notification).with do |notif|
@@ -1,8 +1,8 @@
1
1
  require 'unit_spec_helper'
2
2
 
3
- describe Rpush::Apns::CertificateExpiredError do
4
- let(:app) { double(:name => 'test') }
5
- let(:error) { Rpush::Apns::CertificateExpiredError.new(app, Time.now) }
3
+ describe Rpush::CertificateExpiredError do
4
+ let(:app) { double(name: 'test') }
5
+ let(:error) { Rpush::CertificateExpiredError.new(app, Time.now) }
6
6
 
7
7
  it 'returns a message' do
8
8
  error.message
@@ -1,101 +1,108 @@
1
1
  require 'unit_spec_helper'
2
2
 
3
3
  describe Rpush::Daemon::Apns::Delivery do
4
- let(:app) { double(:name => 'MyApp') }
5
- let(:notification) { double.as_null_object }
6
- let(:batch) { double(:mark_failed => nil, :mark_delivered => nil) }
7
- let(:logger) { double(:error => nil, :info => nil) }
8
- let(:config) { double(:check_for_errors => true) }
9
- let(:connection) { double(:select => false, :write => nil, :reconnect => nil, :close => nil, :connect => nil) }
10
- let(:delivery) { Rpush::Daemon::Apns::Delivery.new(app, connection, notification, batch) }
11
-
12
- def perform
13
- begin
14
- delivery.perform
15
- rescue Rpush::DeliveryError, Rpush::Apns::DisconnectionError
16
- end
17
- end
4
+ let(:app) { double(name: 'MyApp') }
5
+ let(:notification1) { double.as_null_object }
6
+ let(:notification2) { double.as_null_object }
7
+ let(:batch) { double(mark_all_failed: nil, mark_all_delivered: nil, all_processed: nil) }
8
+ let(:logger) { double(error: nil, info: nil) }
9
+ let(:connection) { double(select: false, write: nil, reconnect: nil, close: nil, connect: nil) }
10
+ let(:delivery) { Rpush::Daemon::Apns::Delivery.new(app, connection, batch) }
18
11
 
19
12
  before do
20
- Rpush.stub(:config => config, :logger => logger)
13
+ batch.stub(:each_notification) do |&blk|
14
+ [notification1, notification2].each(&blk)
15
+ end
16
+ Rpush.stub(logger: logger)
21
17
  end
22
18
 
23
- it "sends the binary version of the notification" do
24
- notification.stub(:to_binary => "hi mom")
25
- connection.should_receive(:write).with("hi mom")
26
- perform
19
+ it 'writes the binary batch' do
20
+ notification1.stub(to_binary: 'binary1')
21
+ notification2.stub(to_binary: 'binary2')
22
+ connection.should_receive(:write).with('binary1binary2')
23
+ delivery.perform
27
24
  end
28
25
 
29
- it "logs the notification delivery" do
30
- notification.stub(:id => 666, :device_token => 'abc123')
31
- logger.should_receive(:info).with("[MyApp] 666 sent to abc123")
32
- perform
26
+ it 'logs the notification deliveries' do
27
+ notification1.stub(id: 666, device_token: 'abc123')
28
+ notification2.stub(id: 42, device_token: 'abc456')
29
+ logger.should_receive(:info).with('[MyApp] 666 sent to abc123')
30
+ logger.should_receive(:info).with('[MyApp] 42 sent to abc456')
31
+ delivery.perform
33
32
  end
34
33
 
35
- it "marks the notification as delivered" do
36
- delivery.should_receive(:mark_delivered)
37
- perform
34
+ it 'marks all notifications as delivered' do
35
+ delivery.should_receive(:mark_batch_delivered)
36
+ delivery.perform
38
37
  end
39
38
 
40
- it 'does not check for errors if check_for_errors config option is false' do
41
- config.stub(:check_for_errors => false)
42
- delivery.should_not_receive(:check_for_error)
43
- perform
39
+ it 'notifies the batch all notifications have been processed' do
40
+ batch.should_receive(:all_processed)
41
+ delivery.perform
44
42
  end
45
43
 
46
- describe "when delivery fails" do
47
- before { connection.stub(:select => true, :read => [8, 4, 69].pack("ccN")) }
48
-
49
- it "marks the notification as failed" do
50
- delivery.should_receive(:mark_failed).with(4, "Missing payload")
51
- perform
52
- end
53
-
54
- it "logs the delivery error" do
55
- # checking for the doublebed error doesn't work in jruby, but checking
56
- # for the exception by class does.
57
-
58
- #error = Rpush::DeliveryError.new(4, 12, "Missing payload")
59
- #Rpush::DeliveryError.stub(:new => error)
60
- #expect { delivery.perform }.to raise_error(error)
61
-
62
- expect { delivery.perform }.to raise_error(Rpush::DeliveryError)
63
- end
64
-
65
- it "reads 6 bytes from the socket" do
66
- connection.should_receive(:read).with(6).and_return(nil)
67
- perform
68
- end
69
-
70
- it "does not attempt to read from the socket if the socket was not selected for reading after the timeout" do
71
- connection.stub(:select => nil)
72
- connection.should_not_receive(:read)
73
- perform
74
- end
75
-
76
- it "reconnects the socket" do
77
- connection.should_receive(:reconnect)
78
- perform
79
- end
80
-
81
- it "logs that the connection is being reconnected" do
82
- Rpush.logger.should_receive(:error).with("[MyApp] Error received, reconnecting...")
83
- perform
84
- end
85
-
86
- context "when the APNs disconnects without returning an error" do
87
- before do
88
- connection.stub(:read => nil)
89
- end
90
-
91
- it 'raises a DisconnectError error if the connection is closed without an error being returned' do
92
- expect { delivery.perform }.to raise_error(Rpush::Apns::DisconnectionError)
93
- end
94
-
95
- it 'marks the notification as failed' do
96
- delivery.should_receive(:mark_failed).with(nil, "APNs disconnected without returning an error.")
97
- perform
98
- end
44
+ describe 'when an error is raised' do
45
+ it 'marks all notifications as failed' do
46
+ error = StandardError.new
47
+ connection.stub(:write).and_raise(error)
48
+ delivery.should_receive(:mark_batch_failed).with(error)
49
+ expect { delivery.perform }.to raise_error(error)
99
50
  end
100
51
  end
52
+
53
+ # describe "when delivery fails" do
54
+ # before { connection.stub(select: true, read: [8, 4, 69].pack("ccN")) }
55
+ #
56
+ # it "marks the notification as failed" do
57
+ # delivery.should_receive(:mark_failed).with(4, "Unable to deliver notification 69, received error 4 (Missing payload)")
58
+ # perform
59
+ # end
60
+ #
61
+ # it "logs the delivery error" do
62
+ # # checking for the doublebed error doesn't work in jruby, but checking
63
+ # # for the exception by class does.
64
+ #
65
+ # # error = Rpush::DeliveryError.new(4, 12, "Missing payload")
66
+ # # Rpush::DeliveryError.stub(new: error)
67
+ # # expect { delivery.perform }.to raise_error(error)
68
+ #
69
+ # expect { delivery.perform }.to raise_error(Rpush::DeliveryError)
70
+ # end
71
+ #
72
+ # it "reads 6 bytes from the socket" do
73
+ # connection.should_receive(:read).with(6).and_return(nil)
74
+ # perform
75
+ # end
76
+ #
77
+ # it "does not attempt to read from the socket if the socket was not selected for reading after the timeout" do
78
+ # connection.stub(select: nil)
79
+ # connection.should_not_receive(:read)
80
+ # perform
81
+ # end
82
+ #
83
+ # it "reconnects the socket" do
84
+ # connection.should_receive(:reconnect)
85
+ # perform
86
+ # end
87
+ #
88
+ # it "logs that the connection is being reconnected" do
89
+ # Rpush.logger.should_receive(:error).with("[MyApp] Error received, reconnecting...")
90
+ # perform
91
+ # end
92
+ #
93
+ # context "when the APNs disconnects without returning an error" do
94
+ # before do
95
+ # connection.stub(read: nil)
96
+ # end
97
+ #
98
+ # it 'raises a DisconnectError error if the connection is closed without an error being returned' do
99
+ # expect { delivery.perform }.to raise_error(Rpush::DisconnectionError)
100
+ # end
101
+ #
102
+ # it 'marks the notification as failed' do
103
+ # delivery.should_receive(:mark_failed).with(nil, "The APNs disconnected without returning an error. This may indicate you are using an invalid certificate for the host.")
104
+ # perform
105
+ # end
106
+ # end
107
+ # end
101
108
  end