rpush_extended 3.2.5

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 (248) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +365 -0
  3. data/LICENSE +7 -0
  4. data/README.md +393 -0
  5. data/bin/rpush +4 -0
  6. data/lib/generators/rpush_config_generator.rb +7 -0
  7. data/lib/generators/rpush_migration_generator.rb +66 -0
  8. data/lib/generators/templates/add_adm.rb +23 -0
  9. data/lib/generators/templates/add_alert_is_json_to_rapns_notifications.rb +9 -0
  10. data/lib/generators/templates/add_app_to_rapns.rb +11 -0
  11. data/lib/generators/templates/add_fail_after_to_rpush_notifications.rb +9 -0
  12. data/lib/generators/templates/add_gcm.rb +117 -0
  13. data/lib/generators/templates/add_rpush.rb +402 -0
  14. data/lib/generators/templates/add_wpns.rb +16 -0
  15. data/lib/generators/templates/create_rapns_apps.rb +16 -0
  16. data/lib/generators/templates/create_rapns_feedback.rb +25 -0
  17. data/lib/generators/templates/create_rapns_notifications.rb +36 -0
  18. data/lib/generators/templates/rename_rapns_to_rpush.rb +87 -0
  19. data/lib/generators/templates/rpush.rb +135 -0
  20. data/lib/generators/templates/rpush_2_0_0_updates.rb +79 -0
  21. data/lib/generators/templates/rpush_2_1_0_updates.rb +11 -0
  22. data/lib/generators/templates/rpush_2_6_0_updates.rb +10 -0
  23. data/lib/generators/templates/rpush_2_7_0_updates.rb +12 -0
  24. data/lib/generators/templates/rpush_3_0_0_updates.rb +11 -0
  25. data/lib/generators/templates/rpush_3_0_1_updates.rb +13 -0
  26. data/lib/generators/templates/rpush_3_1_0_add_pushy.rb +9 -0
  27. data/lib/generators/templates/rpush_3_1_1_updates.rb +15 -0
  28. data/lib/generators/templates/rpush_3_2_0_add_apns_p8.rb +15 -0
  29. data/lib/generators/templates/rpush_3_2_4_updates.rb +9 -0
  30. data/lib/generators/templates/rpush_3_3_0_updates.rb +9 -0
  31. data/lib/generators/templates/rpush_3_3_1_updates.rb +11 -0
  32. data/lib/rpush/apns_feedback.rb +17 -0
  33. data/lib/rpush/cli.rb +213 -0
  34. data/lib/rpush/client/active_model/adm/app.rb +23 -0
  35. data/lib/rpush/client/active_model/adm/data_validator.rb +14 -0
  36. data/lib/rpush/client/active_model/adm/notification.rb +28 -0
  37. data/lib/rpush/client/active_model/apns/app.rb +37 -0
  38. data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +16 -0
  39. data/lib/rpush/client/active_model/apns/device_token_format_validator.rb +14 -0
  40. data/lib/rpush/client/active_model/apns/notification.rb +104 -0
  41. data/lib/rpush/client/active_model/apns2/app.rb +15 -0
  42. data/lib/rpush/client/active_model/apns2/notification.rb +9 -0
  43. data/lib/rpush/client/active_model/apnsp8/app.rb +23 -0
  44. data/lib/rpush/client/active_model/apnsp8/notification.rb +9 -0
  45. data/lib/rpush/client/active_model/gcm/app.rb +19 -0
  46. data/lib/rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +14 -0
  47. data/lib/rpush/client/active_model/gcm/notification.rb +59 -0
  48. data/lib/rpush/client/active_model/notification.rb +22 -0
  49. data/lib/rpush/client/active_model/payload_data_size_validator.rb +13 -0
  50. data/lib/rpush/client/active_model/pushy/app.rb +20 -0
  51. data/lib/rpush/client/active_model/pushy/notification.rb +31 -0
  52. data/lib/rpush/client/active_model/pushy/time_to_live_validator.rb +14 -0
  53. data/lib/rpush/client/active_model/registration_ids_count_validator.rb +13 -0
  54. data/lib/rpush/client/active_model/wns/app.rb +23 -0
  55. data/lib/rpush/client/active_model/wns/notification.rb +32 -0
  56. data/lib/rpush/client/active_model/wpns/app.rb +13 -0
  57. data/lib/rpush/client/active_model/wpns/notification.rb +28 -0
  58. data/lib/rpush/client/active_model.rb +34 -0
  59. data/lib/rpush/client/active_record/adm/app.rb +11 -0
  60. data/lib/rpush/client/active_record/adm/notification.rb +11 -0
  61. data/lib/rpush/client/active_record/apns/app.rb +11 -0
  62. data/lib/rpush/client/active_record/apns/feedback.rb +18 -0
  63. data/lib/rpush/client/active_record/apns/notification.rb +40 -0
  64. data/lib/rpush/client/active_record/apns2/app.rb +11 -0
  65. data/lib/rpush/client/active_record/apns2/notification.rb +10 -0
  66. data/lib/rpush/client/active_record/apnsp8/app.rb +11 -0
  67. data/lib/rpush/client/active_record/apnsp8/notification.rb +10 -0
  68. data/lib/rpush/client/active_record/app.rb +13 -0
  69. data/lib/rpush/client/active_record/gcm/app.rb +11 -0
  70. data/lib/rpush/client/active_record/gcm/notification.rb +11 -0
  71. data/lib/rpush/client/active_record/notification.rb +42 -0
  72. data/lib/rpush/client/active_record/pushy/app.rb +11 -0
  73. data/lib/rpush/client/active_record/pushy/notification.rb +11 -0
  74. data/lib/rpush/client/active_record/wns/app.rb +11 -0
  75. data/lib/rpush/client/active_record/wns/badge_notification.rb +15 -0
  76. data/lib/rpush/client/active_record/wns/notification.rb +11 -0
  77. data/lib/rpush/client/active_record/wns/raw_notification.rb +13 -0
  78. data/lib/rpush/client/active_record/wpns/app.rb +11 -0
  79. data/lib/rpush/client/active_record/wpns/notification.rb +11 -0
  80. data/lib/rpush/client/active_record.rb +33 -0
  81. data/lib/rpush/client/redis/adm/app.rb +14 -0
  82. data/lib/rpush/client/redis/adm/notification.rb +11 -0
  83. data/lib/rpush/client/redis/apns/app.rb +11 -0
  84. data/lib/rpush/client/redis/apns/feedback.rb +20 -0
  85. data/lib/rpush/client/redis/apns/notification.rb +11 -0
  86. data/lib/rpush/client/redis/apns2/app.rb +11 -0
  87. data/lib/rpush/client/redis/apns2/notification.rb +11 -0
  88. data/lib/rpush/client/redis/apnsp8/app.rb +11 -0
  89. data/lib/rpush/client/redis/apnsp8/notification.rb +11 -0
  90. data/lib/rpush/client/redis/app.rb +29 -0
  91. data/lib/rpush/client/redis/gcm/app.rb +11 -0
  92. data/lib/rpush/client/redis/gcm/notification.rb +11 -0
  93. data/lib/rpush/client/redis/notification.rb +74 -0
  94. data/lib/rpush/client/redis/pushy/app.rb +16 -0
  95. data/lib/rpush/client/redis/pushy/notification.rb +18 -0
  96. data/lib/rpush/client/redis/wns/app.rb +14 -0
  97. data/lib/rpush/client/redis/wns/badge_notification.rb +15 -0
  98. data/lib/rpush/client/redis/wns/notification.rb +11 -0
  99. data/lib/rpush/client/redis/wns/raw_notification.rb +11 -0
  100. data/lib/rpush/client/redis/wpns/app.rb +11 -0
  101. data/lib/rpush/client/redis/wpns/notification.rb +11 -0
  102. data/lib/rpush/client/redis.rb +56 -0
  103. data/lib/rpush/configuration.rb +115 -0
  104. data/lib/rpush/daemon/adm/delivery.rb +226 -0
  105. data/lib/rpush/daemon/adm.rb +9 -0
  106. data/lib/rpush/daemon/apns/delivery.rb +43 -0
  107. data/lib/rpush/daemon/apns/feedback_receiver.rb +90 -0
  108. data/lib/rpush/daemon/apns.rb +17 -0
  109. data/lib/rpush/daemon/apns2/delivery.rb +127 -0
  110. data/lib/rpush/daemon/apns2.rb +10 -0
  111. data/lib/rpush/daemon/apnsp8/delivery.rb +166 -0
  112. data/lib/rpush/daemon/apnsp8/token.rb +43 -0
  113. data/lib/rpush/daemon/apnsp8.rb +10 -0
  114. data/lib/rpush/daemon/app_runner.rb +190 -0
  115. data/lib/rpush/daemon/batch.rb +138 -0
  116. data/lib/rpush/daemon/constants.rb +59 -0
  117. data/lib/rpush/daemon/delivery.rb +46 -0
  118. data/lib/rpush/daemon/delivery_error.rb +27 -0
  119. data/lib/rpush/daemon/dispatcher/apns_http2.rb +51 -0
  120. data/lib/rpush/daemon/dispatcher/apns_tcp.rb +152 -0
  121. data/lib/rpush/daemon/dispatcher/apnsp8_http2.rb +33 -0
  122. data/lib/rpush/daemon/dispatcher/http.rb +21 -0
  123. data/lib/rpush/daemon/dispatcher/tcp.rb +22 -0
  124. data/lib/rpush/daemon/dispatcher_loop.rb +73 -0
  125. data/lib/rpush/daemon/errors.rb +18 -0
  126. data/lib/rpush/daemon/feeder.rb +69 -0
  127. data/lib/rpush/daemon/gcm/delivery.rb +241 -0
  128. data/lib/rpush/daemon/gcm.rb +9 -0
  129. data/lib/rpush/daemon/interruptible_sleep.rb +24 -0
  130. data/lib/rpush/daemon/loggable.rb +33 -0
  131. data/lib/rpush/daemon/proc_title.rb +17 -0
  132. data/lib/rpush/daemon/pushy/delivery.rb +90 -0
  133. data/lib/rpush/daemon/pushy.rb +9 -0
  134. data/lib/rpush/daemon/queue_payload.rb +12 -0
  135. data/lib/rpush/daemon/retry_header_parser.rb +23 -0
  136. data/lib/rpush/daemon/retryable_error.rb +22 -0
  137. data/lib/rpush/daemon/ring_buffer.rb +16 -0
  138. data/lib/rpush/daemon/rpc/client.rb +27 -0
  139. data/lib/rpush/daemon/rpc/server.rb +82 -0
  140. data/lib/rpush/daemon/rpc.rb +9 -0
  141. data/lib/rpush/daemon/service_config_methods.rb +51 -0
  142. data/lib/rpush/daemon/signal_handler.rb +75 -0
  143. data/lib/rpush/daemon/store/active_record/reconnectable.rb +80 -0
  144. data/lib/rpush/daemon/store/active_record.rb +214 -0
  145. data/lib/rpush/daemon/store/interface.rb +20 -0
  146. data/lib/rpush/daemon/store/redis.rb +166 -0
  147. data/lib/rpush/daemon/string_helpers.rb +15 -0
  148. data/lib/rpush/daemon/synchronizer.rb +62 -0
  149. data/lib/rpush/daemon/tcp_connection.rb +190 -0
  150. data/lib/rpush/daemon/wns/badge_request.rb +32 -0
  151. data/lib/rpush/daemon/wns/delivery.rb +178 -0
  152. data/lib/rpush/daemon/wns/post_request.rb +33 -0
  153. data/lib/rpush/daemon/wns/raw_request.rb +22 -0
  154. data/lib/rpush/daemon/wns/toast_request.rb +54 -0
  155. data/lib/rpush/daemon/wns.rb +9 -0
  156. data/lib/rpush/daemon/wpns/delivery.rb +132 -0
  157. data/lib/rpush/daemon/wpns.rb +9 -0
  158. data/lib/rpush/daemon.rb +179 -0
  159. data/lib/rpush/deprecatable.rb +24 -0
  160. data/lib/rpush/deprecation.rb +26 -0
  161. data/lib/rpush/embed.rb +41 -0
  162. data/lib/rpush/logger.rb +92 -0
  163. data/lib/rpush/multi_json_helper.rb +16 -0
  164. data/lib/rpush/plugin.rb +44 -0
  165. data/lib/rpush/push.rb +11 -0
  166. data/lib/rpush/reflectable.rb +13 -0
  167. data/lib/rpush/reflection_collection.rb +44 -0
  168. data/lib/rpush/reflection_public_methods.rb +11 -0
  169. data/lib/rpush/version.rb +14 -0
  170. data/lib/rpush.rb +43 -0
  171. data/lib/tasks/quality.rake +35 -0
  172. data/lib/tasks/test.rake +69 -0
  173. data/spec/.rubocop.yml +4 -0
  174. data/spec/functional/adm_spec.rb +50 -0
  175. data/spec/functional/apns2_spec.rb +232 -0
  176. data/spec/functional/apns_spec.rb +162 -0
  177. data/spec/functional/cli_spec.rb +36 -0
  178. data/spec/functional/embed_spec.rb +49 -0
  179. data/spec/functional/gcm_spec.rb +46 -0
  180. data/spec/functional/new_app_spec.rb +44 -0
  181. data/spec/functional/pushy_spec.rb +22 -0
  182. data/spec/functional/retry_spec.rb +42 -0
  183. data/spec/functional/synchronization_spec.rb +97 -0
  184. data/spec/functional/wpns_spec.rb +71 -0
  185. data/spec/functional_spec_helper.rb +32 -0
  186. data/spec/spec_helper.rb +69 -0
  187. data/spec/support/active_record_setup.rb +73 -0
  188. data/spec/support/cert_with_password.pem +90 -0
  189. data/spec/support/cert_without_password.pem +59 -0
  190. data/spec/support/config/database.yml +44 -0
  191. data/spec/support/simplecov_helper.rb +24 -0
  192. data/spec/support/simplecov_quality_formatter.rb +12 -0
  193. data/spec/tmp/.gitkeep +0 -0
  194. data/spec/unit/apns_feedback_spec.rb +28 -0
  195. data/spec/unit/client/active_record/adm/app_spec.rb +58 -0
  196. data/spec/unit/client/active_record/adm/notification_spec.rb +43 -0
  197. data/spec/unit/client/active_record/apns/app_spec.rb +29 -0
  198. data/spec/unit/client/active_record/apns/feedback_spec.rb +9 -0
  199. data/spec/unit/client/active_record/apns/notification_spec.rb +324 -0
  200. data/spec/unit/client/active_record/app_spec.rb +30 -0
  201. data/spec/unit/client/active_record/gcm/app_spec.rb +4 -0
  202. data/spec/unit/client/active_record/gcm/notification_spec.rb +67 -0
  203. data/spec/unit/client/active_record/notification_spec.rb +21 -0
  204. data/spec/unit/client/active_record/pushy/app_spec.rb +17 -0
  205. data/spec/unit/client/active_record/pushy/notification_spec.rb +65 -0
  206. data/spec/unit/client/active_record/wns/badge_notification_spec.rb +15 -0
  207. data/spec/unit/client/active_record/wns/raw_notification_spec.rb +26 -0
  208. data/spec/unit/client/active_record/wpns/app_spec.rb +4 -0
  209. data/spec/unit/client/active_record/wpns/notification_spec.rb +21 -0
  210. data/spec/unit/configuration_spec.rb +46 -0
  211. data/spec/unit/daemon/adm/delivery_spec.rb +253 -0
  212. data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +11 -0
  213. data/spec/unit/daemon/apns/delivery_spec.rb +108 -0
  214. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +119 -0
  215. data/spec/unit/daemon/app_runner_spec.rb +188 -0
  216. data/spec/unit/daemon/batch_spec.rb +169 -0
  217. data/spec/unit/daemon/delivery_error_spec.rb +13 -0
  218. data/spec/unit/daemon/delivery_spec.rb +51 -0
  219. data/spec/unit/daemon/dispatcher/http_spec.rb +34 -0
  220. data/spec/unit/daemon/dispatcher/tcp_spec.rb +32 -0
  221. data/spec/unit/daemon/dispatcher_loop_spec.rb +53 -0
  222. data/spec/unit/daemon/feeder_spec.rb +96 -0
  223. data/spec/unit/daemon/gcm/delivery_spec.rb +387 -0
  224. data/spec/unit/daemon/proc_title_spec.rb +11 -0
  225. data/spec/unit/daemon/pushy/delivery_spec.rb +159 -0
  226. data/spec/unit/daemon/retryable_error_spec.rb +14 -0
  227. data/spec/unit/daemon/service_config_methods_spec.rb +36 -0
  228. data/spec/unit/daemon/signal_handler_spec.rb +99 -0
  229. data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +165 -0
  230. data/spec/unit/daemon/store/active_record_spec.rb +357 -0
  231. data/spec/unit/daemon/store/redis_spec.rb +365 -0
  232. data/spec/unit/daemon/tcp_connection_spec.rb +292 -0
  233. data/spec/unit/daemon/wns/delivery_spec.rb +176 -0
  234. data/spec/unit/daemon/wns/post_request_spec.rb +117 -0
  235. data/spec/unit/daemon/wpns/delivery_spec.rb +167 -0
  236. data/spec/unit/daemon_spec.rb +138 -0
  237. data/spec/unit/deprecatable_spec.rb +32 -0
  238. data/spec/unit/deprecation_spec.rb +15 -0
  239. data/spec/unit/embed_spec.rb +47 -0
  240. data/spec/unit/logger_spec.rb +127 -0
  241. data/spec/unit/notification_shared.rb +53 -0
  242. data/spec/unit/plugin_spec.rb +36 -0
  243. data/spec/unit/push_spec.rb +34 -0
  244. data/spec/unit/reflectable_spec.rb +27 -0
  245. data/spec/unit/reflection_collection_spec.rb +26 -0
  246. data/spec/unit/rpush_spec.rb +8 -0
  247. data/spec/unit_spec_helper.rb +26 -0
  248. metadata +709 -0
@@ -0,0 +1,232 @@
1
+ require 'functional_spec_helper'
2
+
3
+ describe 'APNs http2 adapter' do
4
+ let(:fake_client) {
5
+ double(
6
+ prepare_request: fake_http2_request,
7
+ close: 'ok',
8
+ call_async: 'ok',
9
+ join: 'ok',
10
+ on: 'ok'
11
+ )
12
+ }
13
+ let(:app) { create_app }
14
+ let(:fake_device_token) { 'a' * 108 }
15
+ let(:fake_http2_request) { double }
16
+ let(:fake_http_resp_headers) {
17
+ {
18
+ ":status" => "200",
19
+ "apns-id"=>"C6D65840-5E3F-785A-4D91-B97D305C12F6"
20
+ }
21
+ }
22
+ let(:fake_http_resp_body) { '' }
23
+ let(:notification_data) { nil }
24
+
25
+ before do
26
+ Rpush.config.push_poll = 0.5
27
+ allow(NetHttp2::Client).
28
+ to receive(:new).and_return(fake_client)
29
+ allow(fake_http2_request).
30
+ to receive(:on).with(:headers).
31
+ and_yield(fake_http_resp_headers)
32
+ allow(fake_http2_request).
33
+ to receive(:on).with(:body_chunk).
34
+ and_yield(fake_http_resp_body)
35
+ allow(fake_http2_request).
36
+ to receive(:on).with(:close).
37
+ and_yield
38
+ end
39
+
40
+ def create_app
41
+ app = Rpush::Apns2::App.new
42
+ app.certificate = TEST_CERT
43
+ app.name = 'test'
44
+ app.environment = 'development'
45
+ app.save!
46
+ app
47
+ end
48
+
49
+ def create_notification
50
+ notification = Rpush::Apns2::Notification.new
51
+ notification.app = app
52
+ notification.sound = 'default'
53
+ notification.alert = 'test'
54
+ notification.device_token = fake_device_token
55
+ notification.data = notification_data
56
+ notification.content_available = 1
57
+ notification.save!
58
+ notification
59
+ end
60
+
61
+ it 'delivers a notification successfully' do
62
+ notification = create_notification
63
+
64
+ thread = nil
65
+ expect(fake_http2_request).
66
+ to receive(:on).with(:close) { |&block|
67
+ # imitate HTTP2 delay
68
+ thread = Thread.new { sleep(0.01); block.call }
69
+ }
70
+ expect(fake_client).to receive(:join) { thread.join }
71
+
72
+ expect(fake_client)
73
+ .to receive(:prepare_request)
74
+ .with(
75
+ :post,
76
+ "/3/device/#{fake_device_token}",
77
+ { body: "{\"aps\":{\"alert\":\"test\",\"sound\":\"default\",\"content-available\":1}}",
78
+ headers: {} }
79
+ )
80
+ .and_return(fake_http2_request)
81
+
82
+ expect do
83
+ Rpush.push
84
+ notification.reload
85
+ end.to change(notification, :delivered).to(true)
86
+ end
87
+
88
+ context 'when there is "headers" field in a data' do
89
+ let(:bundle_id) { 'some.example.com' }
90
+ let(:notification_data) {
91
+ {
92
+ 'headers' => { 'apns-topic' => bundle_id },
93
+ 'some_field' => 'some value'
94
+ }
95
+ }
96
+
97
+ it 'delivers notification with custom headers' do
98
+ notification = create_notification
99
+
100
+ expect(fake_client)
101
+ .to receive(:prepare_request)
102
+ .with(
103
+ :post,
104
+ "/3/device/#{fake_device_token}",
105
+ { body: "{\"aps\":{\"alert\":\"test\",\"sound\":\"default\","\
106
+ "\"content-available\":1},\"some_field\":\"some value\"}",
107
+ headers: { 'apns-topic' => bundle_id }
108
+ }
109
+ ).and_return(fake_http2_request)
110
+
111
+ expect do
112
+ Rpush.push
113
+ notification.reload
114
+ end.to change(notification, :delivered).to(true)
115
+ end
116
+ end
117
+
118
+ describe 'delivery failures' do
119
+ context 'when response is about incorrect request' do
120
+ let(:fake_http_resp_headers) {
121
+ {
122
+ ":status" => "404",
123
+ "apns-id"=>"C6D65840-5E3F-785A-4D91-B97D305C12F6"
124
+ }
125
+ }
126
+
127
+ it 'fails to deliver a notification' do
128
+ notification = create_notification
129
+ expect do
130
+ Rpush.push
131
+ notification.reload
132
+ end.to change(notification, :failed).to(true)
133
+ end
134
+
135
+ it 'reflects :notification_id_failed' do
136
+ Rpush.reflect do |on|
137
+ on.notification_id_failed do |app, id, code, descr|
138
+ expect(app).to be_kind_of(Rpush::Client::Apns2::App)
139
+ expect(id).to eq 1
140
+ expect(code).to eq 404
141
+ expect(descr).to be_nil
142
+ end
143
+ end
144
+
145
+ notification = create_notification
146
+ Rpush.push
147
+ end
148
+ end
149
+
150
+ context 'when response returns 500 error for APNs maintenance' do
151
+ let(:fake_http_resp_headers) {
152
+ {
153
+ ":status" => "500",
154
+ "apns-id"=>"C6D65840-5E3F-785A-4D91-B97D305C12F6"
155
+ }
156
+ }
157
+
158
+ it 'fails but retries delivery several times' do
159
+ notification = create_notification
160
+ expect do
161
+ Rpush.push
162
+ notification.reload
163
+ end.to change(notification, :retries)
164
+ end
165
+
166
+ it 'reflects :notification_id_will_retry' do
167
+ Rpush.reflect do |on|
168
+ on.notification_id_will_retry do |app, id, timer|
169
+ expect(app).to be_kind_of(Rpush::Client::Apns2::App)
170
+ expect(id).to eq 1
171
+ end
172
+ end
173
+
174
+ notification = create_notification
175
+ Rpush.push
176
+ end
177
+ end
178
+
179
+ context 'when there is SocketError' do
180
+ before(:each) do
181
+ expect(fake_client).to receive(:call_async) { raise(SocketError) }
182
+ end
183
+
184
+ it 'fails but retries delivery several times' do
185
+ notification = create_notification
186
+ expect do
187
+ Rpush.push
188
+ notification.reload
189
+ end.to change(notification, :retries)
190
+ end
191
+
192
+ it 'reflects :notification_id_will_retry' do
193
+ Rpush.reflect do |on|
194
+ on.notification_id_will_retry do |app, id, timer|
195
+ expect(app).to be_kind_of(Rpush::Client::Apns2::App)
196
+ expect(id).to eq 1
197
+ expect(timer).to be_kind_of(Time)
198
+ end
199
+ end
200
+
201
+ notification = create_notification
202
+ Rpush.push
203
+ end
204
+ end
205
+
206
+ context 'when any StandardError occurs' do
207
+ before(:each) do
208
+ expect(fake_client).to receive(:call_async) { raise(StandardError) }
209
+ end
210
+
211
+ it 'marks notification failed' do
212
+ notification = create_notification
213
+ expect do
214
+ Rpush.push
215
+ notification.reload
216
+ end.to change(notification, :failed).to(true)
217
+ end
218
+
219
+ it 'reflects :error' do
220
+ Rpush.reflect do |on|
221
+ on.error do |error|
222
+ expect(error).to be_kind_of(StandardError)
223
+ reflector.accept
224
+ end
225
+ end
226
+
227
+ notification = create_notification
228
+ Rpush.push
229
+ end
230
+ end
231
+ end
232
+ end
@@ -0,0 +1,162 @@
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
@@ -0,0 +1,36 @@
1
+ require 'functional_spec_helper'
2
+
3
+ describe Rpush::CLI do
4
+ def create_app
5
+ app = Rpush::Apns::App.new
6
+ app.certificate = TEST_CERT
7
+ app.name = 'test'
8
+ app.environment = 'sandbox'
9
+ app.save!
10
+ app
11
+ end
12
+
13
+ describe 'status' do
14
+ let(:tcp_socket) { double(TCPSocket, setsockopt: nil, close: nil) }
15
+ let(:ssl_socket) { double(OpenSSL::SSL::SSLSocket, :sync= => nil, connect: nil, write: nil, flush: nil, read: nil, close: nil) }
16
+ let(:io_double) { double(select: nil) }
17
+
18
+ before do
19
+ create_app
20
+ stub_tcp_connection(tcp_socket, ssl_socket, io_double)
21
+ Rpush.embed
22
+
23
+ timeout do
24
+ Thread.pass until File.exist?(Rpush::Daemon::Rpc.socket_path)
25
+ end
26
+ end
27
+
28
+ after { timeout { Rpush.shutdown } }
29
+
30
+ it 'prints the status' do
31
+ expect(subject).to receive(:configure_rpush) { true }
32
+ expect(subject).to receive(:puts).with(/app_runners:/)
33
+ subject.status
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,49 @@
1
+ require 'functional_spec_helper'
2
+
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
12
+ app.certificate = TEST_CERT
13
+ app.name = 'test'
14
+ app.environment = 'sandbox'
15
+ app.save!
16
+
17
+ notification.app = app
18
+ notification.alert = 'test'
19
+ notification.device_token = 'a' * 108
20
+ notification.save!
21
+
22
+ stub_tcp_connection
23
+ end
24
+
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
31
+
32
+ before do
33
+ Rpush.config.push_poll = 5
34
+ Rpush.embed
35
+ end
36
+
37
+ it 'delivers a notification successfully' do
38
+ expect do
39
+ Timeout.timeout(timeout) do
40
+ until notification.delivered
41
+ notification.reload
42
+ sleep 0.1
43
+ end
44
+ end
45
+ end.to change(notification, :delivered).to(true)
46
+ end
47
+
48
+ after { Timeout.timeout(timeout) { Rpush.shutdown } }
49
+ end
@@ -0,0 +1,46 @@
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
@@ -0,0 +1,44 @@
1
+ require 'functional_spec_helper'
2
+
3
+ describe 'New app loading' do
4
+ let(:timeout) { 10 }
5
+ let(:app) { create_app }
6
+ let(:tcp_socket) { double(TCPSocket, setsockopt: nil, close: nil) }
7
+ let(:ssl_socket) { double(OpenSSL::SSL::SSLSocket, :sync= => nil, connect: nil, write: nil, flush: nil, read: nil, close: nil) }
8
+ let(:io_double) { double(select: nil) }
9
+
10
+ before do
11
+ stub_tcp_connection
12
+ end
13
+
14
+ def create_app
15
+ app = Rpush::Apns::App.new
16
+ app.certificate = TEST_CERT
17
+ app.name = 'test'
18
+ app.environment = 'sandbox'
19
+ app.save!
20
+ app
21
+ end
22
+
23
+ def create_notification
24
+ notification = Rpush::Apns::Notification.new
25
+ notification.app = app
26
+ notification.alert = 'test'
27
+ notification.device_token = 'a' * 108
28
+ notification.save!
29
+ notification
30
+ end
31
+
32
+ def stub_tcp_connection
33
+ allow_any_instance_of(Rpush::Daemon::TcpConnection).to receive_messages(connect_socket: [tcp_socket, ssl_socket])
34
+ allow_any_instance_of(Rpush::Daemon::TcpConnection).to receive_messages(setup_ssl_context: double.as_null_object)
35
+ stub_const('Rpush::Daemon::TcpConnection::IO', io_double)
36
+ end
37
+
38
+ it 'delivers a notification successfully' do
39
+ notification = create_notification
40
+ Rpush.push
41
+ notification.reload
42
+ expect(notification.delivered).to eq(true)
43
+ end
44
+ end
@@ -0,0 +1,22 @@
1
+ require 'functional_spec_helper'
2
+
3
+ describe 'Pushy' do
4
+ let(:external_device_id) { '5a622ae5813e2875bfdbe496' }
5
+ let(:response) { instance_double('Net::HTTPResponse', code: 200, body: { id: external_device_id }.to_json) }
6
+ let(:http) { instance_double('Net::HTTP::Persistent', request: response, shutdown: nil) }
7
+ let(:app) { Rpush::Pushy::App.create!(name: 'MyApp', api_key: 'my_api_key') }
8
+
9
+ let(:notification) do
10
+ Rpush::Pushy::Notification.create!(app: app, data: { message: 'test' }, registration_ids: ['id'])
11
+ end
12
+
13
+ before do
14
+ allow(Net::HTTP::Persistent).to receive_messages(new: http)
15
+ end
16
+
17
+ it 'deliveres a notification successfully' do
18
+ expect { Rpush.push }.to change { notification.reload.delivered }.to(true)
19
+ end
20
+
21
+ it { expect { Rpush.push }.to change { notification.reload.external_device_id }.to(external_device_id) }
22
+ end
@@ -0,0 +1,42 @@
1
+ require 'functional_spec_helper'
2
+
3
+ describe 'Retries' 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
+ Rpush::Daemon.common_init
11
+
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.save!
20
+
21
+ Modis.with_connection do |redis|
22
+ redis.del(Rpush::Client::Redis::Notification.absolute_pending_namespace)
23
+ end
24
+
25
+ allow(Net::HTTP::Persistent).to receive_messages(new: http)
26
+ allow(response).to receive_messages(body: JSON.dump(results: [{ message_id: notification.registration_ids.first.to_s }]))
27
+ end
28
+
29
+ it 'delivers a notification due to be retried' do
30
+ Rpush::Daemon.store.mark_retryable(notification, Time.now - 1.minute)
31
+ Rpush.push
32
+ notification.reload
33
+ expect(notification.delivered).to eq(true)
34
+ end
35
+
36
+ it 'does not deliver a notification not due to be retried' do
37
+ Rpush::Daemon.store.mark_retryable(notification, Time.now + 1.minute)
38
+ Rpush.push
39
+ notification.reload
40
+ expect(notification.delivered).to eq(false)
41
+ end
42
+ end