rpush 8.0.0 → 9.1.0

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