rpush 8.0.0 → 9.1.0

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 (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +20 -6
  3. data/README.md +8 -65
  4. data/lib/generators/templates/rpush.rb +9 -16
  5. data/lib/rpush/client/active_model/fcm/notification.rb +1 -0
  6. data/lib/rpush/client/active_model.rb +0 -4
  7. data/lib/rpush/client/active_record/notification.rb +2 -0
  8. data/lib/rpush/client/active_record.rb +0 -3
  9. data/lib/rpush/client/redis.rb +0 -3
  10. data/lib/rpush/configuration.rb +2 -19
  11. data/lib/rpush/daemon/service_config_methods.rb +0 -2
  12. data/lib/rpush/daemon/store/active_record.rb +2 -14
  13. data/lib/rpush/daemon/store/interface.rb +2 -2
  14. data/lib/rpush/daemon/store/redis.rb +2 -11
  15. data/lib/rpush/daemon.rb +0 -10
  16. data/lib/rpush/reflection_collection.rb +1 -2
  17. data/lib/rpush/version.rb +2 -2
  18. data/lib/rpush.rb +0 -1
  19. data/spec/functional/cli_spec.rb +41 -15
  20. data/spec/functional/embed_spec.rb +57 -26
  21. data/spec/functional/retry_spec.rb +21 -4
  22. data/spec/functional/synchronization_spec.rb +1 -1
  23. data/spec/functional_spec_helper.rb +0 -6
  24. data/spec/spec_helper.rb +17 -7
  25. data/spec/unit/client/active_record/shared/app.rb +1 -1
  26. data/spec/unit/client/shared/fcm/notification.rb +6 -1
  27. data/spec/unit/daemon/shared/store.rb +0 -42
  28. metadata +61 -61
  29. data/lib/rpush/apns_feedback.rb +0 -18
  30. data/lib/rpush/client/active_model/gcm/app.rb +0 -19
  31. data/lib/rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +0 -14
  32. data/lib/rpush/client/active_model/gcm/notification.rb +0 -62
  33. data/lib/rpush/client/active_record/gcm/app.rb +0 -11
  34. data/lib/rpush/client/active_record/gcm/notification.rb +0 -11
  35. data/lib/rpush/client/redis/gcm/app.rb +0 -11
  36. data/lib/rpush/client/redis/gcm/notification.rb +0 -11
  37. data/lib/rpush/daemon/apns/delivery.rb +0 -43
  38. data/lib/rpush/daemon/apns/feedback_receiver.rb +0 -91
  39. data/lib/rpush/daemon/apns.rb +0 -17
  40. data/lib/rpush/daemon/dispatcher/apns_tcp.rb +0 -152
  41. data/lib/rpush/daemon/dispatcher/tcp.rb +0 -22
  42. data/lib/rpush/daemon/gcm/delivery.rb +0 -241
  43. data/lib/rpush/daemon/gcm.rb +0 -9
  44. data/lib/rpush/daemon/tcp_connection.rb +0 -190
  45. data/spec/functional/apns_spec.rb +0 -162
  46. data/spec/functional/gcm_priority_spec.rb +0 -40
  47. data/spec/functional/gcm_spec.rb +0 -46
  48. data/spec/functional/new_app_spec.rb +0 -44
  49. data/spec/unit/apns_feedback_spec.rb +0 -39
  50. data/spec/unit/client/active_record/gcm/app_spec.rb +0 -6
  51. data/spec/unit/client/active_record/gcm/notification_spec.rb +0 -14
  52. data/spec/unit/client/redis/gcm/app_spec.rb +0 -5
  53. data/spec/unit/client/redis/gcm/notification_spec.rb +0 -5
  54. data/spec/unit/client/shared/gcm/app.rb +0 -4
  55. data/spec/unit/client/shared/gcm/notification.rb +0 -77
  56. data/spec/unit/daemon/apns/delivery_spec.rb +0 -108
  57. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +0 -137
  58. data/spec/unit/daemon/dispatcher/tcp_spec.rb +0 -32
  59. data/spec/unit/daemon/gcm/delivery_spec.rb +0 -387
  60. data/spec/unit/daemon/tcp_connection_spec.rb +0 -293
@@ -1,241 +0,0 @@
1
- module Rpush
2
- module Daemon
3
- module Gcm
4
- # https://firebase.google.com/docs/cloud-messaging/server
5
- class Delivery < Rpush::Daemon::Delivery
6
- include MultiJsonHelper
7
-
8
- host = 'https://fcm.googleapis.com'
9
- FCM_URI = URI.parse("#{host}/fcm/send")
10
- UNAVAILABLE_STATES = %w(Unavailable BadGateway InternalServerError)
11
- INVALID_REGISTRATION_ID_STATES = %w(InvalidRegistration MismatchSenderId NotRegistered InvalidPackageName)
12
-
13
- def initialize(app, http, notification, batch)
14
- @app = app
15
- @http = http
16
- @notification = notification
17
- @batch = batch
18
- end
19
-
20
- def perform
21
- handle_response(do_post)
22
- rescue SocketError => error
23
- mark_retryable(@notification, Time.now + 10.seconds, error)
24
- raise
25
- rescue StandardError => error
26
- mark_failed(error)
27
- raise
28
- ensure
29
- @batch.notification_processed
30
- end
31
-
32
- protected
33
-
34
- def handle_response(response)
35
- case response.code.to_i
36
- when 200
37
- ok(response)
38
- when 400
39
- bad_request
40
- when 401
41
- unauthorized
42
- when 500
43
- internal_server_error(response)
44
- when 502
45
- bad_gateway(response)
46
- when 503
47
- service_unavailable(response)
48
- when 500..599
49
- other_5xx_error(response)
50
- else
51
- fail Rpush::DeliveryError.new(response.code.to_i, @notification.id, Rpush::Daemon::HTTP_STATUS_CODES[response.code.to_i])
52
- end
53
- end
54
-
55
- def ok(response)
56
- results = process_response(response)
57
- handle_successes(results.successes)
58
-
59
- if results.failures.any?
60
- handle_failures(results.failures, response)
61
- else
62
- mark_delivered
63
- log_info("#{@notification.id} sent to #{@notification.registration_ids.join(', ')}")
64
- end
65
- end
66
-
67
- def process_response(response)
68
- body = multi_json_load(response.body)
69
- results = Results.new(body['results'], @notification.registration_ids)
70
- results.process(invalid: INVALID_REGISTRATION_ID_STATES, unavailable: UNAVAILABLE_STATES)
71
- results
72
- end
73
-
74
- def handle_successes(successes)
75
- successes.each do |result|
76
- reflect(:gcm_delivered_to_recipient, @notification, result[:registration_id])
77
- next unless result.key?(:canonical_id)
78
- reflect(:gcm_canonical_id, result[:registration_id], result[:canonical_id])
79
- end
80
- end
81
-
82
- def handle_failures(failures, response)
83
- if failures[:unavailable].count == @notification.registration_ids.count
84
- retry_delivery(@notification, response)
85
- log_warn("All recipients unavailable. #{retry_message}")
86
- else
87
- if failures[:unavailable].any?
88
- unavailable_idxs = failures[:unavailable].map { |result| result[:index] }
89
- new_notification = create_new_notification(response, unavailable_idxs)
90
- failures.description += " #{unavailable_idxs.join(', ')} will be retried as notification #{new_notification.id}."
91
- end
92
- handle_errors(failures)
93
- fail Rpush::DeliveryError.new(nil, @notification.id, failures.description)
94
- end
95
- end
96
-
97
- def handle_errors(failures)
98
- failures.each do |result|
99
- reflect(:gcm_failed_to_recipient, @notification, result[:error], result[:registration_id])
100
- end
101
- failures[:invalid].each do |result|
102
- reflect(:gcm_invalid_registration_id, @app, result[:error], result[:registration_id])
103
- end
104
- end
105
-
106
- def create_new_notification(response, unavailable_idxs)
107
- attrs = { 'app_id' => @notification.app_id, 'collapse_key' => @notification.collapse_key, 'delay_while_idle' => @notification.delay_while_idle }
108
- registration_ids = @notification.registration_ids.values_at(*unavailable_idxs)
109
- Rpush::Daemon.store.create_gcm_notification(attrs, @notification.data,
110
- registration_ids, deliver_after_header(response), @app)
111
- end
112
-
113
- def bad_request
114
- fail Rpush::DeliveryError.new(400, @notification.id, 'GCM failed to parse the JSON request. Possibly an Rpush bug, please open an issue.')
115
- end
116
-
117
- def unauthorized
118
- fail Rpush::DeliveryError.new(401, @notification.id, 'Unauthorized, check your App auth_key.')
119
- end
120
-
121
- def internal_server_error(response)
122
- retry_delivery(@notification, response)
123
- log_warn("GCM responded with an Internal Error. " + retry_message)
124
- end
125
-
126
- def bad_gateway(response)
127
- retry_delivery(@notification, response)
128
- log_warn("GCM responded with a Bad Gateway Error. " + retry_message)
129
- end
130
-
131
- def service_unavailable(response)
132
- retry_delivery(@notification, response)
133
- log_warn("GCM responded with an Service Unavailable Error. " + retry_message)
134
- end
135
-
136
- def other_5xx_error(response)
137
- retry_delivery(@notification, response)
138
- log_warn("GCM responded with a 5xx Error. " + retry_message)
139
- end
140
-
141
- def deliver_after_header(response)
142
- Rpush::Daemon::RetryHeaderParser.parse(response.header['retry-after'])
143
- end
144
-
145
- def retry_delivery(notification, response)
146
- time = deliver_after_header(response)
147
- if time
148
- mark_retryable(notification, time)
149
- else
150
- mark_retryable_exponential(notification)
151
- end
152
- end
153
-
154
- def retry_message
155
- "Notification #{@notification.id} will be retried after #{@notification.deliver_after.strftime('%Y-%m-%d %H:%M:%S')} (retry #{@notification.retries})."
156
- end
157
-
158
- def do_post
159
- post = Net::HTTP::Post.new(FCM_URI.path, 'Content-Type' => 'application/json',
160
- 'Authorization' => "key=#{@app.auth_key}")
161
- post.body = @notification.as_json.to_json
162
- @http.request(FCM_URI, post)
163
- end
164
- end
165
-
166
- class Results
167
- attr_reader :successes, :failures
168
-
169
- def initialize(results_data, registration_ids)
170
- @results_data = results_data
171
- @registration_ids = registration_ids
172
- end
173
-
174
- def process(failure_partitions = {}) # rubocop:disable Metrics/AbcSize
175
- @successes = []
176
- @failures = Failures.new
177
- failure_partitions.each_key do |category|
178
- failures[category] = []
179
- end
180
-
181
- @results_data.each_with_index do |result, index|
182
- entry = {
183
- registration_id: @registration_ids[index],
184
- index: index
185
- }
186
- if result['message_id']
187
- entry[:canonical_id] = result['registration_id'] if result['registration_id'].present?
188
- successes << entry
189
- elsif result['error']
190
- entry[:error] = result['error']
191
- failures << entry
192
- failure_partitions.each do |category, error_states|
193
- failures[category] << entry if error_states.include?(result['error'])
194
- end
195
- end
196
- end
197
- failures.all_failed = failures.count == @registration_ids.count
198
- end
199
- end
200
-
201
- class Failures < Hash
202
- include Enumerable
203
- attr_writer :all_failed, :description
204
-
205
- def initialize
206
- super[:all] = []
207
- end
208
-
209
- def each
210
- self[:all].each { |x| yield x }
211
- end
212
-
213
- def <<(item)
214
- self[:all] << item
215
- end
216
-
217
- def description
218
- @description ||= describe
219
- end
220
-
221
- def any?
222
- self[:all].any?
223
- end
224
-
225
- private
226
-
227
- def describe
228
- if @all_failed
229
- error_description = "Failed to deliver to all recipients."
230
- else
231
- index_list = map { |item| item[:index] }
232
- error_description = "Failed to deliver to recipients #{index_list.join(', ')}."
233
- end
234
-
235
- error_list = map { |item| item[:error] }
236
- error_description + " Errors: #{error_list.join(', ')}."
237
- end
238
- end
239
- end
240
- end
241
- end
@@ -1,9 +0,0 @@
1
- module Rpush
2
- module Daemon
3
- module Gcm
4
- extend ServiceConfigMethods
5
-
6
- dispatcher :http
7
- end
8
- end
9
- end
@@ -1,190 +0,0 @@
1
- module Rpush
2
- module Daemon
3
- class TcpConnectionError < StandardError; end
4
-
5
- class TcpConnection
6
- include Reflectable
7
- include Loggable
8
-
9
- OSX_TCP_KEEPALIVE = 0x10 # Defined in <netinet/tcp.h>
10
- KEEPALIVE_INTERVAL = 5
11
- KEEPALIVE_IDLE = 5
12
- KEEPALIVE_MAX_FAIL_PROBES = 1
13
- TCP_ERRORS = [SystemCallError, OpenSSL::OpenSSLError, IOError]
14
-
15
- attr_accessor :last_touch
16
- attr_reader :host, :port
17
-
18
- def self.idle_period
19
- 30.minutes
20
- end
21
-
22
- def initialize(app, host, port)
23
- @app = app
24
- @host = host
25
- @port = port
26
- @certificate = app.certificate
27
- @password = app.password
28
- @connected = false
29
- @connection_callbacks = []
30
- touch
31
- end
32
-
33
- def on_connect(&blk)
34
- raise 'already connected' if @connected
35
- @connection_callbacks << blk
36
- end
37
-
38
- def connect
39
- @ssl_context = setup_ssl_context
40
- @tcp_socket, @ssl_socket = connect_socket
41
- @connected = true
42
-
43
- @connection_callbacks.each do |blk|
44
- begin
45
- blk.call
46
- rescue StandardError => e
47
- log_error(e)
48
- end
49
- end
50
-
51
- @connection_callbacks.clear
52
- end
53
-
54
- def close
55
- @ssl_socket.close if @ssl_socket
56
- @tcp_socket.close if @tcp_socket
57
- rescue IOError # rubocop:disable HandleExceptions
58
- end
59
-
60
- def read(num_bytes)
61
- @ssl_socket.read(num_bytes) if @ssl_socket
62
- end
63
-
64
- def select(timeout)
65
- IO.select([@ssl_socket], nil, nil, timeout) if @ssl_socket
66
- end
67
-
68
- def write(data)
69
- connect unless @connected
70
- reconnect_idle if idle_period_exceeded?
71
-
72
- retry_count = 0
73
-
74
- begin
75
- write_data(data)
76
- rescue *TCP_ERRORS => e
77
- retry_count += 1
78
-
79
- if retry_count == 1
80
- log_error("Lost connection to #{@host}:#{@port} (#{e.class.name}, #{e.message}), reconnecting...")
81
- reflect(:tcp_connection_lost, @app, e)
82
- end
83
-
84
- if retry_count <= 3
85
- reconnect_with_rescue
86
- sleep 1
87
- retry
88
- else
89
- raise TcpConnectionError, "#{@app.name} tried #{retry_count - 1} times to reconnect but failed (#{e.class.name}, #{e.message})."
90
- end
91
- end
92
- end
93
-
94
- def reconnect_with_rescue
95
- reconnect
96
- rescue StandardError => e
97
- log_error(e)
98
- end
99
-
100
- def reconnect
101
- close
102
- @tcp_socket, @ssl_socket = connect_socket
103
- end
104
-
105
- protected
106
-
107
- def reconnect_idle
108
- log_info("Idle period exceeded, reconnecting...")
109
- reconnect
110
- end
111
-
112
- def idle_period_exceeded?
113
- Time.now - last_touch > self.class.idle_period
114
- end
115
-
116
- def write_data(data)
117
- @ssl_socket.write(data)
118
- @ssl_socket.flush
119
- touch
120
- end
121
-
122
- def touch
123
- self.last_touch = Time.now
124
- end
125
-
126
- def setup_ssl_context
127
- ssl_context = OpenSSL::SSL::SSLContext.new
128
- ssl_context.key = OpenSSL::PKey::RSA.new(@certificate, @password)
129
- ssl_context.cert = OpenSSL::X509::Certificate.new(@certificate)
130
- ssl_context
131
- end
132
-
133
- def connect_socket
134
- touch
135
- check_certificate_expiration
136
-
137
- tcp_socket = TCPSocket.new(@host, @port)
138
- tcp_socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
139
- tcp_socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true)
140
-
141
- # Linux
142
- if [:SOL_TCP, :TCP_KEEPIDLE, :TCP_KEEPINTVL, :TCP_KEEPCNT].all? { |c| Socket.const_defined?(c) }
143
- tcp_socket.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPIDLE, KEEPALIVE_IDLE)
144
- tcp_socket.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPINTVL, KEEPALIVE_INTERVAL)
145
- tcp_socket.setsockopt(Socket::SOL_TCP, Socket::TCP_KEEPCNT, KEEPALIVE_MAX_FAIL_PROBES)
146
- end
147
-
148
- # OSX
149
- if RUBY_PLATFORM =~ /darwin/
150
- tcp_socket.setsockopt(Socket::IPPROTO_TCP, OSX_TCP_KEEPALIVE, KEEPALIVE_IDLE)
151
- end
152
-
153
- ssl_socket = OpenSSL::SSL::SSLSocket.new(tcp_socket, @ssl_context)
154
- ssl_socket.sync = true
155
- ssl_socket.connect
156
- [tcp_socket, ssl_socket]
157
- rescue *TCP_ERRORS => error
158
- if error.message =~ /certificate revoked/i
159
- log_error('Certificate has been revoked.')
160
- reflect(:ssl_certificate_revoked, @app, error)
161
- end
162
- raise TcpConnectionError, "#{error.class.name}, #{error.message}"
163
- end
164
-
165
- def check_certificate_expiration
166
- cert = @ssl_context.cert
167
- if certificate_expired?
168
- log_error(certificate_msg('expired'))
169
- raise Rpush::CertificateExpiredError.new(@app, cert.not_after)
170
- elsif certificate_expires_soon?
171
- log_warn(certificate_msg('will expire'))
172
- reflect(:ssl_certificate_will_expire, @app, cert.not_after)
173
- end
174
- end
175
-
176
- def certificate_msg(msg)
177
- time = @ssl_context.cert.not_after.utc.strftime('%Y-%m-%d %H:%M:%S UTC')
178
- "Certificate #{msg} at #{time}."
179
- end
180
-
181
- def certificate_expired?
182
- @ssl_context.cert.not_after && @ssl_context.cert.not_after.utc < Time.now.utc
183
- end
184
-
185
- def certificate_expires_soon?
186
- @ssl_context.cert.not_after && @ssl_context.cert.not_after.utc < (Time.now + 1.month).utc
187
- end
188
- end
189
- end
190
- end
@@ -1,162 +0,0 @@
1
- require 'functional_spec_helper'
2
-
3
- describe 'APNs' do
4
- let(:app) { create_app }
5
- let(:tcp_socket) { double(TCPSocket, setsockopt: nil, close: nil) }
6
- let(:ssl_socket) { double(OpenSSL::SSL::SSLSocket, :sync= => nil, connect: nil, write: nil, flush: nil, read: nil, close: nil) }
7
- let(:io_double) { double(select: nil) }
8
- let(:delivered_ids) { [] }
9
- let(:failed_ids) { [] }
10
- let(:retry_ids) { [] }
11
-
12
- before do
13
- Rpush.config.push_poll = 0.5
14
- stub_tcp_connection(tcp_socket, ssl_socket, io_double)
15
- end
16
-
17
- def create_app
18
- app = Rpush::Apns::App.new
19
- app.certificate = TEST_CERT
20
- app.name = 'test'
21
- app.environment = 'sandbox'
22
- app.save!
23
- app
24
- end
25
-
26
- def create_notification
27
- notification = Rpush::Apns::Notification.new
28
- notification.app = app
29
- notification.alert = 'test'
30
- notification.device_token = 'a' * 108
31
- notification.save!
32
- notification
33
- end
34
-
35
- def wait
36
- sleep 0.1
37
- end
38
-
39
- def wait_for_notification_to_deliver(notification)
40
- timeout { wait until delivered_ids.include?(notification.id) }
41
- end
42
-
43
- def wait_for_notification_to_fail(notification)
44
- timeout { wait until failed_ids.include?(notification.id) }
45
- end
46
-
47
- def wait_for_notification_to_retry(notification)
48
- timeout { wait until retry_ids.include?(notification.id) }
49
- end
50
-
51
- def fail_notification(notification)
52
- allow(ssl_socket).to receive_messages(read: [8, 4, notification.id].pack('ccN'))
53
- enable_io_select
54
- end
55
-
56
- def enable_io_select
57
- called = false
58
- allow(io_double).to receive(:select) do
59
- if called
60
- nil
61
- else
62
- called = true
63
- end
64
- end
65
- end
66
-
67
- it 'delivers a notification successfully' do
68
- notification = create_notification
69
- expect do
70
- Rpush.push
71
- notification.reload
72
- end.to change(notification, :delivered).to(true)
73
- end
74
-
75
- it 'receives feedback' do
76
- app
77
- 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"
78
- allow(ssl_socket).to receive(:read).and_return(tuple, nil)
79
- Rpush.apns_feedback
80
- feedback = Rpush::Apns::Feedback.all.first
81
- expect(feedback).not_to be_nil
82
- expect(feedback.app_id).to eq(app.id)
83
- expect(feedback.device_token).to eq('834f786655eb9f84614a05ad7d00af31e5cfe93ac3ea078f1da44d2a4eb0ce17')
84
- end
85
-
86
- describe 'delivery failures' do
87
- before do
88
- Rpush.reflect do |on|
89
- on.notification_delivered do |n|
90
- delivered_ids << n.id
91
- end
92
-
93
- on.notification_id_failed do |_, n_id|
94
- failed_ids << n_id
95
- end
96
-
97
- on.notification_id_will_retry do |_, n_id|
98
- retry_ids << n_id
99
- end
100
-
101
- on.notification_will_retry do |n|
102
- retry_ids << n.id
103
- end
104
- end
105
-
106
- Rpush.embed
107
- end
108
-
109
- after do
110
- Rpush.reflection_stack.clear
111
- Rpush.reflection_stack.push(Rpush::ReflectionCollection.new)
112
-
113
- timeout { Rpush.shutdown }
114
- end
115
-
116
- it 'fails to deliver a notification' do
117
- notification = create_notification
118
- wait_for_notification_to_deliver(notification)
119
- fail_notification(notification)
120
- wait_for_notification_to_fail(notification)
121
- end
122
-
123
- describe 'with a failed connection' do
124
- it 'retries all notifications' do
125
- allow_any_instance_of(Rpush::Daemon::TcpConnection).to receive_messages(sleep: nil)
126
- expect(ssl_socket).to receive(:write).at_least(1).times.and_raise(Errno::EPIPE)
127
- notifications = 2.times.map { create_notification }
128
- notifications.each { |n| wait_for_notification_to_retry(n) }
129
- end
130
- end
131
-
132
- describe 'with multiple notifications' do
133
- let(:notification1) { create_notification }
134
- let(:notification2) { create_notification }
135
- let(:notification3) { create_notification }
136
- let(:notification4) { create_notification }
137
- let(:notifications) { [notification1, notification2, notification3, notification4] }
138
-
139
- it 'marks the correct notification as failed' do
140
- notifications.each { |n| wait_for_notification_to_deliver(n) }
141
- fail_notification(notification2)
142
- wait_for_notification_to_fail(notification2)
143
- end
144
-
145
- it 'does not mark prior notifications as failed' do
146
- notifications.each { |n| wait_for_notification_to_deliver(n) }
147
- fail_notification(notification2)
148
- wait_for_notification_to_fail(notification2)
149
-
150
- expect(failed_ids).to_not include(notification1.id)
151
- notification1.reload
152
- expect(notification1.delivered).to eq(true)
153
- end
154
-
155
- it 'marks notifications following the failed one as retryable' do
156
- notifications.each { |n| wait_for_notification_to_deliver(n) }
157
- fail_notification(notification2)
158
- [notification3, notification4].each { |n| wait_for_notification_to_retry(n) }
159
- end
160
- end
161
- end
162
- end
@@ -1,40 +0,0 @@
1
- require 'functional_spec_helper'
2
-
3
- describe 'GCM priority' do
4
- let(:app) { Rpush::Gcm::App.new }
5
- let(:notification) { Rpush::Gcm::Notification.new }
6
- let(:hydrated_notification) { Rpush::Gcm::Notification.find(notification.id) }
7
- let(:response) { double(Net::HTTPResponse, code: 200) }
8
- let(:http) { double(Net::HTTP::Persistent, request: response, shutdown: nil) }
9
- let(:priority) { 'normal' }
10
-
11
- before do
12
- app.name = 'test'
13
- app.auth_key = 'abc123'
14
- app.save!
15
-
16
- notification.app_id = app.id
17
- notification.registration_ids = ['foo']
18
- notification.data = { message: 'test' }
19
- notification.priority = priority
20
- notification.save!
21
-
22
- allow(Net::HTTP::Persistent).to receive_messages(new: http)
23
- end
24
-
25
- it 'supports normal priority' do
26
- expect(hydrated_notification.as_json['priority']).to eq('normal')
27
- end
28
-
29
- context 'high priority' do
30
- let(:priority) { 'high' }
31
-
32
- it 'supports high priority' do
33
- expect(hydrated_notification.as_json['priority']).to eq('high')
34
- end
35
- end
36
-
37
- it 'does not add an error when receiving expected priority' do
38
- expect(hydrated_notification.errors.messages[:priority]).to be_empty
39
- end
40
- end
@@ -1,46 +0,0 @@
1
- require 'functional_spec_helper'
2
-
3
- describe 'GCM' do
4
- let(:app) { Rpush::Gcm::App.new }
5
- let(:notification) { Rpush::Gcm::Notification.new }
6
- let(:response) { double(Net::HTTPResponse, code: 200) }
7
- let(:http) { double(Net::HTTP::Persistent, request: response, shutdown: nil) }
8
-
9
- before do
10
- app.name = 'test'
11
- app.auth_key = 'abc123'
12
- app.save!
13
-
14
- notification.app_id = app.id
15
- notification.registration_ids = ['foo']
16
- notification.data = { message: 'test' }
17
- notification.save!
18
-
19
- allow(Net::HTTP::Persistent).to receive_messages(new: http)
20
- end
21
-
22
- it 'delivers a notification successfully' do
23
- allow(response).to receive_messages(body: JSON.dump(results: [{ message_id: notification.registration_ids.first.to_s }]))
24
-
25
- expect do
26
- Rpush.push
27
- notification.reload
28
- end.to change(notification, :delivered).to(true)
29
- end
30
-
31
- it 'fails to deliver a notification successfully' do
32
- allow(response).to receive_messages(body: JSON.dump(results: [{ error: 'Err' }]))
33
- Rpush.push
34
- notification.reload
35
- expect(notification.delivered).to eq(false)
36
- end
37
-
38
- it 'retries notification that fail due to a SocketError' do
39
- expect(http).to receive(:request).and_raise(SocketError.new)
40
- expect(notification.deliver_after).to be_nil
41
- expect do
42
- Rpush.push
43
- notification.reload
44
- end.to change(notification, :deliver_after).to(kind_of(Time))
45
- end
46
- end