rpush 2.0.0.beta2 → 2.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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