rpush 2.0.0.beta2 → 2.0.0.rc1

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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1 -0
  3. data/README.md +1 -1
  4. data/lib/generators/rpush_generator.rb +2 -2
  5. data/lib/generators/templates/rpush.rb +19 -0
  6. data/lib/generators/templates/rpush_2_0_0_updates.rb +19 -0
  7. data/lib/rpush/client/active_model/apns/notification.rb +1 -1
  8. data/lib/rpush/client/active_model/notification.rb +1 -1
  9. data/lib/rpush/client/active_record/apns/feedback.rb +3 -1
  10. data/lib/rpush/client/redis/notification.rb +1 -1
  11. data/lib/rpush/daemon/adm/delivery.rb +5 -2
  12. data/lib/rpush/daemon/app_runner.rb +1 -1
  13. data/lib/rpush/daemon/dispatcher/apns_tcp.rb +10 -2
  14. data/lib/rpush/daemon/store/active_record/reconnectable.rb +1 -1
  15. data/lib/rpush/daemon/store/active_record.rb +1 -1
  16. data/lib/rpush/daemon/store/redis.rb +1 -1
  17. data/lib/rpush/daemon.rb +2 -2
  18. data/lib/rpush/reflection.rb +3 -1
  19. data/lib/rpush/version.rb +1 -1
  20. data/lib/rpush.rb +1 -1
  21. data/lib/tasks/quality.rake +6 -5
  22. data/lib/tasks/test.rake +1 -5
  23. data/spec/functional/apns_spec.rb +5 -5
  24. data/spec/functional/embed_spec.rb +1 -3
  25. data/spec/functional/new_app_spec.rb +1 -3
  26. data/spec/unit/client/active_record/notification_spec.rb +6 -0
  27. data/spec/unit/daemon/adm/delivery_spec.rb +8 -0
  28. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +1 -3
  29. data/spec/unit/daemon/app_runner_spec.rb +20 -5
  30. data/spec/unit/daemon/feeder_spec.rb +1 -3
  31. data/spec/unit/daemon/gcm/delivery_spec.rb +18 -16
  32. data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +39 -19
  33. data/spec/unit/daemon/store/active_record_spec.rb +1 -1
  34. data/spec/unit/daemon/wpns/delivery_spec.rb +1 -4
  35. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 09d2df386688b4c0ac01e8aab5e4c725257a3263
4
- data.tar.gz: a7233c67417785808daf0e8d0f637d17b31a33b9
3
+ metadata.gz: 0b35cfade151c01d8fc40a3c2c600294eacfbfe0
4
+ data.tar.gz: e9da0a8194b7916eab23ad91b8158e48f506247f
5
5
  SHA512:
6
- metadata.gz: 4e19a18011c6e4e06b84deb49b82172ebb580a71ba8aef64e7ba6dce9edfc8aa42273bc131643a1f174aa9a30429b9797617e0661f7005eb657f9d9f1daf0b76
7
- data.tar.gz: 47c703cdd66bb3fd80327d991604d0ee573db02b4324023484a90ac5ce7793cd022906ea3b1f424c97390edf7e59e13649c41efc9f2de9cadf68859fbc937f01
6
+ metadata.gz: a5b4463d42d74de9fa8a68cdcc424b0990d7b6e34fae5a920875b042dba246a6901a4666ff2452d6ef37f1325232764537a41ed06b2f8dc318a84ef9ae3b368b
7
+ data.tar.gz: 0fc2176665da6cabbc9459bd35d1cb7b782771195fd882122808ccad7e35f9303675da12bf0c2c7617c17b4a8bdc271742a8ead20b790711b2d25f6fb5fe0657
data/CHANGELOG.md CHANGED
@@ -10,6 +10,7 @@
10
10
  * The 'wakeup' config option has been removed.
11
11
  * The 'batch_storage_updates' config option has been deprecated, storage backends will now always batch updates where appropriate.
12
12
  * The rpush process title updates with number of queued notifications and number of dispatchers.
13
+ * Rpush::Apns::Feedback#app has been renamed to app_id and is now an Integer.
13
14
 
14
15
  ## 1.0.0 (Feb 9, 2014)
15
16
  * Renamed to Rpush (from Rapns). Version number reset to 1.0.0.
data/README.md CHANGED
@@ -29,7 +29,7 @@ Add it to your Gemfile:
29
29
  gem 'rpush'
30
30
  ```
31
31
 
32
- Generate the migrations, rpush.yml and migrate:
32
+ Generate the migrations, rpush.rb and migrate:
33
33
 
34
34
  ```
35
35
  rails g rpush
@@ -20,11 +20,11 @@ class RpushGenerator < Rails::Generators::Base
20
20
  add_rpush_migration('add_adm')
21
21
  add_rpush_migration('rename_rapns_to_rpush')
22
22
  add_rpush_migration('add_fail_after_to_rpush_notifications')
23
- add_rpush_migration('add_processing_to_rpush_notifications')
24
23
  else
25
24
  add_rpush_migration('add_rpush')
26
- add_rpush_migration('rpush_2_0_0_updates')
27
25
  end
26
+
27
+ add_rpush_migration('rpush_2_0_0_updates')
28
28
  end
29
29
 
30
30
  def copy_config
@@ -59,12 +59,22 @@ Rpush.reflect do |on|
59
59
  # on.notification_failed do |notification|
60
60
  # end
61
61
 
62
+ # Called when the notification delivery failed and only the notification ID
63
+ # is present in memory.
64
+ # on.notification_id_failed do |app, notification_id, error_code, error_description|
65
+ # end
66
+
62
67
  # Called when a notification will be retried at a later date.
63
68
  # Call 'deliver_after' on the notification for the next delivery date
64
69
  # and 'retries' for the number of times this notification has been retried.
65
70
  # on.notification_will_retry do |notification|
66
71
  # end
67
72
 
73
+ # Called when a notification will be retried and only the notification ID
74
+ # is present in memory.
75
+ # on.notification_id_will_retry do |app, notification_id, retry_after|
76
+ # end
77
+
68
78
  # Called when a TCP connection is lost and will be reconnected.
69
79
  # on.tcp_connection_lost do |app, error|
70
80
  # end
@@ -101,6 +111,15 @@ Rpush.reflect do |on|
101
111
  # on.adm_canonical_id do |old_id, canonical_id|
102
112
  # end
103
113
 
114
+ # Called when Failed to deliver to ADM. Check the 'reason' string for further
115
+ # explanations.
116
+ #
117
+ # If the reason is the string 'Unregistered', you should remove
118
+ # this registration id from your records.
119
+ # on.adm_failed_to_recipient do |notification, registration_id, reason|
120
+ # end
121
+
122
+
104
123
  # Called when an exception is raised.
105
124
  # on.error do |error|
106
125
  # end
@@ -8,9 +8,20 @@ class Rpush200Updates < ActiveRecord::Migration
8
8
  end
9
9
 
10
10
  add_index :rpush_notifications, [:processing, :delivered, :failed, :deliver_after], name: 'index_rpush_notifications_multi'
11
+
12
+ rename_column :rpush_feedback, :app, :app_id
13
+
14
+ if postgresql?
15
+ execute('ALTER TABLE rpush_feedback ALTER COLUMN app_id TYPE integer USING (trim(app_id)::integer)')
16
+ else
17
+ change_column :rpush_feedback, :app_id, :integer
18
+ end
11
19
  end
12
20
 
13
21
  def self.down
22
+ change_column :rpush_feedback, :app_id, :string
23
+ rename_column :rpush_feedback, :app_id, :app
24
+
14
25
  if index_name_exists?(:rpush_notifications, :index_rpush_notifications_multi, true)
15
26
  remove_index :rpush_notifications, name: :index_rpush_notifications_multi
16
27
  end
@@ -20,4 +31,12 @@ class Rpush200Updates < ActiveRecord::Migration
20
31
  remove_column :rpush_notifications, :priority
21
32
  remove_column :rpush_notifications, :processing
22
33
  end
34
+
35
+ def self.adapter_name
36
+ ActiveRecord::Base.configurations[Rails.env]['adapter']
37
+ end
38
+
39
+ def self.postgresql?
40
+ adapter_name =~ /postgresql/
41
+ end
23
42
  end
@@ -38,7 +38,7 @@ module Rpush
38
38
  self.data = (data || {}).merge(CONTENT_AVAILABLE_KEY => true)
39
39
  end
40
40
 
41
- def as_json
41
+ def as_json # rubocop:disable Metrics/PerceivedComplexity
42
42
  json = ActiveSupport::OrderedHash.new
43
43
 
44
44
  if data && data.key?(MDM_KEY)
@@ -5,7 +5,7 @@ module Rpush
5
5
  def self.included(base)
6
6
  base.instance_eval do
7
7
  validates :expiry, numericality: true, allow_nil: true
8
- validates :app_id, presence: true
8
+ validates :app, presence: true
9
9
  end
10
10
  end
11
11
 
@@ -6,9 +6,11 @@ module Rpush
6
6
  self.table_name = 'rpush_feedback'
7
7
 
8
8
  if Rpush.attr_accessible_available?
9
- attr_accessible :device_token, :failed_at, :app
9
+ attr_accessible :device_token, :failed_at, :app_id
10
10
  end
11
11
 
12
+ belongs_to :app, class_name: 'Rpush::Client::ActiveRecord::App'
13
+
12
14
  validates :device_token, presence: true
13
15
  validates :failed_at, presence: true
14
16
 
@@ -21,7 +21,7 @@ module Rpush
21
21
  attribute :badge, :integer
22
22
  attribute :device_token, :string
23
23
  attribute :sound, :string, default: 'default'
24
- attribute :alert, :hash, strict: false
24
+ attribute :alert, [:string, :hash], strict: false
25
25
  attribute :data, :hash
26
26
  attribute :expiry, :integer, default: 1.day.to_i
27
27
  attribute :delivered, :boolean
@@ -120,8 +120,11 @@ module Rpush
120
120
 
121
121
  return unless response_body.key?('reason')
122
122
 
123
- log_warn("bad_request: #{current_registration_id} (#{response_body['reason']})")
124
- @failed_registration_ids[current_registration_id] = response_body['reason']
123
+ reason = response_body['reason']
124
+ log_warn("bad_request: #{current_registration_id} (#{reason})")
125
+ @failed_registration_ids[current_registration_id] = reason
126
+
127
+ reflect(:adm_failed_to_recipient, @notification, current_registration_id, reason)
125
128
  end
126
129
 
127
130
  def unauthorized(response)
@@ -98,7 +98,7 @@ module Rpush
98
98
 
99
99
  def enqueue(notifications)
100
100
  if service.batch_deliveries?
101
- batch_size = (notifications.size / num_dispatcher_loops).ceil
101
+ batch_size = (notifications.size / num_dispatcher_loops.to_f).ceil
102
102
  notifications.in_groups_of(batch_size, false).each do |batch_notifications|
103
103
  batch = Batch.new(batch_notifications)
104
104
  queue.push(QueuePayload.new(batch))
@@ -3,6 +3,7 @@ module Rpush
3
3
  module Dispatcher
4
4
  class ApnsTcp < Rpush::Daemon::Dispatcher::Tcp
5
5
  include Loggable
6
+ include Reflectable
6
7
 
7
8
  SELECT_TIMEOUT = 10
8
9
  ERROR_TUPLE_BYTES = 6
@@ -85,17 +86,24 @@ module Rpush
85
86
 
86
87
  def handle_disconnect
87
88
  log_error('The APNs disconnected without returning an error. Marking all notifications delivered via this connection as failed.')
88
- Rpush::Daemon.store.mark_ids_failed(delivered_buffer, nil, 'The APNs disconnected without returning an error. This may indicate you are using an invalid certificate.', Time.now)
89
+ reason = 'The APNs disconnected without returning an error. This may indicate you are using an invalid certificate.'
90
+ Rpush::Daemon.store.mark_ids_failed(delivered_buffer, nil, reason, Time.now)
91
+ delivered_buffer.each { |id| reflect(:notification_id_failed, @app, id, nil, reason) }
89
92
  end
90
93
 
91
94
  def handle_error(code, notification_id)
92
95
  failed_pos = delivered_buffer.index(notification_id)
93
96
  description = APNS_ERRORS[code.to_i] || "Unknown error code #{code.inspect}. Possible Rpush bug?"
94
97
  Rpush::Daemon.store.mark_ids_failed([notification_id], code, description, Time.now)
98
+ reflect(:notification_id_failed, @app, notification_id, code, description)
95
99
 
96
100
  if failed_pos
97
101
  retry_ids = delivered_buffer[(failed_pos + 1)..-1]
98
- Rpush::Daemon.store.mark_ids_retryable(retry_ids, Time.now) if retry_ids.size > 0
102
+ if retry_ids.size > 0
103
+ now = Time.now
104
+ Rpush::Daemon.store.mark_ids_retryable(retry_ids, now)
105
+ retry_ids.each { |id| reflect(:notification_id_will_retry, @app, id, now) }
106
+ end
99
107
  elsif delivered_buffer.size > 0
100
108
  log_error("Delivery sequence unknown for notifications following #{notification_id}.")
101
109
  end
@@ -22,7 +22,7 @@ module Rpush
22
22
  module Reconnectable
23
23
  ADAPTER_ERRORS = [::ActiveRecord::StatementInvalid, PGError, PG::Error,
24
24
  Mysql::Error, Mysql2::Error, ::ActiveRecord::JDBCError,
25
- SQLite3::Exception]
25
+ SQLite3::Exception, ::ActiveRecord::ConnectionTimeoutError]
26
26
 
27
27
  def with_database_reconnect_and_retry
28
28
  ::ActiveRecord::Base.connection_pool.with_connection do
@@ -119,7 +119,7 @@ module Rpush
119
119
  def create_apns_feedback(failed_at, device_token, app)
120
120
  with_database_reconnect_and_retry do
121
121
  Rpush::Client::ActiveRecord::Apns::Feedback.create!(failed_at: failed_at,
122
- device_token: device_token, app: app)
122
+ device_token: device_token, app_id: app.id)
123
123
  end
124
124
  end
125
125
 
@@ -79,7 +79,7 @@ module Rpush
79
79
  end
80
80
 
81
81
  def create_apns_feedback(failed_at, device_token, app)
82
- Rpush::Client::Redis::Apns::Feedback.create!(failed_at: failed_at, device_token: device_token, app: app)
82
+ Rpush::Client::Redis::Apns::Feedback.create!(failed_at: failed_at, device_token: device_token, app_id: app.id)
83
83
  end
84
84
 
85
85
  def create_gcm_notification(attrs, data, registration_ids, deliver_after, app) # rubocop:disable ParameterLists
data/lib/rpush/daemon.rb CHANGED
@@ -67,8 +67,8 @@ module Rpush
67
67
  shutdown_lock.synchronize { true }
68
68
  end
69
69
 
70
- def self.shutdown(quiet = false)
71
- puts "\nShutting down..." unless quiet
70
+ def self.shutdown
71
+ puts "\nShutting down..."
72
72
 
73
73
  shutdown_lock.synchronize do
74
74
  Feeder.stop
@@ -14,7 +14,9 @@ module Rpush
14
14
  :apns_feedback, :notification_enqueued, :notification_delivered,
15
15
  :notification_failed, :notification_will_retry, :gcm_delivered_to_recipient,
16
16
  :gcm_failed_to_recipient, :gcm_canonical_id, :gcm_invalid_registration_id,
17
- :error, :adm_canonical_id, :tcp_connection_lost, :ssl_certificate_will_expire
17
+ :error, :adm_canonical_id, :adm_failed_to_recipient,
18
+ :tcp_connection_lost, :ssl_certificate_will_expire,
19
+ :notification_id_will_retry, :notification_id_failed
18
20
  ]
19
21
 
20
22
  DEPRECATIONS = {}
data/lib/rpush/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Rpush
2
- VERSION = '2.0.0.beta2'
2
+ VERSION = '2.0.0.rc1'
3
3
  end
data/lib/rpush.rb CHANGED
@@ -4,7 +4,7 @@ require 'active_support/all'
4
4
  module Rpush
5
5
  def self.attr_accessible_available?
6
6
  require 'rails'
7
- ::Rails::VERSION::STRING < '4'
7
+ ::Rails::VERSION::STRING < '4' || defined?(::ActiveRecord::MassAssignmentSecurity)
8
8
  end
9
9
  end
10
10
 
@@ -11,24 +11,25 @@ begin
11
11
  end
12
12
 
13
13
  namespace :spec do
14
- task :cane => ['spec', 'cane_quality']
14
+ task cane: %w(spec cane_quality)
15
15
  end
16
16
  rescue LoadError
17
17
  warn "cane not available."
18
18
 
19
19
  namespace :spec do
20
- task :cane => ['spec']
20
+ task cane: ['spec']
21
21
  end
22
22
  end
23
23
 
24
24
  begin
25
25
  require 'rubocop/rake_task'
26
- RuboCop::RakeTask.new
26
+ t = RuboCop::RakeTask.new
27
+ t.options << '-D'
27
28
  rescue LoadError
28
29
  warn 'rubocop not available.'
29
- task :rubocop => ['spec']
30
+ task rubocop: ['spec']
30
31
  end
31
32
 
32
33
  namespace :spec do
33
- task quality: ['cane', 'rubocop']
34
+ task quality: %w(cane rubocop)
34
35
  end
data/lib/tasks/test.rake CHANGED
@@ -4,11 +4,7 @@ namespace :test do
4
4
 
5
5
  def cmd(str, clean_env = true)
6
6
  puts "* #{str}"
7
- retval = if clean_env
8
- Bundler.with_clean_env { `#{str}` }
9
- else
10
- `#{str}`
11
- end
7
+ retval = clean_env ? Bundler.with_clean_env { `#{str}` } : `#{str}`
12
8
  puts retval.strip
13
9
  retval
14
10
  end
@@ -5,9 +5,7 @@ describe 'APNs' do
5
5
  let(:app) { create_app }
6
6
  let!(:notification) { create_notification }
7
7
  let(:tcp_socket) { double(TCPSocket, setsockopt: nil, close: nil) }
8
- let(:ssl_socket) do double(OpenSSL::SSL::SSLSocket, :sync= => nil, connect: nil,
9
- write: nil, flush: nil, read: nil, close: nil)
10
- end
8
+ let(:ssl_socket) { double(OpenSSL::SSL::SSLSocket, :sync= => nil, connect: nil, write: nil, flush: nil, read: nil, close: nil) }
11
9
  let(:io_double) { double(select: nil) }
12
10
 
13
11
  before do
@@ -92,8 +90,10 @@ describe 'APNs' do
92
90
  tuple = "N\xE3\x84\r\x00 \x83OxfU\xEB\x9F\x84aJ\x05\xAD}\x00\xAF1\xE5\xCF\xE9:\xC3\xEA\a\x8F\x1D\xA4M*N\xB0\xCE\x17"
93
91
  allow(ssl_socket).to receive(:read).and_return(tuple, nil)
94
92
  Rpush.apns_feedback
95
- feedback = Rpush::Apns::Feedback.all
96
- feedback.should_not be_empty
93
+ feedback = Rpush::Apns::Feedback.all.first
94
+ feedback.should_not be_nil
95
+ feedback.app_id.should eq(app.id)
96
+ feedback.device_token.should eq('834f786655eb9f84614a05ad7d00af31e5cfe93ac3ea078f1da44d2a4eb0ce17')
97
97
  end
98
98
 
99
99
  describe 'delivery failures' do
@@ -5,9 +5,7 @@ describe 'embedding' do
5
5
  let(:app) { Rpush::Apns::App.new }
6
6
  let(:notification) { Rpush::Apns::Notification.new }
7
7
  let(:tcp_socket) { double(TCPSocket, setsockopt: nil, close: nil) }
8
- let(:ssl_socket) do double(OpenSSL::SSL::SSLSocket, :sync= => nil, connect: nil,
9
- write: nil, flush: nil, read: nil, close: nil)
10
- end
8
+ let(:ssl_socket) { double(OpenSSL::SSL::SSLSocket, :sync= => nil, connect: nil, write: nil, flush: nil, read: nil, close: nil) }
11
9
  let(:io_double) { double(select: nil) }
12
10
 
13
11
  before do
@@ -4,9 +4,7 @@ describe 'New app loading' do
4
4
  let(:timeout) { 10 }
5
5
  let(:app) { create_app }
6
6
  let(:tcp_socket) { double(TCPSocket, setsockopt: nil, close: nil) }
7
- let(:ssl_socket) do double(OpenSSL::SSL::SSLSocket, :sync= => nil, connect: nil,
8
- write: nil, flush: nil, read: nil, close: nil)
9
- end
7
+ let(:ssl_socket) { double(OpenSSL::SSL::SSLSocket, :sync= => nil, connect: nil, write: nil, flush: nil, read: nil, close: nil) }
10
8
  let(:io_double) { double(select: nil) }
11
9
 
12
10
  before do
@@ -12,4 +12,10 @@ describe Rpush::Client::ActiveRecord::Notification do
12
12
  notification.registration_ids = 'a'
13
13
  notification.registration_ids.should eq ['a']
14
14
  end
15
+
16
+ it 'saves its parent App if required' do
17
+ notification.app = Rpush::Client::ActiveRecord::App.new(name: "aname")
18
+ expect(notification.app).to be_valid
19
+ expect(notification).to be_valid
20
+ end
15
21
  end
@@ -80,6 +80,14 @@ describe Rpush::Daemon::Adm::Delivery do
80
80
  logger.should_receive(:warn).with("[MyApp] bad_request: xyz (InvalidRegistrationId)")
81
81
  expect { perform }.to raise_error
82
82
  end
83
+
84
+ it 'reflects' do
85
+ response.stub(body: JSON.dump('registrationID' => 'canonical123', 'reason' => 'Unregistered'))
86
+ notification.stub(registration_ids: ['1'])
87
+ delivery.should_receive(:reflect).with(:adm_failed_to_recipient, notification, '1', 'Unregistered')
88
+ expect { perform }.to raise_error
89
+ end
90
+
83
91
  end
84
92
 
85
93
  describe 'a 401 (Unauthorized) response' do
@@ -14,9 +14,7 @@ describe Rpush::Daemon::Apns::FeedbackReceiver, 'check_for_feedback' do
14
14
  let(:receiver) { Rpush::Daemon::Apns::FeedbackReceiver.new(app) }
15
15
  let(:feedback) { double }
16
16
  let(:sleeper) { double(Rpush::Daemon::InterruptibleSleep, sleep: nil, start: nil, stop: nil) }
17
- let(:store) do double(Rpush::Daemon::Store::ActiveRecord,
18
- create_apns_feedback: feedback, release_connection: nil)
19
- end
17
+ let(:store) { double(Rpush::Daemon::Store::ActiveRecord, create_apns_feedback: feedback, release_connection: nil) }
20
18
 
21
19
  before do
22
20
  Rpush.config.feedback_poll = poll
@@ -78,8 +78,9 @@ describe Rpush::Daemon::AppRunner, 'start_app' do
78
78
  end
79
79
 
80
80
  describe Rpush::Daemon::AppRunner, 'debug' do
81
- let(:app) do double(Rpush::AppRunnerSpecService::App, id: 1, name: 'test', connections: 1,
82
- environment: 'development', certificate: TEST_CERT, service_name: 'app_runner_spec_service')
81
+ let(:app) do
82
+ double(Rpush::AppRunnerSpecService::App, id: 1, name: 'test', connections: 1,
83
+ environment: 'development', certificate: TEST_CERT, service_name: 'app_runner_spec_service')
83
84
  end
84
85
  let(:logger) { double(Rpush::Logger, info: nil) }
85
86
  let(:store) { double(all_apps: [app], release_connection: nil) }
@@ -99,9 +100,9 @@ describe Rpush::Daemon::AppRunner, 'debug' do
99
100
  end
100
101
 
101
102
  describe Rpush::Daemon::AppRunner do
102
- let(:app) do double(Rpush::AppRunnerSpecService::App, environment: :sandbox,
103
- connections: 1, service_name: 'app_runner_spec_service',
104
- name: 'test')
103
+ let(:app) do
104
+ double(Rpush::AppRunnerSpecService::App, environment: :sandbox,
105
+ connections: 1, service_name: 'app_runner_spec_service', name: 'test')
105
106
  end
106
107
  let(:runner) { Rpush::Daemon::AppRunner.new(app) }
107
108
  let(:logger) { double(Rpush::Logger, info: nil) }
@@ -151,6 +152,20 @@ describe Rpush::Daemon::AppRunner do
151
152
  runner.should_receive(:reflect).with(:notification_enqueued, notification)
152
153
  runner.enqueue([notification])
153
154
  end
155
+
156
+ describe 'a service that batches deliveries' do
157
+ before do
158
+ runner.send(:service).stub(batch_deliveries?: true)
159
+ end
160
+
161
+ describe '1 notification with more than one dispatcher loop' do
162
+ it 'does not raise ArgumentError: invalid slice size' do
163
+ # https://github.com/rpush/rpush/issues/57
164
+ runner.stub(:num_dispatcher_loops).and_return(2)
165
+ runner.enqueue([notification])
166
+ end
167
+ end
168
+ end
154
169
  end
155
170
 
156
171
  describe 'stop' do
@@ -5,9 +5,7 @@ describe Rpush::Daemon::Feeder do
5
5
  let(:notification) { Rpush::Apns::Notification.create!(device_token: "a" * 64, app: app) }
6
6
  let(:logger) { double }
7
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
8
+ let(:store) { double(Rpush::Daemon::Store::ActiveRecord, deliverable_notifications: [notification], release_connection: nil) }
11
9
 
12
10
  before do
13
11
  Rpush.configure do |config|
@@ -224,28 +224,30 @@ describe Rpush::Daemon::Gcm::Delivery do
224
224
  end
225
225
 
226
226
  describe 'all deliveries failed with some as Unavailable or InternalServerError' do
227
- let(:body) do{
228
- 'failure' => 3,
229
- 'success' => 0,
230
- 'results' => [
231
- { 'error' => 'Unavailable' },
232
- { 'error' => 'InvalidDataKey' },
233
- { 'error' => 'Unavailable' }
234
- ] }
227
+ let(:body) do
228
+ { 'failure' => 3,
229
+ 'success' => 0,
230
+ 'results' => [
231
+ { 'error' => 'Unavailable' },
232
+ { 'error' => 'InvalidDataKey' },
233
+ { 'error' => 'Unavailable' }
234
+ ]
235
+ }
235
236
  end
236
237
  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]+\./ }
237
238
  it_should_behave_like 'a notification with some delivery failures'
238
239
  end
239
240
 
240
241
  describe 'some deliveries failed with Unavailable or InternalServerError' do
241
- let(:body) do{
242
- 'failure' => 2,
243
- 'success' => 1,
244
- 'results' => [
245
- { 'error' => 'Unavailable' },
246
- { 'message_id' => '1:000' },
247
- { 'error' => 'InternalServerError' }
248
- ] }
242
+ let(:body) do
243
+ { 'failure' => 2,
244
+ 'success' => 1,
245
+ 'results' => [
246
+ { 'error' => 'Unavailable' },
247
+ { 'message_id' => '1:000' },
248
+ { 'error' => 'InternalServerError' }
249
+ ]
250
+ }
249
251
  end
250
252
  let(:error_description) { /#{Regexp.escape("Failed to deliver to recipients 0, 2. Errors: Unavailable, InternalServerError. 0, 2 will be retried as notification")} [\d]+\./ }
251
253
  it_should_behave_like 'a notification with some delivery failures'
@@ -43,7 +43,8 @@ describe Rpush::Daemon::Store::ActiveRecord::Reconnectable do
43
43
  end
44
44
 
45
45
  let(:error) { adapter_error_class.new("db down!") }
46
- let(:test_double) { TestDouble.new(error, 1) }
46
+ let(:timeout) { ActiveRecord::ConnectionTimeoutError.new("db lazy!") }
47
+ let(:test_doubles) { [TestDouble.new(error, 1), TestDouble.new(timeout, 1)] }
47
48
 
48
49
  before do
49
50
  @logger = double("Logger", info: nil, error: nil, warn: nil)
@@ -51,37 +52,37 @@ describe Rpush::Daemon::Store::ActiveRecord::Reconnectable do
51
52
 
52
53
  ActiveRecord::Base.stub(:clear_all_connections!)
53
54
  ActiveRecord::Base.stub(:establish_connection)
54
- test_double.stub(:sleep)
55
+ test_doubles.each { |td| allow(td).to receive(:sleep) }
55
56
  end
56
57
 
57
58
  it "should log the error raised" do
58
59
  Rpush.logger.should_receive(:error).with(error)
59
- test_double.perform
60
+ test_doubles.each(&:perform)
60
61
  end
61
62
 
62
63
  it "should log that the database is being reconnected" do
63
64
  Rpush.logger.should_receive(:warn).with("Lost connection to database, reconnecting...")
64
- test_double.perform
65
+ test_doubles.each(&:perform)
65
66
  end
66
67
 
67
68
  it "should log the reconnection attempt" do
68
69
  Rpush.logger.should_receive(:warn).with("Attempt 1")
69
- test_double.perform
70
+ test_doubles.each(&:perform)
70
71
  end
71
72
 
72
73
  it "should clear all connections" do
73
74
  ActiveRecord::Base.should_receive(:clear_all_connections!)
74
- test_double.perform
75
+ test_doubles.each(&:perform)
75
76
  end
76
77
 
77
78
  it "should establish a new connection" do
78
79
  ActiveRecord::Base.should_receive(:establish_connection)
79
- test_double.perform
80
+ test_doubles.each(&:perform)
80
81
  end
81
82
 
82
83
  it "should test out the new connection by performing a count" do
83
- Rpush::Client::ActiveRecord::Notification.should_receive(:count)
84
- test_double.perform
84
+ Rpush::Client::ActiveRecord::Notification.should_receive(:count).twice
85
+ test_doubles.each(&:perform)
85
86
  end
86
87
 
87
88
  context "when the reconnection attempt is not successful" do
@@ -97,19 +98,38 @@ describe Rpush::Daemon::Store::ActiveRecord::Reconnectable do
97
98
  Rpush::Client::ActiveRecord::Notification.instance_variable_set("@error", error)
98
99
  end
99
100
 
100
- it "should log the 2nd attempt" do
101
- Rpush.logger.should_receive(:warn).with("Attempt 2")
102
- test_double.perform
103
- end
101
+ describe "error behaviour" do
102
+ it "should log the 2nd attempt" do
103
+ Rpush.logger.should_receive(:warn).with("Attempt 2")
104
+ test_doubles[0].perform
105
+ end
104
106
 
105
- it "should log errors raised when the reconnection is not successful" do
106
- Rpush.logger.should_receive(:error).with(error)
107
- test_double.perform
107
+ it "should log errors raised when the reconnection is not successful" do
108
+ Rpush.logger.should_receive(:error).with(error)
109
+ test_doubles[0].perform
110
+ end
111
+
112
+ it "should sleep to avoid thrashing when the database is down" do
113
+ expect(test_doubles[0]).to receive(:sleep).with(2)
114
+ test_doubles[0].perform
115
+ end
108
116
  end
109
117
 
110
- it "should sleep to avoid thrashing when the database is down" do
111
- test_double.should_receive(:sleep).with(2)
112
- test_double.perform
118
+ describe "timeout behaviour" do
119
+ it "should log the 2nd attempt" do
120
+ Rpush.logger.should_receive(:warn).with("Attempt 2")
121
+ test_doubles[1].perform
122
+ end
123
+
124
+ it "should log errors raised when the reconnection is not successful" do
125
+ Rpush.logger.should_receive(:error).with(error)
126
+ test_doubles[1].perform
127
+ end
128
+
129
+ it "should sleep to avoid thrashing when the database is down" do
130
+ expect(test_doubles[1]).to receive(:sleep).with(2)
131
+ test_doubles[1].perform
132
+ end
113
133
  end
114
134
  end
115
135
  end
@@ -273,7 +273,7 @@ describe Rpush::Daemon::Store::ActiveRecord do
273
273
  describe 'create_apns_feedback' do
274
274
  it 'creates the Feedback record' do
275
275
  Rpush::Client::ActiveRecord::Apns::Feedback.should_receive(:create!).with(
276
- failed_at: time, device_token: 'ab' * 32, app: app)
276
+ failed_at: time, device_token: 'ab' * 32, app_id: app.id)
277
277
  store.create_apns_feedback(time, 'ab' * 32, app)
278
278
  end
279
279
  end
@@ -2,10 +2,7 @@ require 'unit_spec_helper'
2
2
 
3
3
  describe Rpush::Daemon::Wpns::Delivery do
4
4
  let(:app) { Rpush::Wpns::App.create!(name: "MyApp") }
5
- let(:notification) do Rpush::Wpns::Notification.create!(app: app, alert: "test",
6
- uri: "http://some.example/",
7
- deliver_after: Time.now)
8
- end
5
+ let(:notification) { Rpush::Wpns::Notification.create!(app: app, alert: "test", uri: "http://some.example/", deliver_after: Time.now) }
9
6
  let(:logger) { double(error: nil, info: nil, warn: nil) }
10
7
  let(:response) { double(code: 200, header: {}) }
11
8
  let(:http) { double(shutdown: nil, request: response) }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rpush
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.beta2
4
+ version: 2.0.0.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ian Leitch
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-17 00:00:00.000000000 Z
11
+ date: 2014-09-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json