rpush 4.2.0 → 5.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +248 -163
  3. data/README.md +103 -17
  4. data/lib/generators/templates/add_gcm.rb +4 -4
  5. data/lib/generators/templates/add_rpush.rb +4 -4
  6. data/lib/generators/templates/rpush.rb +4 -0
  7. data/lib/generators/templates/rpush_3_3_1_updates.rb +2 -2
  8. data/lib/rpush/cli.rb +1 -1
  9. data/lib/rpush/client/active_model.rb +4 -1
  10. data/lib/rpush/client/active_model/adm/data_validator.rb +1 -1
  11. data/lib/rpush/client/active_model/apns/device_token_format_validator.rb +2 -2
  12. data/lib/rpush/client/active_model/apns/notification.rb +9 -1
  13. data/lib/rpush/client/active_model/apns/notification_payload_size_validator.rb +15 -0
  14. data/lib/rpush/client/active_model/apns2/notification.rb +14 -0
  15. data/lib/rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +1 -1
  16. data/lib/rpush/client/active_model/gcm/notification.rb +2 -2
  17. data/lib/rpush/client/active_model/payload_data_size_validator.rb +1 -1
  18. data/lib/rpush/client/active_model/registration_ids_count_validator.rb +1 -1
  19. data/lib/rpush/client/active_model/webpush/app.rb +41 -0
  20. data/lib/rpush/client/active_model/webpush/notification.rb +66 -0
  21. data/lib/rpush/client/active_record.rb +4 -0
  22. data/lib/rpush/client/active_record/apns/active_record_serializable_notification.rb +65 -0
  23. data/lib/rpush/client/active_record/apns/notification.rb +1 -57
  24. data/lib/rpush/client/active_record/apns2/notification.rb +4 -1
  25. data/lib/rpush/client/active_record/apnsp8/notification.rb +1 -0
  26. data/lib/rpush/client/active_record/webpush/app.rb +11 -0
  27. data/lib/rpush/client/active_record/webpush/notification.rb +12 -0
  28. data/lib/rpush/client/redis.rb +3 -0
  29. data/lib/rpush/client/redis/apns2/notification.rb +1 -0
  30. data/lib/rpush/client/redis/apnsp8/notification.rb +2 -0
  31. data/lib/rpush/client/redis/pushy/notification.rb +0 -1
  32. data/lib/rpush/client/redis/webpush/app.rb +15 -0
  33. data/lib/rpush/client/redis/webpush/notification.rb +15 -0
  34. data/lib/rpush/configuration.rb +3 -2
  35. data/lib/rpush/daemon.rb +4 -1
  36. data/lib/rpush/daemon/apns/feedback_receiver.rb +1 -1
  37. data/lib/rpush/daemon/apns2/delivery.rb +13 -2
  38. data/lib/rpush/daemon/apnsp8/delivery.rb +7 -2
  39. data/lib/rpush/daemon/app_runner.rb +1 -1
  40. data/lib/rpush/daemon/batch.rb +12 -5
  41. data/lib/rpush/daemon/delivery.rb +1 -2
  42. data/lib/rpush/daemon/store/active_record/reconnectable.rb +1 -1
  43. data/lib/rpush/daemon/webpush.rb +10 -0
  44. data/lib/rpush/daemon/webpush/delivery.rb +114 -0
  45. data/lib/rpush/logger.rb +1 -0
  46. data/lib/rpush/version.rb +2 -2
  47. data/spec/functional/apns2_spec.rb +97 -2
  48. data/spec/functional/gcm_priority_spec.rb +40 -0
  49. data/spec/functional/webpush_spec.rb +30 -0
  50. data/spec/spec_helper.rb +2 -0
  51. data/spec/support/simplecov_helper.rb +1 -1
  52. data/spec/unit/client/active_record/adm/app_spec.rb +2 -54
  53. data/spec/unit/client/active_record/adm/notification_spec.rb +2 -39
  54. data/spec/unit/client/active_record/apns/app_spec.rb +3 -26
  55. data/spec/unit/client/active_record/apns/feedback_spec.rb +1 -5
  56. data/spec/unit/client/active_record/apns/notification_spec.rb +29 -293
  57. data/spec/unit/client/active_record/apns2/app_spec.rb +4 -0
  58. data/spec/unit/client/active_record/apns2/notification_spec.rb +65 -0
  59. data/spec/unit/client/active_record/apnsp8/notification_spec.rb +28 -0
  60. data/spec/unit/client/active_record/app_spec.rb +1 -26
  61. data/spec/unit/client/active_record/gcm/app_spec.rb +3 -1
  62. data/spec/unit/client/active_record/gcm/notification_spec.rb +6 -88
  63. data/spec/unit/client/active_record/notification_spec.rb +3 -11
  64. data/spec/unit/client/active_record/pushy/app_spec.rb +2 -13
  65. data/spec/unit/client/active_record/pushy/notification_spec.rb +2 -55
  66. data/spec/unit/client/active_record/shared/app.rb +14 -0
  67. data/spec/unit/{notification_shared.rb → client/active_record/shared/notification.rb} +12 -7
  68. data/spec/unit/client/active_record/webpush/app_spec.rb +6 -0
  69. data/spec/unit/client/active_record/webpush/notification_spec.rb +6 -0
  70. data/spec/unit/client/active_record/wns/badge_notification_spec.rb +1 -11
  71. data/spec/unit/client/active_record/wns/raw_notification_spec.rb +3 -12
  72. data/spec/unit/client/active_record/wpns/app_spec.rb +3 -1
  73. data/spec/unit/client/active_record/wpns/notification_spec.rb +2 -17
  74. data/spec/unit/client/redis/adm/app_spec.rb +5 -0
  75. data/spec/unit/client/redis/adm/notification_spec.rb +5 -0
  76. data/spec/unit/client/redis/apns/app_spec.rb +5 -0
  77. data/spec/unit/client/redis/apns/feedback_spec.rb +5 -0
  78. data/spec/unit/client/redis/apns/notification_spec.rb +50 -0
  79. data/spec/unit/client/redis/apns2/app_spec.rb +4 -0
  80. data/spec/unit/client/redis/apns2/notification_spec.rb +50 -0
  81. data/spec/unit/client/redis/apnsp8/notification_spec.rb +29 -0
  82. data/spec/unit/client/redis/app_spec.rb +5 -0
  83. data/spec/unit/client/redis/gcm/app_spec.rb +5 -0
  84. data/spec/unit/client/redis/gcm/notification_spec.rb +5 -0
  85. data/spec/unit/client/redis/notification_spec.rb +5 -0
  86. data/spec/unit/client/redis/pushy/app_spec.rb +5 -0
  87. data/spec/unit/client/redis/pushy/notification_spec.rb +5 -0
  88. data/spec/unit/client/redis/webpush/app_spec.rb +5 -0
  89. data/spec/unit/client/redis/webpush/notification_spec.rb +5 -0
  90. data/spec/unit/client/redis/wns/badge_notification_spec.rb +5 -0
  91. data/spec/unit/client/redis/wns/raw_notification_spec.rb +22 -0
  92. data/spec/unit/client/redis/wpns/app_spec.rb +5 -0
  93. data/spec/unit/client/redis/wpns/notification_spec.rb +5 -0
  94. data/spec/unit/client/shared/adm/app.rb +51 -0
  95. data/spec/unit/client/shared/adm/notification.rb +39 -0
  96. data/spec/unit/client/shared/apns/app.rb +29 -0
  97. data/spec/unit/client/shared/apns/feedback.rb +9 -0
  98. data/spec/unit/client/shared/apns/notification.rb +262 -0
  99. data/spec/unit/client/shared/app.rb +17 -0
  100. data/spec/unit/client/shared/gcm/app.rb +4 -0
  101. data/spec/unit/client/shared/gcm/notification.rb +77 -0
  102. data/spec/unit/client/shared/notification.rb +10 -0
  103. data/spec/unit/client/shared/pushy/app.rb +17 -0
  104. data/spec/unit/client/shared/pushy/notification.rb +55 -0
  105. data/spec/unit/client/shared/webpush/app.rb +33 -0
  106. data/spec/unit/client/shared/webpush/notification.rb +83 -0
  107. data/spec/unit/client/shared/wns/badge_notification.rb +15 -0
  108. data/spec/unit/client/shared/wns/raw_notification.rb +21 -0
  109. data/spec/unit/client/shared/wpns/app.rb +4 -0
  110. data/spec/unit/client/shared/wpns/notification.rb +18 -0
  111. data/spec/unit/daemon/batch_spec.rb +50 -2
  112. data/spec/unit/daemon/delivery_spec.rb +10 -0
  113. data/spec/unit/daemon/pushy/delivery_spec.rb +5 -3
  114. data/spec/unit/daemon/shared/store.rb +312 -0
  115. data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +7 -7
  116. data/spec/unit/daemon/store/active_record_spec.rb +2 -290
  117. data/spec/unit/daemon/store/redis_spec.rb +2 -291
  118. data/spec/unit/daemon/webpush/delivery_spec.rb +144 -0
  119. data/spec/unit_spec_helper.rb +3 -0
  120. metadata +135 -12
  121. data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +0 -16
@@ -29,7 +29,7 @@ module Rpush
29
29
  Rpush.logger.info("[#{app.name}] Starting #{pluralize(app.connections, 'dispatcher')}... ", true)
30
30
  runner = @runners[app.id] = new(app)
31
31
  runner.start_dispatchers
32
- puts Rainbow('✔').green if Rpush.config.foreground
32
+ puts Rainbow('✔').green if Rpush.config.foreground && Rpush.config.foreground_logging
33
33
  runner.start_loops
34
34
  rescue StandardError => e
35
35
  @runners.delete(app.id)
@@ -2,6 +2,7 @@ module Rpush
2
2
  module Daemon
3
3
  class Batch
4
4
  include Reflectable
5
+ include Loggable
5
6
 
6
7
  attr_reader :num_processed, :notifications, :delivered, :failed, :retryable
7
8
 
@@ -31,16 +32,21 @@ module Rpush
31
32
  @retryable[deliver_after] ||= []
32
33
  @retryable[deliver_after] << notification
33
34
  end
35
+
34
36
  Rpush::Daemon.store.mark_retryable(notification, deliver_after, persist: false)
35
37
  end
36
38
 
37
- def mark_all_retryable(deliver_after)
38
- @mutex.synchronize do
39
- @retryable[deliver_after] = @notifications
40
- end
39
+ def mark_all_retryable(deliver_after, error)
40
+ retryable_count = 0
41
+
41
42
  each_notification do |notification|
42
- Rpush::Daemon.store.mark_retryable(notification, deliver_after, persist: false)
43
+ next if notification.delivered || notification.failed
44
+
45
+ retryable_count += 1
46
+ mark_retryable(notification, deliver_after)
43
47
  end
48
+
49
+ log_warn("Will retry #{retryable_count} of #{@notifications.size} notifications after #{deliver_after.strftime('%Y-%m-%d %H:%M:%S')} due to error (#{error.class.name}, #{error.message})")
44
50
  end
45
51
 
46
52
  def mark_delivered(notification)
@@ -54,6 +60,7 @@ module Rpush
54
60
  @mutex.synchronize do
55
61
  @delivered = @notifications
56
62
  end
63
+
57
64
  each_notification do |notification|
58
65
  Rpush::Daemon.store.mark_delivered(notification, Time.now, persist: false)
59
66
  end
@@ -20,8 +20,7 @@ module Rpush
20
20
  end
21
21
 
22
22
  def mark_batch_retryable(deliver_after, error)
23
- log_warn("Will retry #{@batch.notifications.size} notifications after #{deliver_after.strftime('%Y-%m-%d %H:%M:%S')} due to error (#{error.class.name}, #{error.message})")
24
- @batch.mark_all_retryable(deliver_after)
23
+ @batch.mark_all_retryable(deliver_after, error)
25
24
  end
26
25
 
27
26
  def mark_delivered
@@ -67,7 +67,7 @@ module Rpush
67
67
 
68
68
  def check_database_is_connected
69
69
  # Simply asking the adapter for the connection state is not sufficient.
70
- Rpush::Client::ActiveRecord::Notification.count
70
+ Rpush::Client::ActiveRecord::Notification.exists?
71
71
  end
72
72
 
73
73
  def sleep_to_avoid_thrashing
@@ -0,0 +1,10 @@
1
+ module Rpush
2
+ module Daemon
3
+ module Webpush
4
+ extend ServiceConfigMethods
5
+
6
+ dispatcher :http
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "webpush"
4
+
5
+ module Rpush
6
+ module Daemon
7
+ module Webpush
8
+
9
+ # Webpush::Request handles all the encryption / signing.
10
+ # We just override #perform to inject the http instance that is managed
11
+ # by Rpush.
12
+ #
13
+ class Request < ::Webpush::Request
14
+ def perform(http)
15
+ req = Net::HTTP::Post.new(uri.request_uri, headers)
16
+ req.body = body
17
+ http.request(uri, req)
18
+ end
19
+ end
20
+
21
+ class Delivery < Rpush::Daemon::Delivery
22
+
23
+ OK = [ 200, 201, 202 ].freeze
24
+ TEMPORARY_FAILURES = [ 429, 500, 502, 503, 504 ].freeze
25
+
26
+ def initialize(app, http, notification, batch)
27
+ @app = app
28
+ @http = http
29
+ @notification = notification
30
+ @batch = batch
31
+ end
32
+
33
+ def perform
34
+ response = send_request
35
+ process_response response
36
+ rescue SocketError, SystemCallError => error
37
+ mark_retryable(@notification, Time.now + 10.seconds, error)
38
+ raise
39
+ rescue StandardError => error
40
+ mark_failed(error)
41
+ raise
42
+ ensure
43
+ @batch.notification_processed
44
+ end
45
+
46
+ private
47
+
48
+ def send_request
49
+ # The initializer is inherited from Webpush::Request and looks like
50
+ # this:
51
+ #
52
+ # initialize(message: '', subscription:, vapid:, **options)
53
+ #
54
+ # where subscription is a hash of :endpoint and :keys, and vapid
55
+ # holds the vapid public and private keys and the :subject (which is
56
+ # an email address).
57
+ Request.new(
58
+ message: @notification.message,
59
+ subscription: @notification.subscription,
60
+ vapid: @app.vapid,
61
+ ttl: @notification.time_to_live,
62
+ urgency: @notification.urgency
63
+ ).perform(@http)
64
+ end
65
+
66
+ def process_response(response)
67
+ case response.code.to_i
68
+ when *OK
69
+ mark_delivered
70
+ when *TEMPORARY_FAILURES
71
+ retry_delivery(response)
72
+ else
73
+ fail_delivery(response)
74
+ end
75
+ end
76
+
77
+ def retry_delivery(response)
78
+ time = deliver_after_header(response)
79
+ if time
80
+ mark_retryable(@notification, time)
81
+ else
82
+ mark_retryable_exponential(@notification)
83
+ end
84
+ log_info("Webpush endpoint responded with a #{response.code} error. #{retry_message}")
85
+ end
86
+
87
+ def fail_delivery(response)
88
+ fail_message = fail_message(response)
89
+ log_error("#{@notification.id} failed: #{fail_message}")
90
+ fail Rpush::DeliveryError.new(response.code.to_i, @notification.id, fail_message)
91
+ end
92
+
93
+ def deliver_after_header(response)
94
+ Rpush::Daemon::RetryHeaderParser.parse(response.header['retry-after'])
95
+ end
96
+
97
+ def retry_message
98
+ deliver_after = @notification.deliver_after.strftime('%Y-%m-%d %H:%M:%S')
99
+ "Notification #{@notification.id} will be retried after #{deliver_after} (retry #{@notification.retries})."
100
+ end
101
+
102
+ def fail_message(response)
103
+ msg = Rpush::Daemon::HTTP_STATUS_CODES[response.code.to_i]
104
+ if explanation = response.body.to_s[0..200].presence
105
+ msg += ": #{explanation}"
106
+ end
107
+ msg
108
+ end
109
+
110
+ end
111
+ end
112
+ end
113
+ end
114
+
data/lib/rpush/logger.rb CHANGED
@@ -79,6 +79,7 @@ module Rpush
79
79
  end
80
80
 
81
81
  def log_foreground(io, formatted_msg, inline)
82
+ return unless Rpush.config.foreground_logging
82
83
  return unless io == STDERR || Rpush.config.foreground
83
84
 
84
85
  if inline
data/lib/rpush/version.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module Rpush
2
2
  module VERSION
3
- MAJOR = 4
4
- MINOR = 2
3
+ MAJOR = 5
4
+ MINOR = 4
5
5
  TINY = 0
6
6
  PRE = nil
7
7
 
@@ -42,6 +42,7 @@ describe 'APNs http2 adapter' do
42
42
  app.certificate = TEST_CERT
43
43
  app.name = 'test'
44
44
  app.environment = 'development'
45
+ app.bundle_id = 'com.example.app'
45
46
  app.save!
46
47
  app
47
48
  end
@@ -75,7 +76,12 @@ describe 'APNs http2 adapter' do
75
76
  :post,
76
77
  "/3/device/#{fake_device_token}",
77
78
  { body: "{\"aps\":{\"alert\":\"test\",\"sound\":\"default\",\"content-available\":1}}",
78
- headers: {} }
79
+ headers: {
80
+ 'apns-expiration' => '0',
81
+ 'apns-priority' => '10',
82
+ 'apns-topic' => 'com.example.app'
83
+ }
84
+ }
79
85
  )
80
86
  .and_return(fake_http2_request)
81
87
 
@@ -104,7 +110,11 @@ describe 'APNs http2 adapter' do
104
110
  "/3/device/#{fake_device_token}",
105
111
  { body: "{\"aps\":{\"alert\":\"test\",\"sound\":\"default\","\
106
112
  "\"content-available\":1},\"some_field\":\"some value\"}",
107
- headers: { 'apns-topic' => bundle_id }
113
+ headers: {
114
+ 'apns-topic' => bundle_id,
115
+ 'apns-expiration' => '0',
116
+ 'apns-priority' => '10'
117
+ }
108
118
  }
109
119
  ).and_return(fake_http2_request)
110
120
 
@@ -177,6 +187,13 @@ describe 'APNs http2 adapter' do
177
187
  end
178
188
 
179
189
  context 'when there is SocketError' do
190
+ let(:fake_http_resp_headers) {
191
+ {
192
+ ":status" => "500",
193
+ "apns-id"=>"C6D65840-5E3F-785A-4D91-B97D305C12F6"
194
+ }
195
+ }
196
+
180
197
  before(:each) do
181
198
  expect(fake_client).to receive(:call_async) { raise(SocketError) }
182
199
  end
@@ -201,6 +218,24 @@ describe 'APNs http2 adapter' do
201
218
  notification = create_notification
202
219
  Rpush.push
203
220
  end
221
+
222
+ context 'when specific notification was delivered before request failed' do
223
+ let(:fake_http_resp_headers) {
224
+ {
225
+ ":status" => "200",
226
+ "apns-id"=>"C6D65840-5E3F-785A-4D91-B97D305C12F6"
227
+ }
228
+ }
229
+
230
+ it 'fails but will not retry this notification' do
231
+ notification = create_notification
232
+ expect do
233
+ Rpush.push
234
+ notification.reload
235
+ end.to change(notification, :retries).by(0)
236
+ .and change(notification, :delivered).to(true)
237
+ end
238
+ end
204
239
  end
205
240
 
206
241
  context 'when any StandardError occurs' do
@@ -228,5 +263,65 @@ describe 'APNs http2 adapter' do
228
263
  Rpush.push
229
264
  end
230
265
  end
266
+
267
+ context 'when waiting for requests to complete times out' do
268
+ let(:on_close) do
269
+ proc { |&block| @thread = Thread.new { sleep(0.01) } }
270
+ end
271
+
272
+ before(:each) do
273
+ @thread = nil
274
+
275
+ expect(fake_http2_request).
276
+ to receive(:on).with(:close), &on_close
277
+
278
+ expect(fake_client).to receive(:join) { @thread.join; raise(NetHttp2::AsyncRequestTimeout) }
279
+ end
280
+
281
+ it 'closes the client' do
282
+ create_notification
283
+ expect(fake_client).to receive(:close)
284
+ Rpush.push
285
+ end
286
+
287
+ it 'reflects :error' do
288
+ reflected_error = false
289
+ Rpush.reflect do |on|
290
+ on.error do |error|
291
+ reflected_error = true
292
+ expect(error).to be_kind_of(StandardError)
293
+ reflector.accept
294
+ end
295
+ end
296
+
297
+ notification = create_notification
298
+ Rpush.push
299
+
300
+ expect(reflected_error).to be true
301
+ end
302
+
303
+ it 'fails but retries delivery several times' do
304
+ notification = create_notification
305
+ expect do
306
+ Rpush.push
307
+ notification.reload
308
+ end.to change(notification, :retries)
309
+ end
310
+
311
+ context 'when specific notification was delivered before another async call failed' do
312
+ let(:on_close) do
313
+ proc { |&block| @thread = Thread.new { sleep(0.01); block.call } }
314
+ end
315
+
316
+ it 'fails but retries delivery several times' do
317
+ notification = create_notification
318
+ expect do
319
+ Rpush.push
320
+ notification.reload
321
+ end.to change(notification, :retries).by(0)
322
+ .and change(notification, :delivered).to(true)
323
+ end
324
+ end
325
+ end
231
326
  end
232
327
  end
@@ -0,0 +1,40 @@
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
@@ -0,0 +1,30 @@
1
+ require 'functional_spec_helper'
2
+
3
+ describe 'Webpush' do
4
+ let(:code) { 201 }
5
+ let(:response) { instance_double('Net::HTTPResponse', code: code, body: '') }
6
+ let(:http) { instance_double('Net::HTTP::Persistent', request: response, shutdown: nil) }
7
+ let(:app) { Rpush::Webpush::App.create!(name: 'MyApp', vapid_keypair: VAPID_KEYPAIR) }
8
+
9
+ let(:device_reg) {
10
+ { endpoint: 'https://webpush-provider.example.org/push/some-id',
11
+ keys: {'auth' => 'DgN9EBia1o057BdhCOGURA', 'p256dh' => 'BAtxJ--7vHq9IVm8utUB3peJ4lpxRqk1rukCIkVJOomS83QkCnrQ4EyYQsSaCRgy_c8XPytgXxuyAvRJdnTPK4A'} }
12
+ }
13
+ let(:notification) { Rpush::Webpush::Notification.create!(app: app, registration_ids: [device_reg], data: { message: 'test' }) }
14
+
15
+ before do
16
+ allow(Net::HTTP::Persistent).to receive_messages(new: http)
17
+ end
18
+
19
+ it 'deliveres a notification successfully' do
20
+ expect { Rpush.push }.to change { notification.reload.delivered }.to(true)
21
+ end
22
+
23
+ context 'when delivery failed' do
24
+ let(:code) { 404 }
25
+ it 'marks a notification as failed' do
26
+ expect { Rpush.push }.to change { notification.reload.failed }.to(true)
27
+ end
28
+ end
29
+ end
30
+
data/spec/spec_helper.rb CHANGED
@@ -46,6 +46,8 @@ path = File.join(File.dirname(__FILE__), 'support')
46
46
  TEST_CERT = File.read(File.join(path, 'cert_without_password.pem'))
47
47
  TEST_CERT_WITH_PASSWORD = File.read(File.join(path, 'cert_with_password.pem'))
48
48
 
49
+ VAPID_KEYPAIR = Webpush.generate_key.to_hash.merge(subject: 'rpush-test@example.org').to_json
50
+
49
51
  def after_example_cleanup
50
52
  Rpush.logger = nil
51
53
  Rpush::Daemon.store = nil
@@ -18,7 +18,7 @@ module SimpleCovHelper
18
18
  end
19
19
  end
20
20
 
21
- formatter SimpleCov::Formatter::MultiFormatter[*formatters]
21
+ formatter SimpleCov::Formatter::MultiFormatter.new(formatters)
22
22
  end
23
23
  end
24
24
  end