rpush 7.0.1 → 9.0.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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -4
  3. data/README.md +24 -44
  4. data/lib/generators/rpush_migration_generator.rb +1 -0
  5. data/lib/generators/templates/rpush.rb +23 -13
  6. data/lib/generators/templates/rpush_7_1_0_updates.rb +12 -0
  7. data/lib/rpush/client/active_model/apns/notification.rb +0 -4
  8. data/lib/rpush/client/active_model/{gcm → fcm}/app.rb +4 -3
  9. data/lib/rpush/client/active_model/{gcm → fcm}/expiry_collapse_key_mutual_inclusion_validator.rb +1 -1
  10. data/lib/rpush/client/active_model/fcm/notification.rb +129 -0
  11. data/lib/rpush/client/active_model/fcm/notification_keys_in_allowed_list_validator.rb +20 -0
  12. data/lib/rpush/client/active_model.rb +4 -3
  13. data/lib/rpush/client/active_record/{gcm → fcm}/app.rb +2 -2
  14. data/lib/rpush/client/active_record/{gcm → fcm}/notification.rb +2 -2
  15. data/lib/rpush/client/active_record.rb +2 -2
  16. data/lib/rpush/client/redis/app.rb +2 -0
  17. data/lib/rpush/client/redis/{gcm → fcm}/app.rb +2 -2
  18. data/lib/rpush/client/redis/{gcm → fcm}/notification.rb +2 -2
  19. data/lib/rpush/client/redis.rb +2 -2
  20. data/lib/rpush/configuration.rb +2 -19
  21. data/lib/rpush/daemon/apns2/delivery.rb +0 -1
  22. data/lib/rpush/daemon/apnsp8/delivery.rb +0 -1
  23. data/lib/rpush/daemon/fcm/delivery.rb +162 -0
  24. data/lib/rpush/daemon/{gcm.rb → fcm.rb} +1 -1
  25. data/lib/rpush/daemon/google_credential_cache.rb +41 -0
  26. data/lib/rpush/daemon/service_config_methods.rb +0 -2
  27. data/lib/rpush/daemon/store/active_record.rb +15 -12
  28. data/lib/rpush/daemon/store/interface.rb +3 -3
  29. data/lib/rpush/daemon/store/redis.rb +13 -9
  30. data/lib/rpush/daemon/webpush/delivery.rb +2 -2
  31. data/lib/rpush/daemon.rb +3 -9
  32. data/lib/rpush/reflection_collection.rb +3 -3
  33. data/lib/rpush/version.rb +2 -2
  34. data/lib/rpush.rb +1 -1
  35. data/spec/functional/apns2_spec.rb +2 -6
  36. data/spec/functional/cli_spec.rb +41 -15
  37. data/spec/functional/embed_spec.rb +57 -26
  38. data/spec/functional/{gcm_priority_spec.rb → fcm_priority_spec.rb} +13 -7
  39. data/spec/functional/fcm_spec.rb +77 -0
  40. data/spec/functional/retry_spec.rb +21 -4
  41. data/spec/functional/synchronization_spec.rb +1 -1
  42. data/spec/functional_spec_helper.rb +1 -7
  43. data/spec/spec_helper.rb +4 -1
  44. data/spec/support/active_record_setup.rb +3 -1
  45. data/spec/unit/client/active_record/{gcm → fcm}/app_spec.rb +2 -2
  46. data/spec/unit/client/active_record/fcm/notification_spec.rb +10 -0
  47. data/spec/unit/client/active_record/shared/app.rb +1 -1
  48. data/spec/unit/client/redis/fcm/app_spec.rb +5 -0
  49. data/spec/unit/client/redis/fcm/notification_spec.rb +5 -0
  50. data/spec/unit/client/shared/apns/notification.rb +0 -15
  51. data/spec/unit/client/shared/fcm/app.rb +4 -0
  52. data/spec/unit/client/shared/fcm/notification.rb +92 -0
  53. data/spec/unit/configuration_spec.rb +1 -1
  54. data/spec/unit/daemon/apnsp8/delivery_spec.rb +1 -1
  55. data/spec/unit/daemon/fcm/delivery_spec.rb +127 -0
  56. data/spec/unit/daemon/service_config_methods_spec.rb +1 -1
  57. data/spec/unit/daemon/shared/store.rb +0 -42
  58. data/spec/unit/daemon/wns/delivery_spec.rb +1 -1
  59. data/spec/unit/logger_spec.rb +1 -1
  60. data/spec/unit_spec_helper.rb +1 -1
  61. metadata +127 -69
  62. data/lib/rpush/apns_feedback.rb +0 -18
  63. data/lib/rpush/client/active_model/gcm/notification.rb +0 -62
  64. data/lib/rpush/daemon/apns/delivery.rb +0 -43
  65. data/lib/rpush/daemon/apns/feedback_receiver.rb +0 -91
  66. data/lib/rpush/daemon/apns.rb +0 -17
  67. data/lib/rpush/daemon/dispatcher/apns_tcp.rb +0 -152
  68. data/lib/rpush/daemon/dispatcher/tcp.rb +0 -22
  69. data/lib/rpush/daemon/gcm/delivery.rb +0 -241
  70. data/lib/rpush/daemon/tcp_connection.rb +0 -190
  71. data/spec/functional/apns_spec.rb +0 -162
  72. data/spec/functional/gcm_spec.rb +0 -46
  73. data/spec/functional/new_app_spec.rb +0 -44
  74. data/spec/unit/apns_feedback_spec.rb +0 -39
  75. data/spec/unit/client/active_record/gcm/notification_spec.rb +0 -14
  76. data/spec/unit/client/redis/gcm/app_spec.rb +0 -5
  77. data/spec/unit/client/redis/gcm/notification_spec.rb +0 -5
  78. data/spec/unit/client/shared/gcm/app.rb +0 -4
  79. data/spec/unit/client/shared/gcm/notification.rb +0 -77
  80. data/spec/unit/daemon/apns/delivery_spec.rb +0 -108
  81. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +0 -137
  82. data/spec/unit/daemon/dispatcher/tcp_spec.rb +0 -32
  83. data/spec/unit/daemon/gcm/delivery_spec.rb +0 -387
  84. data/spec/unit/daemon/tcp_connection_spec.rb +0 -292
@@ -0,0 +1,162 @@
1
+ module Rpush
2
+ module Daemon
3
+ module Fcm
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'.freeze
9
+ SCOPE = 'https://www.googleapis.com/auth/firebase.messaging'.freeze
10
+
11
+ def initialize(app, http, notification, batch)
12
+ if necessary_data_exists?(app)
13
+ @app = app
14
+ @http = http
15
+ @notification = notification
16
+ @batch = batch
17
+
18
+ @uri = URI.parse("#{HOST}/v1/projects/#{@app.firebase_project_id || ENV['FIREBASE_PROJECT_ID']}/messages:send")
19
+ else
20
+ Rpush.logger.error("Cannot find necessary configuration! Please make sure you have set all necessary ENV variables or firebase_project_id and json_key attributes.")
21
+ end
22
+ end
23
+
24
+ def perform
25
+ handle_response(do_post)
26
+ rescue SocketError => error
27
+ mark_retryable(@notification, Time.now + 10.seconds, error)
28
+ raise
29
+ rescue StandardError => error
30
+ mark_failed(error)
31
+ raise
32
+ ensure
33
+ @batch.notification_processed
34
+ end
35
+
36
+ protected
37
+
38
+ def handle_response(response)
39
+ case response.code.to_i
40
+ when 200
41
+ ok
42
+ when 400
43
+ bad_request(response)
44
+ when 401
45
+ unauthorized
46
+ when 403
47
+ sender_id_mismatch
48
+ when 404
49
+ unregistered(response)
50
+ when 429
51
+ too_many_requests
52
+ when 500
53
+ internal_server_error(response)
54
+ when 502
55
+ bad_gateway(response)
56
+ when 503
57
+ service_unavailable(response)
58
+ when 500..599
59
+ other_5xx_error(response)
60
+ else
61
+ fail Rpush::DeliveryError.new(response.code.to_i, @notification.id, Rpush::Daemon::HTTP_STATUS_CODES[response.code.to_i])
62
+ end
63
+ end
64
+
65
+ def ok
66
+ reflect(:fcm_delivered_to_recipient, @notification)
67
+ mark_delivered
68
+ log_info("#{@notification.id} sent to #{@notification.device_token}")
69
+ end
70
+
71
+ def bad_request(response)
72
+ fail Rpush::DeliveryError.new(400, @notification.id, "FCM failed to handle the JSON request. (#{parse_error(response)})")
73
+ end
74
+
75
+ def unauthorized
76
+ fail Rpush::DeliveryError.new(401, @notification.id, 'Unauthorized, Bearer token could not be validated.')
77
+ end
78
+
79
+ def sender_id_mismatch
80
+ fail Rpush::DeliveryError.new(403, @notification.id, 'The sender ID was mismatched. It seems the device token is wrong.')
81
+ end
82
+
83
+ def unregistered(response)
84
+ error = parse_error(response)
85
+ reflect(:fcm_invalid_device_token, @app, error, @notification.device_token)
86
+ fail Rpush::DeliveryError.new(404, @notification.id, "Client was not registered for your app. (#{error})")
87
+ end
88
+
89
+ def too_many_requests
90
+ fail Rpush::DeliveryError.new(429, @notification.id, 'Slow down. Too many requests were sent!')
91
+ end
92
+
93
+ def internal_server_error(response)
94
+ retry_delivery(@notification, response)
95
+ log_warn("FCM responded with an Internal Error. " + retry_message)
96
+ end
97
+
98
+ def bad_gateway(response)
99
+ retry_delivery(@notification, response)
100
+ log_warn("FCM responded with a Bad Gateway Error. " + retry_message)
101
+ end
102
+
103
+ def service_unavailable(response)
104
+ retry_delivery(@notification, response)
105
+ log_warn("FCM responded with an Service Unavailable Error. " + retry_message)
106
+ end
107
+
108
+ def other_5xx_error(response)
109
+ retry_delivery(@notification, response)
110
+ log_warn("FCM responded with a 5xx Error. " + retry_message)
111
+ end
112
+
113
+ def parse_error(response)
114
+ error = multi_json_load(response.body)['error']
115
+ "#{error['status']}: #{error['message']}"
116
+ end
117
+
118
+ def deliver_after_header(response)
119
+ Rpush::Daemon::RetryHeaderParser.parse(response.header['retry-after'])
120
+ end
121
+
122
+ def retry_delivery(notification, response)
123
+ time = deliver_after_header(response)
124
+ if time
125
+ mark_retryable(notification, time)
126
+ else
127
+ mark_retryable_exponential(notification)
128
+ end
129
+ end
130
+
131
+ def retry_message
132
+ "Notification #{@notification.id} will be retried after #{@notification.deliver_after.strftime('%Y-%m-%d %H:%M:%S')} (retry #{@notification.retries})."
133
+ end
134
+
135
+ def obtain_access_token
136
+ GoogleCredentialCache.instance.access_token(SCOPE, @app.json_key)
137
+ end
138
+
139
+ def do_post
140
+ token = obtain_access_token['access_token']
141
+ post = Net::HTTP::Post.new(@uri.path, 'Content-Type' => 'application/json',
142
+ 'Authorization' => "Bearer #{token}")
143
+ post.body = @notification.as_json.to_json
144
+ @http.request(@uri, post)
145
+ end
146
+
147
+ def necessary_data_exists?(app)
148
+ # Needed for Google Auth
149
+ # See https://github.com/googleapis/google-auth-library-ruby#example-environment-variables
150
+ # for further information
151
+ (app.firebase_project_id || ENV.key?('FIREBASE_PROJECT_ID')) &&
152
+ (app.json_key || (
153
+ ENV.key?('GOOGLE_ACCOUNT_TYPE') &&
154
+ ENV.key?('GOOGLE_CLIENT_ID') &&
155
+ ENV.key?('GOOGLE_CLIENT_EMAIL') &&
156
+ ENV.key?('GOOGLE_PRIVATE_KEY')
157
+ ))
158
+ end
159
+ end
160
+ end
161
+ end
162
+ end
@@ -1,6 +1,6 @@
1
1
  module Rpush
2
2
  module Daemon
3
- module Gcm
3
+ module Fcm
4
4
  extend ServiceConfigMethods
5
5
 
6
6
  dispatcher :http
@@ -0,0 +1,41 @@
1
+ require 'singleton'
2
+ module Rpush
3
+ module Daemon
4
+ class GoogleCredentialCache
5
+ include Singleton
6
+ include Loggable
7
+
8
+ # Assuming tokens are valid for 1 hour
9
+ TOKEN_VALID_FOR_SEC = 60 * 59
10
+
11
+ def initialize
12
+ @credentials_cache = {}
13
+ end
14
+
15
+ def access_token(scope, json_key)
16
+ key = hash_key(scope, json_key)
17
+
18
+ if @credentials_cache[key].nil? || Time.now > @credentials_cache[key][:expires_at]
19
+ token = fetch_fresh_token(scope, json_key)
20
+ expires_at = Time.now + TOKEN_VALID_FOR_SEC
21
+ @credentials_cache[key] = { token: token, expires_at: expires_at }
22
+ end
23
+
24
+ @credentials_cache[key][:token]
25
+ end
26
+
27
+ private
28
+
29
+ def fetch_fresh_token(scope, json_key)
30
+ json_key_io = json_key ? StringIO.new(json_key) : nil
31
+ log_debug("FCM - Obtaining access token.")
32
+ authorizer = Google::Auth::ServiceAccountCredentials.make_creds(scope: scope, json_key_io: json_key_io)
33
+ authorizer.fetch_access_token
34
+ end
35
+
36
+ def hash_key(scope, json_key)
37
+ scope.hash ^ json_key.hash
38
+ end
39
+ end
40
+ end
41
+ end
@@ -3,8 +3,6 @@ module Rpush
3
3
  module ServiceConfigMethods
4
4
  DISPATCHERS = {
5
5
  http: Rpush::Daemon::Dispatcher::Http,
6
- tcp: Rpush::Daemon::Dispatcher::Tcp,
7
- apns_tcp: Rpush::Daemon::Dispatcher::ApnsTcp,
8
6
  apns_http2: Rpush::Daemon::Dispatcher::ApnsHttp2,
9
7
  apnsp8_http2: Rpush::Daemon::Dispatcher::Apnsp8Http2
10
8
  }
@@ -138,21 +138,14 @@ module Rpush
138
138
  end
139
139
  end
140
140
 
141
- def create_apns_feedback(failed_at, device_token, app)
142
- with_database_reconnect_and_retry do
143
- Rpush::Client::ActiveRecord::Apns::Feedback.create!(failed_at: failed_at,
144
- device_token: device_token, app_id: app.id)
145
- end
146
- end
147
-
148
- def create_gcm_notification(attrs, data, registration_ids, deliver_after, app)
149
- notification = Rpush::Client::ActiveRecord::Gcm::Notification.new
150
- create_gcm_like_notification(notification, attrs, data, registration_ids, deliver_after, app)
141
+ def create_fcm_notification(attrs, data, app)
142
+ notification = Rpush::Client::ActiveRecord::Fcm::Notification.new
143
+ create_fcm_like_notification(notification, attrs, data, app)
151
144
  end
152
145
 
153
146
  def create_adm_notification(attrs, data, registration_ids, deliver_after, app)
154
147
  notification = Rpush::Client::ActiveRecord::Adm::Notification.new
155
- create_gcm_like_notification(notification, attrs, data, registration_ids, deliver_after, app)
148
+ create_adm_like_notification(notification, attrs, data, registration_ids, deliver_after, app)
156
149
  end
157
150
 
158
151
  def update_app(app)
@@ -194,7 +187,17 @@ module Rpush
194
187
 
195
188
  private
196
189
 
197
- def create_gcm_like_notification(notification, attrs, data, registration_ids, deliver_after, app) # rubocop:disable Metrics/ParameterLists
190
+ def create_fcm_like_notification(notification, attrs, data, app) # rubocop:disable Metrics/ParameterLists
191
+ with_database_reconnect_and_retry do
192
+ notification.assign_attributes(attrs)
193
+ notification.data = data
194
+ notification.app = app
195
+ notification.save!
196
+ notification
197
+ end
198
+ end
199
+
200
+ def create_adm_like_notification(notification, attrs, data, registration_ids, deliver_after, app) # rubocop:disable Metrics/ParameterLists
198
201
  with_database_reconnect_and_retry do
199
202
  notification.assign_attributes(attrs)
200
203
  notification.data = data
@@ -4,9 +4,9 @@ module Rpush
4
4
  class Interface
5
5
  PUBLIC_METHODS = [:deliverable_notifications, :mark_retryable,
6
6
  :mark_batch_retryable, :mark_delivered, :mark_batch_delivered,
7
- :mark_failed, :mark_batch_failed, :create_apns_feedback,
8
- :create_gcm_notification, :create_adm_notification, :update_app,
9
- :update_notification, :release_connection,
7
+ :mark_failed, :mark_batch_failed,
8
+ :create_fcm_notification, :create_adm_notification,
9
+ :update_app, :update_notification, :release_connection,
10
10
  :all_apps, :app, :mark_ids_failed, :mark_ids_retryable,
11
11
  :reopen_log, :pending_delivery_count, :translate_integer_notification_id]
12
12
 
@@ -88,18 +88,14 @@ module Rpush
88
88
  end
89
89
  end
90
90
 
91
- def create_apns_feedback(failed_at, device_token, app)
92
- Rpush::Client::Redis::Apns::Feedback.create!(failed_at: failed_at, device_token: device_token, app_id: app.id)
93
- end
94
-
95
- def create_gcm_notification(attrs, data, registration_ids, deliver_after, app)
96
- notification = Rpush::Client::Redis::Gcm::Notification.new
97
- create_gcm_like_notification(notification, attrs, data, registration_ids, deliver_after, app)
91
+ def create_fcm_notification(attrs, data, app)
92
+ notification = Rpush::Client::Redis::Fcm::Notification.new
93
+ create_fcm_like_notification(notification, attrs, data, app)
98
94
  end
99
95
 
100
96
  def create_adm_notification(attrs, data, registration_ids, deliver_after, app)
101
97
  notification = Rpush::Client::Redis::Adm::Notification.new
102
- create_gcm_like_notification(notification, attrs, data, registration_ids, deliver_after, app)
98
+ create_adm_like_notification(notification, attrs, data, registration_ids, deliver_after, app)
103
99
  end
104
100
 
105
101
  def update_app(app)
@@ -138,7 +134,15 @@ module Rpush
138
134
  nil
139
135
  end
140
136
 
141
- def create_gcm_like_notification(notification, attrs, data, registration_ids, deliver_after, app) # rubocop:disable Metrics/ParameterLists
137
+ def create_fcm_like_notification(notification, attrs, data, app) # rubocop:disable Metrics/ParameterLists
138
+ notification.assign_attributes(attrs)
139
+ notification.data = data
140
+ notification.app = app
141
+ notification.save!
142
+ notification
143
+ end
144
+
145
+ def create_adm_like_notification(notification, attrs, data, registration_ids, deliver_after, app) # rubocop:disable Metrics/ParameterLists
142
146
  notification.assign_attributes(attrs)
143
147
  notification.data = data
144
148
  notification.registration_ids = registration_ids
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "webpush"
3
+ require "web-push"
4
4
 
5
5
  module Rpush
6
6
  module Daemon
@@ -10,7 +10,7 @@ module Rpush
10
10
  # We just override #perform to inject the http instance that is managed
11
11
  # by Rpush.
12
12
  #
13
- class Request < ::Webpush::Request
13
+ class Request < ::WebPush::Request
14
14
  def perform(http)
15
15
  req = Net::HTTP::Post.new(uri.request_uri, headers)
16
16
  req.body = body
data/lib/rpush/daemon.rb CHANGED
@@ -19,11 +19,8 @@ require 'rpush/daemon/batch'
19
19
  require 'rpush/daemon/queue_payload'
20
20
  require 'rpush/daemon/synchronizer'
21
21
  require 'rpush/daemon/app_runner'
22
- require 'rpush/daemon/tcp_connection'
23
22
  require 'rpush/daemon/dispatcher_loop'
24
23
  require 'rpush/daemon/dispatcher/http'
25
- require 'rpush/daemon/dispatcher/tcp'
26
- require 'rpush/daemon/dispatcher/apns_tcp'
27
24
  require 'rpush/daemon/dispatcher/apns_http2'
28
25
  require 'rpush/daemon/dispatcher/apnsp8_http2'
29
26
  require 'rpush/daemon/service_config_methods'
@@ -38,10 +35,6 @@ require 'rpush/daemon/rpc/client'
38
35
 
39
36
  require 'rpush/daemon/store/interface'
40
37
 
41
- require 'rpush/daemon/apns/delivery'
42
- require 'rpush/daemon/apns/feedback_receiver'
43
- require 'rpush/daemon/apns'
44
-
45
38
  require 'rpush/daemon/apns2/delivery'
46
39
  require 'rpush/daemon/apns2'
47
40
 
@@ -49,8 +42,9 @@ require 'rpush/daemon/apnsp8/delivery'
49
42
  require 'rpush/daemon/apnsp8/token'
50
43
  require 'rpush/daemon/apnsp8'
51
44
 
52
- require 'rpush/daemon/gcm/delivery'
53
- require 'rpush/daemon/gcm'
45
+ require 'rpush/daemon/fcm/delivery'
46
+ require 'rpush/daemon/fcm'
47
+ require 'rpush/daemon/google_credential_cache'
54
48
 
55
49
  require 'rpush/daemon/wpns/delivery'
56
50
  require 'rpush/daemon/wpns'
@@ -4,10 +4,10 @@ module Rpush
4
4
 
5
5
  REFLECTIONS = [
6
6
  :apns_feedback, :notification_enqueued, :notification_delivered,
7
- :notification_failed, :notification_will_retry, :gcm_delivered_to_recipient,
8
- :gcm_failed_to_recipient, :gcm_canonical_id, :gcm_invalid_registration_id,
7
+ :notification_failed, :notification_will_retry,
8
+ :fcm_delivered_to_recipient, :fcm_failed_to_recipient, :fcm_canonical_id, :fcm_invalid_device_token,
9
9
  :error, :adm_canonical_id, :adm_failed_to_recipient, :wns_invalid_channel,
10
- :tcp_connection_lost, :ssl_certificate_will_expire, :ssl_certificate_revoked,
10
+ :ssl_certificate_will_expire, :ssl_certificate_revoked,
11
11
  :notification_id_will_retry, :notification_id_failed
12
12
  ]
13
13
 
data/lib/rpush/version.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  module Rpush
2
2
  module VERSION
3
- MAJOR = 7
3
+ MAJOR = 9
4
4
  MINOR = 0
5
- TINY = 1
5
+ TINY = 0
6
6
  PRE = nil
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".").freeze
data/lib/rpush.rb CHANGED
@@ -3,6 +3,7 @@ require 'multi_json'
3
3
  require 'active_support/all'
4
4
  require 'net-http2'
5
5
  require 'jwt'
6
+ require 'googleauth'
6
7
 
7
8
  require 'rails'
8
9
 
@@ -19,7 +20,6 @@ require 'rpush/reflectable'
19
20
  require 'rpush/plugin'
20
21
  require 'rpush/embed'
21
22
  require 'rpush/push'
22
- require 'rpush/apns_feedback'
23
23
 
24
24
  module Rpush
25
25
  def self.jruby?
@@ -79,8 +79,7 @@ describe 'APNs http2 adapter' do
79
79
  headers: {
80
80
  'apns-expiration' => '0',
81
81
  'apns-priority' => '10',
82
- 'apns-topic' => 'com.example.app',
83
- 'apns-push-type' => 'background'
82
+ 'apns-topic' => 'com.example.app'
84
83
  }
85
84
  }
86
85
  )
@@ -114,8 +113,7 @@ describe 'APNs http2 adapter' do
114
113
  headers: {
115
114
  'apns-topic' => bundle_id,
116
115
  'apns-expiration' => '0',
117
- 'apns-priority' => '10',
118
- 'apns-push-type' => 'background'
116
+ 'apns-priority' => '10'
119
117
  }
120
118
  }
121
119
  ).and_return(fake_http2_request)
@@ -257,7 +255,6 @@ describe 'APNs http2 adapter' do
257
255
  Rpush.reflect do |on|
258
256
  on.error do |error|
259
257
  expect(error).to be_kind_of(StandardError)
260
- reflector.accept
261
258
  end
262
259
  end
263
260
 
@@ -292,7 +289,6 @@ describe 'APNs http2 adapter' do
292
289
  on.error do |error|
293
290
  reflected_error = true
294
291
  expect(error).to be_kind_of(StandardError)
295
- reflector.accept
296
292
  end
297
293
  end
298
294
 
@@ -2,31 +2,57 @@ require 'functional_spec_helper'
2
2
 
3
3
  describe Rpush::CLI do
4
4
  def create_app
5
- app = Rpush::Apns::App.new
5
+ app = Rpush::Apns2::App.new
6
6
  app.certificate = TEST_CERT
7
7
  app.name = 'test'
8
- app.environment = 'sandbox'
8
+ app.environment = 'development'
9
+ app.bundle_id = 'com.example.app'
9
10
  app.save!
10
11
  app
11
12
  end
12
13
 
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) }
14
+ let(:fake_client) {
15
+ double(
16
+ prepare_request: fake_http2_request,
17
+ close: 'ok',
18
+ call_async: 'ok',
19
+ join: 'ok',
20
+ on: 'ok'
21
+ )
22
+ }
23
+ let(:fake_http2_request) { double }
24
+ let(:fake_http_resp_headers) {
25
+ {
26
+ ":status" => "200",
27
+ "apns-id"=>"C6D65840-5E3F-785A-4D91-B97D305C12F6"
28
+ }
29
+ }
30
+ let(:fake_http_resp_body) { '' }
17
31
 
18
- before do
19
- create_app
20
- stub_tcp_connection(tcp_socket, ssl_socket, io_double)
21
- Rpush.embed
32
+ before do
33
+ create_app
34
+ Rpush.config.push_poll = 0.5
22
35
 
23
- timeout do
24
- Thread.pass until File.exist?(Rpush::Daemon::Rpc.socket_path)
25
- end
26
- end
36
+ allow(NetHttp2::Client).
37
+ to receive(:new).and_return(fake_client)
38
+ allow(fake_http2_request).
39
+ to receive(:on).with(:headers).
40
+ and_yield(fake_http_resp_headers)
41
+ allow(fake_http2_request).
42
+ to receive(:on).with(:body_chunk).
43
+ and_yield(fake_http_resp_body)
44
+ allow(fake_http2_request).
45
+ to receive(:on).with(:close).
46
+ and_yield
47
+
48
+ Rpush.embed
49
+ end
27
50
 
28
- after { timeout { Rpush.shutdown } }
51
+ after do
52
+ timeout { Rpush.shutdown }
53
+ end
29
54
 
55
+ describe 'status' do
30
56
  it 'prints the status' do
31
57
  expect(subject).to receive(:configure_rpush) { true }
32
58
  expect(subject).to receive(:puts).with(/app_runners:/)
@@ -1,49 +1,80 @@
1
1
  require 'functional_spec_helper'
2
2
 
3
3
  describe 'embedding' do
4
- let(:timeout) { 10 }
5
- let(:app) { Rpush::Apns::App.new }
6
- let(:notification) { Rpush::Apns::Notification.new }
7
- let(:tcp_socket) { double(TCPSocket, setsockopt: nil, close: nil) }
8
- let(:ssl_socket) { double(OpenSSL::SSL::SSLSocket, :sync= => nil, connect: nil, write: nil, flush: nil, read: nil, close: nil) }
9
- let(:io_double) { double(select: nil) }
10
-
11
- before do
4
+ def create_app
5
+ app = Rpush::Apns2::App.new
12
6
  app.certificate = TEST_CERT
13
7
  app.name = 'test'
14
- app.environment = 'sandbox'
8
+ app.environment = 'development'
9
+ app.bundle_id = 'com.example.app'
15
10
  app.save!
11
+ app
12
+ end
16
13
 
14
+ let(:fake_device_token) { 'a' * 108 }
15
+ let(:notification_data) { nil }
16
+
17
+ def create_notification(app)
18
+ notification = Rpush::Apns2::Notification.new
17
19
  notification.app = app
20
+ notification.sound = 'default'
18
21
  notification.alert = 'test'
19
- notification.device_token = 'a' * 108
22
+ notification.device_token = fake_device_token
23
+ notification.data = notification_data
24
+ notification.content_available = 1
20
25
  notification.save!
21
-
22
- stub_tcp_connection
26
+ notification
23
27
  end
24
28
 
25
- def stub_tcp_connection
26
- allow_any_instance_of(Rpush::Daemon::TcpConnection).to receive_messages(connect_socket: [tcp_socket, ssl_socket])
27
- allow_any_instance_of(Rpush::Daemon::TcpConnection).to receive_messages(setup_ssl_context: double.as_null_object)
28
- stub_const('Rpush::Daemon::TcpConnection::IO', io_double)
29
- allow(Rpush::Daemon::Apns::FeedbackReceiver).to receive_messages(new: double.as_null_object)
30
- end
29
+ let(:app) { create_app }
30
+ let(:notification) { create_notification(app) }
31
+
32
+ let(:fake_client) {
33
+ double(
34
+ prepare_request: fake_http2_request,
35
+ close: 'ok',
36
+ call_async: 'ok',
37
+ join: 'ok',
38
+ on: 'ok'
39
+ )
40
+ }
41
+ let(:fake_http2_request) { double }
42
+ let(:fake_http_resp_headers) {
43
+ {
44
+ ":status" => "200",
45
+ "apns-id"=>"C6D65840-5E3F-785A-4D91-B97D305C12F6"
46
+ }
47
+ }
48
+ let(:fake_http_resp_body) { '' }
31
49
 
32
50
  before do
33
- Rpush.config.push_poll = 5
51
+ Rpush.config.push_poll = 0.5
52
+
53
+ allow(NetHttp2::Client).
54
+ to receive(:new).and_return(fake_client)
55
+ allow(fake_http2_request).
56
+ to receive(:on).with(:headers).
57
+ and_yield(fake_http_resp_headers)
58
+ allow(fake_http2_request).
59
+ to receive(:on).with(:body_chunk).
60
+ and_yield(fake_http_resp_body)
61
+ allow(fake_http2_request).
62
+ to receive(:on).with(:close).
63
+ and_yield
64
+
34
65
  Rpush.embed
35
66
  end
36
67
 
68
+ after do
69
+ timeout { Rpush.shutdown }
70
+ end
71
+
37
72
  it 'delivers a notification successfully' do
38
73
  expect do
39
- Timeout.timeout(timeout) do
40
- until notification.delivered
41
- notification.reload
42
- sleep 0.1
43
- end
74
+ until notification.delivered
75
+ notification.reload
76
+ sleep 0.1
44
77
  end
45
78
  end.to change(notification, :delivered).to(true)
46
79
  end
47
-
48
- after { Timeout.timeout(timeout) { Rpush.shutdown } }
49
80
  end