rpush_extended 3.2.5

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