rpush 2.4.0-java → 2.6.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -1
  3. data/README.md +18 -8
  4. data/lib/generators/rpush_migration_generator.rb +1 -0
  5. data/lib/generators/templates/rpush.rb +8 -2
  6. data/lib/generators/templates/rpush_2_0_0_updates.rb +1 -1
  7. data/lib/generators/templates/rpush_2_6_0_updates.rb +10 -0
  8. data/lib/rpush/cli.rb +63 -27
  9. data/lib/rpush/client/active_model.rb +3 -0
  10. data/lib/rpush/client/active_model/apns/notification.rb +1 -1
  11. data/lib/rpush/client/active_model/gcm/notification.rb +1 -0
  12. data/lib/rpush/client/active_model/wns/app.rb +23 -0
  13. data/lib/rpush/client/active_model/wns/notification.rb +28 -0
  14. data/lib/rpush/client/active_model/wpns/notification.rb +11 -6
  15. data/lib/rpush/client/active_record.rb +3 -0
  16. data/lib/rpush/client/active_record/notification.rb +1 -1
  17. data/lib/rpush/client/active_record/wns/app.rb +11 -0
  18. data/lib/rpush/client/active_record/wns/notification.rb +11 -0
  19. data/lib/rpush/client/mongoid.rb +3 -0
  20. data/lib/rpush/client/mongoid/apns/feedback.rb +3 -0
  21. data/lib/rpush/client/mongoid/notification.rb +7 -0
  22. data/lib/rpush/client/mongoid/wns/app.rb +14 -0
  23. data/lib/rpush/client/mongoid/wns/notification.rb +11 -0
  24. data/lib/rpush/client/redis.rb +3 -0
  25. data/lib/rpush/client/redis/notification.rb +1 -0
  26. data/lib/rpush/client/redis/wns/app.rb +14 -0
  27. data/lib/rpush/client/redis/wns/notification.rb +11 -0
  28. data/lib/rpush/configuration.rb +3 -7
  29. data/lib/rpush/daemon.rb +9 -0
  30. data/lib/rpush/daemon/apns/feedback_receiver.rb +5 -0
  31. data/lib/rpush/daemon/app_runner.rb +4 -5
  32. data/lib/rpush/daemon/dispatcher/apns_tcp.rb +47 -12
  33. data/lib/rpush/daemon/dispatcher_loop.rb +5 -0
  34. data/lib/rpush/daemon/feeder.rb +11 -0
  35. data/lib/rpush/daemon/gcm/delivery.rb +2 -2
  36. data/lib/rpush/daemon/interruptible_sleep.rb +8 -3
  37. data/lib/rpush/daemon/loggable.rb +4 -0
  38. data/lib/rpush/daemon/rpc.rb +9 -0
  39. data/lib/rpush/daemon/rpc/client.rb +27 -0
  40. data/lib/rpush/daemon/rpc/server.rb +82 -0
  41. data/lib/rpush/daemon/signal_handler.rb +7 -0
  42. data/lib/rpush/daemon/store/active_record.rb +17 -3
  43. data/lib/rpush/daemon/store/mongoid.rb +2 -2
  44. data/lib/rpush/daemon/store/redis.rb +2 -2
  45. data/lib/rpush/daemon/tcp_connection.rb +2 -2
  46. data/lib/rpush/daemon/wns.rb +9 -0
  47. data/lib/rpush/daemon/wns/delivery.rb +204 -0
  48. data/lib/rpush/embed.rb +15 -13
  49. data/lib/rpush/logger.rb +4 -0
  50. data/lib/rpush/plugin.rb +1 -1
  51. data/lib/rpush/push.rb +2 -11
  52. data/lib/rpush/reflection_collection.rb +15 -17
  53. data/lib/rpush/reflection_public_methods.rb +6 -4
  54. data/lib/rpush/version.rb +1 -1
  55. data/spec/functional/apns_spec.rb +1 -11
  56. data/spec/functional/cli_spec.rb +36 -0
  57. data/spec/functional_spec_helper.rb +11 -1
  58. data/spec/spec_helper.rb +4 -3
  59. data/spec/support/active_record_setup.rb +3 -2
  60. data/spec/unit/client/active_record/apns/notification_spec.rb +1 -1
  61. data/spec/unit/client/active_record/gcm/notification_spec.rb +5 -0
  62. data/spec/unit/configuration_spec.rb +0 -7
  63. data/spec/unit/daemon/adm/delivery_spec.rb +2 -2
  64. data/spec/unit/daemon/app_runner_spec.rb +2 -3
  65. data/spec/unit/daemon/gcm/delivery_spec.rb +1 -1
  66. data/spec/unit/daemon/tcp_connection_spec.rb +1 -1
  67. data/spec/unit/daemon/wns/delivery_spec.rb +171 -0
  68. data/spec/unit/daemon/wpns/delivery_spec.rb +1 -1
  69. data/spec/unit/daemon_spec.rb +2 -0
  70. data/spec/unit/embed_spec.rb +4 -11
  71. data/spec/unit/logger_spec.rb +2 -2
  72. data/spec/unit/push_spec.rb +0 -7
  73. data/spec/unit_spec_helper.rb +1 -1
  74. metadata +20 -2
@@ -1,21 +1,13 @@
1
1
  module Rpush
2
- def self.embed(options = {})
2
+ def self.embed
3
3
  require 'rpush/daemon'
4
4
 
5
- unless options.empty?
6
- warning = "Passing configuration options directly to Rpush.embed is deprecated and will be removed from Rpush 2.5.0. Please setup configuration using Rpush.configure { |config| ... } before calling embed."
7
- Rpush::Deprecation.warn_with_backtrace(warning)
8
- end
9
-
10
5
  if @embed_thread
11
6
  STDERR.puts 'Rpush.embed can only be run once inside this process.'
12
7
  end
13
8
 
14
- config = Rpush::ConfigurationWithoutDefaults.new
15
- options.each { |k, v| config.send("#{k}=", v) }
16
- config.embedded = true
17
- config.foreground = true
18
- Rpush.config.update(config)
9
+ Rpush.config.embedded = true
10
+ Rpush.config.foreground = true
19
11
  Kernel.at_exit { shutdown }
20
12
  @embed_thread = Thread.new { Rpush::Daemon.start }
21
13
  end
@@ -24,6 +16,10 @@ module Rpush
24
16
  return unless Rpush.config.embedded
25
17
  Rpush::Daemon.shutdown
26
18
  @embed_thread.join if @embed_thread
19
+ rescue StandardError => e
20
+ STDERR.puts(e.message)
21
+ STDERR.puts(e.backtrace.join("\n"))
22
+ ensure
27
23
  @embed_thread = nil
28
24
  end
29
25
 
@@ -32,8 +28,14 @@ module Rpush
32
28
  Rpush::Daemon::Synchronizer.sync
33
29
  end
34
30
 
35
- def self.debug
31
+ def self.status
36
32
  return unless Rpush.config.embedded
37
- Rpush::Daemon::AppRunner.debug
33
+ status = Rpush::Daemon::AppRunner.status
34
+ Rpush.logger.info(JSON.pretty_generate(status))
35
+ status
36
+ end
37
+
38
+ def self.debug
39
+ status
38
40
  end
39
41
  end
@@ -11,6 +11,10 @@ module Rpush
11
11
  error('Logging disabled.')
12
12
  end
13
13
 
14
+ def debug(msg, inline = false)
15
+ log(:debug, msg, inline)
16
+ end
17
+
14
18
  def info(msg, inline = false)
15
19
  log(:info, msg, inline)
16
20
  end
@@ -32,7 +32,7 @@ module Rpush
32
32
  Rpush.config.plugin.send("#{@name}=", @config)
33
33
  end
34
34
 
35
- def init(&block) # rubocop:disable Style/TrivialAccessors
35
+ def init(&block)
36
36
  @init_block = block
37
37
  end
38
38
 
@@ -1,17 +1,8 @@
1
1
  module Rpush
2
- def self.push(options = {})
2
+ def self.push
3
3
  require 'rpush/daemon'
4
4
 
5
- unless options.empty?
6
- warning = "Passing configuration options directly to Rpush.push is deprecated and will be removed from Rpush 2.5.0. Please setup configuration using Rpush.configure { |config| ... } before calling push."
7
- Rpush::Deprecation.warn_with_backtrace(warning)
8
- end
9
-
10
- config = Rpush::ConfigurationWithoutDefaults.new
11
- options.each { |k, v| config.send("#{k}=", v) }
12
- config.push = true
13
- Rpush.config.update(config)
14
-
5
+ Rpush.config.push = true
15
6
  Rpush::Daemon.common_init
16
7
  Rpush::Daemon::Synchronizer.sync
17
8
  Rpush::Daemon::Feeder.start(true) # non-blocking
@@ -6,7 +6,7 @@ module Rpush
6
6
  :apns_feedback, :notification_enqueued, :notification_delivered,
7
7
  :notification_failed, :notification_will_retry, :gcm_delivered_to_recipient,
8
8
  :gcm_failed_to_recipient, :gcm_canonical_id, :gcm_invalid_registration_id,
9
- :error, :adm_canonical_id, :adm_failed_to_recipient,
9
+ :error, :adm_canonical_id, :adm_failed_to_recipient, :wns_invalid_channel,
10
10
  :tcp_connection_lost, :ssl_certificate_will_expire, :ssl_certificate_revoked,
11
11
  :notification_id_will_retry, :notification_id_failed
12
12
  ]
@@ -17,30 +17,28 @@ module Rpush
17
17
  class_eval(<<-RUBY, __FILE__, __LINE__)
18
18
  def #{reflection}(*args, &blk)
19
19
  raise "block required" unless block_given?
20
- reflections[:#{reflection}] = blk
20
+ @reflections[:#{reflection}] = blk
21
21
  end
22
22
  RUBY
23
23
  end
24
24
 
25
+ def initialize
26
+ @reflections = {}
27
+ end
28
+
25
29
  def __dispatch(reflection, *args)
26
- reflection = reflection.to_sym
30
+ blk = @reflections[reflection]
27
31
 
28
- unless REFLECTIONS.include?(reflection)
29
- fail NoSuchReflectionError, reflection
30
- end
32
+ if blk
33
+ blk.call(*args)
31
34
 
32
- if DEPRECATIONS.key?(reflection)
33
- replacement, removal_version = DEPRECATIONS[reflection]
34
- Rpush::Deprecation.warn("#{reflection} is deprecated and will be removed in version #{removal_version}. Use #{replacement} instead.")
35
+ if DEPRECATIONS.key?(reflection)
36
+ replacement, removal_version = DEPRECATIONS[reflection]
37
+ Rpush::Deprecation.warn("#{reflection} is deprecated and will be removed in version #{removal_version}. Use #{replacement} instead.")
38
+ end
39
+ elsif !REFLECTIONS.include?(reflection)
40
+ raise NoSuchReflectionError, reflection
35
41
  end
36
-
37
- reflections[reflection].call(*args) if reflections[reflection]
38
- end
39
-
40
- private
41
-
42
- def reflections
43
- @reflections ||= {}
44
42
  end
45
43
  end
46
44
  end
@@ -1,9 +1,11 @@
1
1
  module Rpush
2
- def self.reflect
3
- yield reflection_stack[0] if block_given?
2
+ @reflection_stack ||= [ReflectionCollection.new]
3
+
4
+ class << self
5
+ attr_reader :reflection_stack
4
6
  end
5
7
 
6
- def self.reflection_stack
7
- @reflection_stack ||= [ReflectionCollection.new]
8
+ def self.reflect
9
+ yield reflection_stack[0] if block_given?
8
10
  end
9
11
  end
@@ -1,3 +1,3 @@
1
1
  module Rpush
2
- VERSION = '2.4.0'
2
+ VERSION = '2.6.0'
3
3
  end
@@ -11,7 +11,7 @@ describe 'APNs' do
11
11
 
12
12
  before do
13
13
  Rpush.config.push_poll = 0.5
14
- stub_tcp_connection
14
+ stub_tcp_connection(tcp_socket, ssl_socket, io_double)
15
15
  end
16
16
 
17
17
  def create_app
@@ -32,12 +32,6 @@ describe 'APNs' do
32
32
  notification
33
33
  end
34
34
 
35
- def stub_tcp_connection
36
- allow_any_instance_of(Rpush::Daemon::TcpConnection).to receive_messages(connect_socket: [tcp_socket, ssl_socket])
37
- allow_any_instance_of(Rpush::Daemon::TcpConnection).to receive_messages(setup_ssl_context: double.as_null_object)
38
- stub_const('Rpush::Daemon::TcpConnection::IO', io_double)
39
- end
40
-
41
35
  def wait
42
36
  sleep 0.1
43
37
  end
@@ -71,10 +65,6 @@ describe 'APNs' do
71
65
  end
72
66
  end
73
67
 
74
- def timeout(&blk)
75
- Timeout.timeout(10, &blk)
76
- end
77
-
78
68
  it 'delivers a notification successfully' do
79
69
  notification = create_notification
80
70
  expect do
@@ -0,0 +1,36 @@
1
+ require 'functional_spec_helper'
2
+
3
+ describe Rpush::CLI do
4
+ def create_app
5
+ app = Rpush::Apns::App.new
6
+ app.certificate = TEST_CERT
7
+ app.name = 'test'
8
+ app.environment = 'sandbox'
9
+ app.save!
10
+ app
11
+ end
12
+
13
+ describe 'status' do
14
+ let(:tcp_socket) { double(TCPSocket, setsockopt: nil, close: nil) }
15
+ let(:ssl_socket) { double(OpenSSL::SSL::SSLSocket, :sync= => nil, connect: nil, write: nil, flush: nil, read: nil, close: nil) }
16
+ let(:io_double) { double(select: nil) }
17
+
18
+ before do
19
+ create_app
20
+ stub_tcp_connection(tcp_socket, ssl_socket, io_double)
21
+ Rpush.embed
22
+
23
+ timeout do
24
+ Thread.pass until File.exist?(Rpush::Daemon::Rpc.socket_path)
25
+ end
26
+ end
27
+
28
+ after { timeout { Rpush.shutdown } }
29
+
30
+ it 'prints the status' do
31
+ expect(subject).to receive(:configure_rpush) { true }
32
+ expect(subject).to receive(:puts).with(/app_runners:/)
33
+ subject.status
34
+ end
35
+ end
36
+ end
@@ -4,7 +4,17 @@ require 'database_cleaner'
4
4
  DatabaseCleaner.strategy = :truncation
5
5
 
6
6
  def functional_example?(metadata)
7
- metadata[:file_path] =~ /spec\/functional/
7
+ metadata[:file_path] =~ %r{/spec/functional/}
8
+ end
9
+
10
+ def timeout(&blk)
11
+ Timeout.timeout(10, &blk)
12
+ end
13
+
14
+ def stub_tcp_connection(tcp_socket, ssl_socket, io_double)
15
+ allow_any_instance_of(Rpush::Daemon::TcpConnection).to receive_messages(connect_socket: [tcp_socket, ssl_socket])
16
+ allow_any_instance_of(Rpush::Daemon::TcpConnection).to receive_messages(setup_ssl_context: double.as_null_object)
17
+ stub_const('Rpush::Daemon::TcpConnection::IO', io_double)
8
18
  end
9
19
 
10
20
  RSpec.configure do |config|
@@ -3,9 +3,6 @@ def client
3
3
  (ENV['CLIENT'] || :active_record).to_sym
4
4
  end
5
5
 
6
- require 'bundler/setup'
7
- Bundler.require(:default)
8
-
9
6
  if !ENV['TRAVIS'] || (ENV['TRAVIS'] && ENV['QUALITY'] == 'true')
10
7
  begin
11
8
  require './spec/support/simplecov_helper'
@@ -16,6 +13,9 @@ if !ENV['TRAVIS'] || (ENV['TRAVIS'] && ENV['QUALITY'] == 'true')
16
13
  end
17
14
  end
18
15
 
16
+ require 'timecop'
17
+ require 'activerecord-jdbc-adapter' if defined? JRUBY_VERSION
18
+
19
19
  require 'rpush'
20
20
  require 'rpush/daemon'
21
21
  require 'rpush/client/redis'
@@ -42,6 +42,7 @@ RPUSH_ROOT = '/tmp/rails_root'
42
42
 
43
43
  Rpush.configure do |config|
44
44
  config.client = client
45
+ config.log_level = ::Logger::Severity::DEBUG
45
46
  end
46
47
 
47
48
  RPUSH_CLIENT = Rpush.config.client
@@ -29,11 +29,12 @@ ActiveRecord::Base.establish_connection(db_config[SPEC_ADAPTER])
29
29
  require 'generators/templates/add_rpush'
30
30
  require 'generators/templates/rpush_2_0_0_updates'
31
31
  require 'generators/templates/rpush_2_1_0_updates'
32
+ require 'generators/templates/rpush_2_6_0_updates'
32
33
 
33
- migrations = [AddRpush, Rpush200Updates, Rpush210Updates]
34
+ migrations = [AddRpush, Rpush200Updates, Rpush210Updates, Rpush260Updates]
34
35
 
35
36
  unless ENV['TRAVIS']
36
- migrations.reverse.each do |m|
37
+ migrations.reverse_each do |m|
37
38
  begin
38
39
  m.down
39
40
  rescue ActiveRecord::StatementInvalid => e
@@ -217,7 +217,7 @@ describe Rpush::Client::ActiveRecord::Apns::Notification, "bug #31" do
217
217
 
218
218
  it 'does confuse a JSON looking string as JSON if the alert_is_json attribute is not present' do
219
219
  notification = Rpush::Client::ActiveRecord::Apns::Notification.new
220
- allow(notification).to receive_messages(:has_attribute? => false)
220
+ allow(notification).to receive_messages(has_attribute?: false)
221
221
  notification.alert = "{\"one\":2}"
222
222
  expect(notification.alert).to eq('one' => 2)
223
223
  end
@@ -31,4 +31,9 @@ describe Rpush::Client::ActiveRecord::Gcm::Notification do
31
31
  notification.expiry = 100
32
32
  expect(notification.as_json['time_to_live']).to eq 100
33
33
  end
34
+
35
+ it 'includes content_available in the payload' do
36
+ notification.content_available = true
37
+ expect(notification.as_json['content_available']).to eq true
38
+ end
34
39
  end if active_record?
@@ -43,11 +43,4 @@ describe Rpush::Configuration do
43
43
  Rpush.config.redis_options = { hi: :mom }
44
44
  expect(Modis.redis_options).to eq(hi: :mom)
45
45
  end
46
-
47
- it 'deprecates feedback_poll=' do
48
- expect(Rpush::Deprecation).to receive(:warn).with(/feedback_poll= is deprecated/)
49
- expect do
50
- Rpush.config.feedback_poll = 123
51
- end.to change { Rpush.config.apns.feedback_receiver.frequency }.to(123)
52
- end
53
46
  end
@@ -78,14 +78,14 @@ describe Rpush::Daemon::Adm::Delivery do
78
78
  it 'logs that the notification was not delivered' do
79
79
  allow(response).to receive_messages(body: JSON.dump('reason' => 'InvalidRegistrationId'))
80
80
  expect(logger).to receive(:warn).with("[MyApp] bad_request: xyz (InvalidRegistrationId)")
81
- expect { perform }.to raise_error
81
+ expect { perform }.to raise_error(Rpush::DeliveryError)
82
82
  end
83
83
 
84
84
  it 'reflects' do
85
85
  allow(response).to receive_messages(body: JSON.dump('registrationID' => 'canonical123', 'reason' => 'Unregistered'))
86
86
  allow(notification).to receive_messages(registration_ids: ['1'])
87
87
  expect(delivery).to receive(:reflect).with(:adm_failed_to_recipient, notification, '1', 'Unregistered')
88
- expect { perform }.to raise_error
88
+ expect { perform }.to raise_error(Rpush::DeliveryError)
89
89
  end
90
90
  end
91
91
 
@@ -94,9 +94,8 @@ describe Rpush::Daemon::AppRunner, 'debug' do
94
94
 
95
95
  after { Rpush::Daemon::AppRunner.stop_app(app.id) }
96
96
 
97
- it 'prints debug app states to the log' do
98
- expect(Rpush.logger).to receive(:info).with(kind_of(String))
99
- Rpush::Daemon::AppRunner.debug
97
+ it 'returns the app runner status' do
98
+ expect(Rpush::Daemon::AppRunner.status.key?(:app_runners)).to eq(true)
100
99
  end
101
100
  end
102
101
 
@@ -16,7 +16,7 @@ describe Rpush::Daemon::Gcm::Delivery do
16
16
  end
17
17
 
18
18
  def perform_with_rescue
19
- expect { perform }.to raise_error
19
+ expect { perform }.to raise_error(StandardError)
20
20
  end
21
21
 
22
22
  before do
@@ -126,7 +126,7 @@ describe Rpush::Daemon::TcpConnection do
126
126
  end
127
127
 
128
128
  it 'logs that the certificate has been revoked' do
129
- expect(logger).to receive(:warn).with('[Connection 0] Certificate has been revoked.')
129
+ expect(logger).to receive(:error).with('[Connection 0] Certificate has been revoked.')
130
130
  expect { connection.connect }.to raise_error(Rpush::Daemon::TcpConnectionError, 'OpenSSL::SSL::SSLError, certificate revoked')
131
131
  end
132
132
  end
@@ -0,0 +1,171 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Rpush::Daemon::Wns::Delivery do
4
+ let(:app) { Rpush::Wns::App.create!(name: "MyApp", client_id: "someclient", client_secret: "somesecret", access_token: "access_token", access_token_expiration: Time.now + (60 * 10)) }
5
+ let(:notification) { Rpush::Wns::Notification.create!(app: app, data: { title: "MyApp", body: "Example notification", param: "/param1" }, uri: "http://some.example/", deliver_after: Time.now) }
6
+ let(:logger) { double(error: nil, info: nil, warn: nil) }
7
+ let(:response) { double(code: 200, header: {}, body: '') }
8
+ let(:http) { double(shutdown: nil, request: response) }
9
+ let(:now) { Time.parse('2012-10-14 00:00:00') }
10
+ let(:batch) { double(mark_failed: nil, mark_delivered: nil, mark_retryable: nil, notification_processed: nil) }
11
+ let(:delivery) { Rpush::Daemon::Wns::Delivery.new(app, http, notification, batch) }
12
+ let(:store) { double(create_wpns_notification: double(id: 2), update_app: nil) }
13
+
14
+ def perform
15
+ delivery.perform
16
+ end
17
+
18
+ def perform_with_rescue
19
+ expect { perform }.to raise_error(StandardError)
20
+ end
21
+
22
+ before do
23
+ allow(delivery).to receive_messages(reflect: nil)
24
+ allow(Rpush::Daemon).to receive_messages(store: store)
25
+ allow(Time).to receive_messages(now: now)
26
+ allow(Rpush).to receive_messages(logger: logger)
27
+ end
28
+
29
+ shared_examples_for "an notification with some delivery faliures" do
30
+ let(:new_notification) { Rpush::Wns::Notification.where('id != ?', notification.id).first }
31
+
32
+ before { allow(response).to receive_messages(body: JSON.dump(body)) }
33
+
34
+ it "marks the original notification falied" do
35
+ expect(delivery).to receive(:mark_failed) do |error|
36
+ expect(error.message).to match(error_description)
37
+ end
38
+ perform_with_rescue
39
+ end
40
+
41
+ it "raises a DeliveryError" do
42
+ expect { perform }.to raise_error(Rpush::DeliveryError)
43
+ end
44
+ end
45
+
46
+ describe "an 200 response without an access token" do
47
+ before do
48
+ allow(app).to receive_messages(access_token_expired?: true)
49
+ allow(response).to receive_messages(to_hash: {}, code: 200, body: JSON.dump(access_token: "dummy_access_token", expires_in: 60))
50
+ end
51
+
52
+ it 'set the access token for the app' do
53
+ expect(delivery).to receive(:update_access_token).with("access_token" => "dummy_access_token", "expires_in" => 60)
54
+ expect(store).to receive(:update_app).with app
55
+ perform
56
+ end
57
+ end
58
+
59
+ describe "an 200 response with a valid access token" do
60
+ before do
61
+ allow(response).to receive_messages(code: 200)
62
+ end
63
+
64
+ it "marks the notification as delivered if delivered successfully to all devices" do
65
+ allow(response).to receive_messages(body: JSON.dump("failure" => 0))
66
+ allow(response).to receive_messages(to_hash: { "X-WNS-Status" => ["received"] })
67
+ expect(batch).to receive(:mark_delivered).with(notification)
68
+ perform
69
+ end
70
+
71
+ it "retries the notification when the queue is full" do
72
+ allow(response).to receive_messages(body: JSON.dump("failure" => 0))
73
+ allow(response).to receive_messages(to_hash: { "X-WNS-Status" => ["channelthrottled"] })
74
+ expect(batch).to receive(:mark_retryable).with(notification, Time.now + (60 * 10))
75
+ perform
76
+ end
77
+
78
+ it "marks the notification as failed if the notification is suppressed" do
79
+ allow(response).to receive_messages(body: JSON.dump("faliure" => 0))
80
+ allow(response).to receive_messages(to_hash: { "X-WNS-Status" => ["dropped"], "X-WNS-Error-Description" => "" })
81
+ error = Rpush::DeliveryError.new(200, notification.id, 'Notification was received but suppressed by the service ().')
82
+ expect(delivery).to receive(:mark_failed).with(error)
83
+ perform_with_rescue
84
+ end
85
+ end
86
+
87
+ describe "an 400 response" do
88
+ before { allow(response).to receive_messages(code: 400) }
89
+ it "marks notifications as failed" do
90
+ error = Rpush::DeliveryError.new(400, notification.id, 'One or more headers were specified incorrectly or conflict with another header.')
91
+ expect(delivery).to receive(:mark_failed).with(error)
92
+ perform_with_rescue
93
+ end
94
+ end
95
+
96
+ describe "an 404 response" do
97
+ before { allow(response).to receive_messages(code: 404) }
98
+ it "marks notifications as failed" do
99
+ error = Rpush::DeliveryError.new(404, notification.id, 'The channel URI is not valid or is not recognized by WNS.')
100
+ expect(delivery).to receive(:mark_failed).with(error)
101
+ perform_with_rescue
102
+ end
103
+ end
104
+
105
+ describe "an 405 response" do
106
+ before { allow(response).to receive_messages(code: 405) }
107
+ it "marks notifications as failed" do
108
+ error = Rpush::DeliveryError.new(405, notification.id, 'Invalid method (GET, CREATE); only POST (Windows or Windows Phone) or DELETE (Windows Phone only) is allowed.')
109
+ expect(delivery).to receive(:mark_failed).with(error)
110
+ perform_with_rescue
111
+ end
112
+ end
113
+
114
+ describe "an 406 response" do
115
+ before { allow(response).to receive_messages(code: 406) }
116
+
117
+ it "retries the notification" do
118
+ expect(batch).to receive(:mark_retryable).with(notification, Time.now + (60 * 60))
119
+ perform
120
+ end
121
+
122
+ it "logs a warning that the notification will be retried" do
123
+ notification.retries = 1
124
+ notification.deliver_after = now + 2
125
+ expect(logger).to receive(:warn).with("[MyApp] Per-day throttling limit reached. Notification #{notification.id} will be retried after 2012-10-14 00:00:02 (retry 1).")
126
+ perform
127
+ end
128
+ end
129
+
130
+ describe "an 412 response" do
131
+ before { allow(response).to receive_messages(code: 412) }
132
+
133
+ it "retries the notification" do
134
+ expect(batch).to receive(:mark_retryable).with(notification, Time.now + (60 * 60))
135
+ perform
136
+ end
137
+
138
+ it "logs a warning that the notification will be retried" do
139
+ notification.retries = 1
140
+ notification.deliver_after = now + 2
141
+ expect(logger).to receive(:warn).with("[MyApp] Device unreachable. Notification #{notification.id} will be retried after 2012-10-14 00:00:02 (retry 1).")
142
+ perform
143
+ end
144
+ end
145
+
146
+ describe "an 503 response" do
147
+ before { allow(response).to receive_messages(code: 503) }
148
+
149
+ it "retries the notification exponentially" do
150
+ expect(delivery).to receive(:mark_retryable_exponential).with(notification)
151
+ perform
152
+ end
153
+
154
+ it 'logs a warning that the notification will be retried.' do
155
+ notification.retries = 1
156
+ notification.deliver_after = now + 2
157
+ expect(logger).to receive(:warn).with("[MyApp] Service Unavailable. Notification #{notification.id} will be retried after 2012-10-14 00:00:02 (retry 1).")
158
+ perform
159
+ end
160
+ end
161
+
162
+ describe 'an un-handled response' do
163
+ before { allow(response).to receive_messages(code: 418) }
164
+
165
+ it 'marks the notification as failed' do
166
+ error = Rpush::DeliveryError.new(418, notification.id, "I'm a Teapot")
167
+ expect(delivery).to receive(:mark_failed).with(error)
168
+ perform_with_rescue
169
+ end
170
+ end
171
+ end