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,188 @@
1
+ require 'unit_spec_helper'
2
+ require 'rpush/daemon/store/active_record'
3
+
4
+ module Rpush
5
+ module AppRunnerSpecService
6
+ class App < Rpush::App
7
+ end
8
+ end
9
+
10
+ module Daemon
11
+ module AppRunnerSpecService
12
+ extend ServiceConfigMethods
13
+
14
+ class ServiceLoop
15
+ def initialize(*)
16
+ end
17
+
18
+ def start
19
+ end
20
+
21
+ def stop
22
+ end
23
+ end
24
+
25
+ dispatcher :http
26
+ loops ServiceLoop
27
+
28
+ class Delivery
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ describe Rpush::Daemon::AppRunner, 'enqueue' do
35
+ let(:app) { double(id: 1, name: 'Test', connections: 1) }
36
+ let(:notification) { double(app_id: 1) }
37
+ let(:runner) { double(Rpush::Daemon::AppRunner, enqueue: nil, start_dispatchers: nil, start_loops: nil, stop: nil) }
38
+ let(:logger) { double(Rpush::Logger, error: nil, info: nil) }
39
+
40
+ before do
41
+ allow(Rpush).to receive_messages(logger: logger)
42
+ allow(Rpush::Daemon::ProcTitle).to receive(:update)
43
+ allow(Rpush::Daemon::AppRunner).to receive_messages(new: runner)
44
+ Rpush::Daemon::AppRunner.start_app(app)
45
+ end
46
+
47
+ after { Rpush::Daemon::AppRunner.stop }
48
+
49
+ it 'enqueues notifications on the runner' do
50
+ expect(runner).to receive(:enqueue).with([notification])
51
+ Rpush::Daemon::AppRunner.enqueue([notification])
52
+ end
53
+
54
+ it 'starts the app if a runner does not exist' do
55
+ notification = double(app_id: 3)
56
+ new_app = double(Rpush::App, id: 3, name: 'NewApp', connections: 1)
57
+ Rpush::Daemon.store = double(app: new_app)
58
+ Rpush::Daemon::AppRunner.enqueue([notification])
59
+ expect(Rpush::Daemon::AppRunner.app_running?(new_app)).to eq(true)
60
+ end
61
+ end
62
+
63
+ describe Rpush::Daemon::AppRunner, 'start_app' do
64
+ let(:app) { double(id: 1, name: 'test', connections: 1) }
65
+ let(:runner) { double(Rpush::Daemon::AppRunner, enqueue: nil, start_dispatchers: nil, stop: nil) }
66
+ let(:logger) { double(Rpush::Logger, error: nil, info: nil) }
67
+
68
+ before do
69
+ allow(Rpush).to receive_messages(logger: logger)
70
+ end
71
+
72
+ it 'logs an error if the runner could not be started' do
73
+ expect(Rpush::Daemon::AppRunner).to receive(:new).with(app).and_return(runner)
74
+ allow(runner).to receive(:start_dispatchers).and_raise(StandardError)
75
+ expect(Rpush.logger).to receive(:error)
76
+ Rpush::Daemon::AppRunner.start_app(app)
77
+ end
78
+ end
79
+
80
+ describe Rpush::Daemon::AppRunner, 'debug' do
81
+ let(:app) do
82
+ double(Rpush::AppRunnerSpecService::App, id: 1, name: 'test', connections: 1,
83
+ environment: 'development', certificate: TEST_CERT,
84
+ service_name: 'app_runner_spec_service')
85
+ end
86
+ let(:logger) { double(Rpush::Logger, info: nil) }
87
+ let(:store) { double(all_apps: [app], release_connection: nil) }
88
+
89
+ before do
90
+ allow(Rpush::Daemon).to receive_messages(config: {}, store: store)
91
+ allow(Rpush).to receive_messages(logger: logger)
92
+ Rpush::Daemon::AppRunner.start_app(app)
93
+ end
94
+
95
+ after { Rpush::Daemon::AppRunner.stop_app(app.id) }
96
+
97
+ it 'returns the app runner status' do
98
+ expect(Rpush::Daemon::AppRunner.status.key?(:app_runners)).to eq(true)
99
+ end
100
+ end
101
+
102
+ describe Rpush::Daemon::AppRunner do
103
+ let(:app) do
104
+ double(Rpush::AppRunnerSpecService::App, environment: :sandbox,
105
+ connections: 1, service_name: 'app_runner_spec_service',
106
+ name: 'test')
107
+ end
108
+ let(:runner) { Rpush::Daemon::AppRunner.new(app) }
109
+ let(:logger) { double(Rpush::Logger, info: nil) }
110
+ let(:queue) { Queue.new }
111
+ let(:service_loop) { double(Rpush::Daemon::AppRunnerSpecService::ServiceLoop, start: nil, stop: nil) }
112
+ let(:dispatcher_loop) { double(Rpush::Daemon::DispatcherLoop, stop: nil, start: nil) }
113
+ let(:store) { double(Rpush::Daemon::Store::ActiveRecord, release_connection: nil) }
114
+
115
+ before do
116
+ allow(Rpush::Daemon::DispatcherLoop).to receive_messages(new: dispatcher_loop)
117
+ allow(Rpush::Daemon).to receive_messages(store: store)
118
+ allow(Rpush::Daemon::AppRunnerSpecService::ServiceLoop).to receive_messages(new: service_loop)
119
+ allow(Queue).to receive_messages(new: queue)
120
+ allow(Rpush).to receive_messages(logger: logger)
121
+ end
122
+
123
+ describe 'start' do
124
+ it 'starts a delivery dispatcher for each connection' do
125
+ allow(app).to receive_messages(connections: 2)
126
+ runner.start_dispatchers
127
+ expect(runner.num_dispatcher_loops).to eq 2
128
+ end
129
+
130
+ it 'starts the dispatcher loop' do
131
+ expect(dispatcher_loop).to receive(:start)
132
+ runner.start_dispatchers
133
+ end
134
+
135
+ it 'starts the loops' do
136
+ expect(service_loop).to receive(:start)
137
+ runner.start_loops
138
+ end
139
+ end
140
+
141
+ describe 'enqueue' do
142
+ let(:notification) { double }
143
+
144
+ it 'enqueues the batch' do
145
+ expect(queue).to receive(:push) do |queue_payload|
146
+ expect(queue_payload.notification).to eq notification
147
+ expect(queue_payload.batch).not_to be_nil
148
+ end
149
+ runner.enqueue([notification])
150
+ end
151
+
152
+ it 'reflects the notification has been enqueued' do
153
+ expect(runner).to receive(:reflect).with(:notification_enqueued, notification)
154
+ runner.enqueue([notification])
155
+ end
156
+
157
+ describe 'a service that batches deliveries' do
158
+ before do
159
+ allow(runner.send(:service)).to receive_messages(batch_deliveries?: true)
160
+ end
161
+
162
+ describe '1 notification with more than one dispatcher loop' do
163
+ it 'does not raise ArgumentError: invalid slice size' do
164
+ # https://github.com/rpush/rpush/issues/57
165
+ allow(runner).to receive(:num_dispatcher_loops).and_return(2)
166
+ runner.enqueue([notification])
167
+ end
168
+ end
169
+ end
170
+ end
171
+
172
+ describe 'stop' do
173
+ before do
174
+ runner.start_dispatchers
175
+ runner.start_loops
176
+ end
177
+
178
+ it 'stops the delivery dispatchers' do
179
+ expect(dispatcher_loop).to receive(:stop)
180
+ runner.stop
181
+ end
182
+
183
+ it 'stop the loops' do
184
+ expect(service_loop).to receive(:stop)
185
+ runner.stop
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,169 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Rpush::Daemon::Batch do
4
+ let(:notification1) { double(:notification1, id: 1) }
5
+ let(:notification2) { double(:notification2, id: 2) }
6
+ let(:batch) { Rpush::Daemon::Batch.new([notification1, notification2]) }
7
+ let(:store) { double.as_null_object }
8
+ let(:time) { Time.now }
9
+
10
+ before do
11
+ allow(Time).to receive_messages(now: time)
12
+ allow(Rpush::Daemon).to receive_messages(store: store)
13
+ end
14
+
15
+ it 'exposes the number notifications processed' do
16
+ expect(batch.num_processed).to eq 0
17
+ end
18
+
19
+ it 'increments the processed notifications count' do
20
+ expect { batch.notification_processed }.to change(batch, :num_processed).to(1)
21
+ end
22
+
23
+ it 'completes the batch when all notifications have been processed' do
24
+ expect(batch).to receive(:complete)
25
+ 2.times { batch.notification_processed }
26
+ end
27
+
28
+ describe 'mark_delivered' do
29
+ it 'marks the notification as delivered immediately without persisting' do
30
+ expect(store).to receive(:mark_delivered).with(notification1, time, persist: false)
31
+ batch.mark_delivered(notification1)
32
+ end
33
+
34
+ it 'defers persisting' do
35
+ batch.mark_delivered(notification1)
36
+ expect(batch.delivered).to eq [notification1]
37
+ end
38
+ end
39
+
40
+ describe 'mark_all_delivered' do
41
+ it 'marks the notifications as delivered immediately without persisting' do
42
+ expect(store).to receive(:mark_delivered).with(notification1, time, persist: false)
43
+ expect(store).to receive(:mark_delivered).with(notification2, time, persist: false)
44
+ batch.mark_all_delivered
45
+ end
46
+
47
+ it 'defers persisting' do
48
+ batch.mark_all_delivered
49
+ expect(batch.delivered).to eq [notification1, notification2]
50
+ end
51
+ end
52
+
53
+ describe 'mark_failed' do
54
+ it 'marks the notification as failed without persisting' do
55
+ expect(store).to receive(:mark_failed).with(notification1, 1, 'an error', time, persist: false)
56
+ batch.mark_failed(notification1, 1, 'an error')
57
+ end
58
+
59
+ it 'defers persisting' do
60
+ batch.mark_failed(notification1, 1, 'an error')
61
+ expect(batch.failed).to eq([1, 'an error'] => [notification1])
62
+ end
63
+ end
64
+
65
+ describe 'mark_failed' do
66
+ it 'marks the notification as failed without persisting' do
67
+ expect(store).to receive(:mark_failed).with(notification1, 1, 'an error', time, persist: false)
68
+ expect(store).to receive(:mark_failed).with(notification2, 1, 'an error', time, persist: false)
69
+ batch.mark_all_failed(1, 'an error')
70
+ end
71
+
72
+ it 'defers persisting' do
73
+ batch.mark_all_failed(1, 'an error')
74
+ expect(batch.failed).to eq([1, 'an error'] => [notification1, notification2])
75
+ end
76
+ end
77
+
78
+ describe 'mark_retryable' do
79
+ it 'marks the notification as retryable without persisting' do
80
+ expect(store).to receive(:mark_retryable).with(notification1, time, persist: false)
81
+ batch.mark_retryable(notification1, time)
82
+ end
83
+
84
+ it 'defers persisting' do
85
+ batch.mark_retryable(notification1, time)
86
+ expect(batch.retryable).to eq(time => [notification1])
87
+ end
88
+ end
89
+
90
+ describe 'complete' do
91
+ before do
92
+ allow(Rpush).to receive_messages(logger: double.as_null_object)
93
+ allow(batch).to receive(:reflect)
94
+ end
95
+
96
+ it 'identifies as complete' do
97
+ expect do
98
+ 2.times { batch.notification_processed }
99
+ end.to change(batch, :complete?).to(true)
100
+ end
101
+
102
+ it 'reflects errors raised during completion' do
103
+ e = StandardError.new
104
+ allow(batch).to receive(:complete_delivered).and_raise(e)
105
+ expect(batch).to receive(:reflect).with(:error, e)
106
+ 2.times { batch.notification_processed }
107
+ end
108
+
109
+ describe 'delivered' do
110
+ def complete
111
+ [notification1, notification2].each do |n|
112
+ batch.mark_delivered(n)
113
+ batch.notification_processed
114
+ end
115
+ end
116
+
117
+ it 'marks the batch as delivered' do
118
+ expect(store).to receive(:mark_batch_delivered).with([notification1, notification2])
119
+ complete
120
+ end
121
+
122
+ it 'reflects the notifications were delivered' do
123
+ expect(batch).to receive(:reflect).with(:notification_delivered, notification1)
124
+ expect(batch).to receive(:reflect).with(:notification_delivered, notification2)
125
+ complete
126
+ end
127
+ end
128
+
129
+ describe 'failed' do
130
+ def complete
131
+ [notification1, notification2].each do |n|
132
+ batch.mark_failed(n, 1, 'an error')
133
+ batch.notification_processed
134
+ end
135
+ end
136
+
137
+ it 'marks the batch as failed' do
138
+ expect(store).to receive(:mark_batch_failed).with([notification1, notification2], 1, 'an error')
139
+ complete
140
+ end
141
+
142
+ it 'reflects the notifications failed' do
143
+ expect(batch).to receive(:reflect).with(:notification_failed, notification1)
144
+ expect(batch).to receive(:reflect).with(:notification_failed, notification2)
145
+ complete
146
+ end
147
+ end
148
+
149
+ describe 'retryable' do
150
+ def complete
151
+ [notification1, notification2].each do |n|
152
+ batch.mark_retryable(n, time)
153
+ batch.notification_processed
154
+ end
155
+ end
156
+
157
+ it 'marks the batch as retryable' do
158
+ expect(store).to receive(:mark_batch_retryable).with([notification1, notification2], time)
159
+ complete
160
+ end
161
+
162
+ it 'reflects the notifications will be retried' do
163
+ expect(batch).to receive(:reflect).with(:notification_will_retry, notification1)
164
+ expect(batch).to receive(:reflect).with(:notification_will_retry, notification2)
165
+ complete
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,13 @@
1
+ require "unit_spec_helper"
2
+
3
+ describe Rpush::DeliveryError do
4
+ let(:error) { Rpush::DeliveryError.new(4, 12, "Missing payload") }
5
+
6
+ it "returns an informative message" do
7
+ expect(error.to_s).to eq "Unable to deliver notification 12, received error 4 (Missing payload)"
8
+ end
9
+
10
+ it "returns the error code" do
11
+ expect(error.code).to eq 4
12
+ end
13
+ end
@@ -0,0 +1,51 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Rpush::Daemon::Delivery do
4
+ class DeliverySpecDelivery < Rpush::Daemon::Delivery
5
+ def initialize(batch)
6
+ @batch = batch
7
+ end
8
+ end
9
+
10
+ let(:now) { Time.parse("2014-10-14 00:00:00") }
11
+ let(:batch) { double(Rpush::Daemon::Batch) }
12
+ let(:delivery) { DeliverySpecDelivery.new(batch) }
13
+ let(:notification) { Rpush::Apns::Notification.new }
14
+
15
+ before { allow(Time).to receive_messages(now: now) }
16
+
17
+ describe 'mark_retryable' do
18
+ it 'does not retry a notification with an expired fail_after' do
19
+ expect(batch).to receive(:mark_failed).with(notification, nil, "Notification failed to be delivered before 2014-10-13 23:00:00.")
20
+ notification.fail_after = Time.now - 1.hour
21
+ delivery.mark_retryable(notification, Time.now + 1.hour)
22
+ end
23
+
24
+ it 'retries the notification if does not have a fail_after time' do
25
+ expect(batch).to receive(:mark_retryable)
26
+ notification.fail_after = nil
27
+ delivery.mark_retryable(notification, Time.now + 1.hour)
28
+ end
29
+
30
+ it 'retries the notification if the fail_after time has not been reached' do
31
+ expect(batch).to receive(:mark_retryable)
32
+ notification.fail_after = Time.now + 1.hour
33
+ delivery.mark_retryable(notification, Time.now + 1.hour)
34
+ end
35
+ end
36
+
37
+ describe 'mark_batch_delivered' do
38
+ it 'marks all notifications as delivered' do
39
+ expect(batch).to receive(:mark_all_delivered)
40
+ delivery.mark_batch_delivered
41
+ end
42
+ end
43
+
44
+ describe 'mark_batch_failed' do
45
+ it 'marks all notifications as delivered' do
46
+ error = Rpush::DeliveryError.new(1, 42, 'an error')
47
+ expect(batch).to receive(:mark_all_failed).with(1, 'Unable to deliver notification 42, received error 1 (an error)')
48
+ delivery.mark_batch_failed(error)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,34 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Rpush::Daemon::Dispatcher::Http do
4
+ let(:app) { double }
5
+ let(:delivery_class) { double }
6
+ let(:notification) { double }
7
+ let(:batch) { double }
8
+ let(:http) { double }
9
+ let(:queue_payload) { Rpush::Daemon::QueuePayload.new(batch, notification) }
10
+ let(:dispatcher) { Rpush::Daemon::Dispatcher::Http.new(app, delivery_class) }
11
+
12
+ before { allow(Net::HTTP::Persistent).to receive_messages(new: http) }
13
+
14
+ it 'constructs a new persistent connection' do
15
+ expect(Net::HTTP::Persistent).to receive(:new)
16
+ Rpush::Daemon::Dispatcher::Http.new(app, delivery_class)
17
+ end
18
+
19
+ describe 'dispatch' do
20
+ it 'delivers the notification' do
21
+ delivery = double
22
+ expect(delivery_class).to receive(:new).with(app, http, notification, batch).and_return(delivery)
23
+ expect(delivery).to receive(:perform)
24
+ dispatcher.dispatch(queue_payload)
25
+ end
26
+ end
27
+
28
+ describe 'cleanup' do
29
+ it 'closes the connection' do
30
+ expect(http).to receive(:shutdown)
31
+ dispatcher.cleanup
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,32 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Rpush::Daemon::Dispatcher::Tcp do
4
+ let(:app) { double }
5
+ let(:delivery) { double(perform: nil) }
6
+ let(:delivery_class) { double(new: delivery) }
7
+ let(:notification) { double }
8
+ let(:batch) { double }
9
+ let(:connection) { double(Rpush::Daemon::TcpConnection, connect: nil) }
10
+ let(:host) { 'localhost' }
11
+ let(:port) { 1234 }
12
+ let(:host_proc) { proc { [host, port] } }
13
+ let(:queue_payload) { Rpush::Daemon::QueuePayload.new(batch, notification) }
14
+ let(:dispatcher) { Rpush::Daemon::Dispatcher::Tcp.new(app, delivery_class, host: host_proc) }
15
+
16
+ before { allow(Rpush::Daemon::TcpConnection).to receive_messages(new: connection) }
17
+
18
+ describe 'dispatch' do
19
+ it 'delivers the notification' do
20
+ expect(delivery_class).to receive(:new).with(app, connection, notification, batch).and_return(delivery)
21
+ expect(delivery).to receive(:perform)
22
+ dispatcher.dispatch(queue_payload)
23
+ end
24
+ end
25
+
26
+ describe 'cleanup' do
27
+ it 'closes the connection' do
28
+ expect(connection).to receive(:close)
29
+ dispatcher.cleanup
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,53 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Rpush::Daemon::DispatcherLoop do
4
+ def run_dispatcher_loop
5
+ dispatcher_loop.start
6
+ dispatcher_loop.stop
7
+ end
8
+
9
+ let(:notification) { double }
10
+ let(:batch) { double(notification_processed: nil) }
11
+ let(:queue) { Queue.new }
12
+ let(:dispatcher) { double(dispatch: nil, cleanup: nil) }
13
+ let(:dispatcher_loop) { Rpush::Daemon::DispatcherLoop.new(queue, dispatcher) }
14
+ let(:store) { double(Rpush::Daemon::Store::ActiveRecord, release_connection: nil) }
15
+
16
+ before do
17
+ allow(Rpush::Daemon).to receive_messages(store: store)
18
+ queue.push([notification, batch])
19
+ end
20
+
21
+ it 'logs errors' do
22
+ logger = double
23
+ allow(Rpush).to receive_messages(logger: logger)
24
+ error = StandardError.new
25
+ allow(dispatcher).to receive(:dispatch).and_raise(error)
26
+ expect(Rpush.logger).to receive(:error).with(error)
27
+ run_dispatcher_loop
28
+ end
29
+
30
+ it 'reflects an exception' do
31
+ allow(Rpush).to receive_messages(logger: double(error: nil))
32
+ error = StandardError.new
33
+ allow(dispatcher).to receive(:dispatch).and_raise(error)
34
+ expect(dispatcher_loop).to receive(:reflect).with(:error, error)
35
+ run_dispatcher_loop
36
+ end
37
+
38
+ describe 'stop' do
39
+ before do
40
+ queue.clear
41
+ end
42
+
43
+ it 'instructs the dispatcher to cleanup' do
44
+ expect(dispatcher).to receive(:cleanup)
45
+ run_dispatcher_loop
46
+ end
47
+
48
+ it 'releases the store connection' do
49
+ expect(Rpush::Daemon.store).to receive(:release_connection)
50
+ run_dispatcher_loop
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,96 @@
1
+ require "unit_spec_helper"
2
+
3
+ describe Rpush::Daemon::Feeder do
4
+ let!(:app) { Rpush::Apns::App.create!(name: 'my_app', environment: 'development', certificate: TEST_CERT) }
5
+ let(:notification) { Rpush::Apns::Notification.create!(device_token: "a" * 108, app: app) }
6
+ let(:logger) { double }
7
+ let(:interruptible_sleeper) { double(sleep: nil, stop: nil) }
8
+ let(:store) { double(Rpush::Daemon::Store::ActiveRecord, deliverable_notifications: [notification], release_connection: nil) }
9
+
10
+ before do
11
+ Rpush.configure do |config|
12
+ config.batch_size = 5000
13
+ config.push_poll = 0
14
+ config.push = false
15
+ end
16
+
17
+ allow(Rpush).to receive_messages(logger: logger)
18
+ allow(Rpush::Daemon).to receive_messages(store: store)
19
+ allow(Rpush::Daemon::Feeder).to receive_messages(should_stop: true, interruptible_sleeper: interruptible_sleeper)
20
+ allow(Rpush::Daemon::AppRunner).to receive_messages(enqueue: nil, num_queued: 0)
21
+ end
22
+
23
+ def start_and_stop
24
+ Rpush::Daemon::Feeder.start
25
+ Rpush::Daemon::Feeder.stop
26
+ end
27
+
28
+ it 'loads deliverable notifications' do
29
+ expect(Rpush::Daemon.store).to receive(:deliverable_notifications).with(Rpush.config.batch_size)
30
+ start_and_stop
31
+ end
32
+
33
+ it 'does not load more notifications if the total queue size is equal to the batch size' do
34
+ allow(Rpush::Daemon::AppRunner).to receive_messages(total_queued: Rpush.config.batch_size)
35
+ expect(Rpush::Daemon.store).not_to receive(:deliverable_notifications)
36
+ start_and_stop
37
+ end
38
+
39
+ it 'limits the batch size if some runners are still processing notifications' do
40
+ allow(Rpush.config).to receive_messages(batch_size: 10)
41
+ allow(Rpush::Daemon::AppRunner).to receive_messages(total_queued: 6)
42
+ expect(Rpush::Daemon.store).to receive(:deliverable_notifications).with(4)
43
+ start_and_stop
44
+ end
45
+
46
+ it 'enqueues notifications without looping if in push mode' do
47
+ expect(Rpush::Daemon::Feeder).not_to receive(:feed_forever)
48
+ expect(Rpush::Daemon::Feeder).to receive(:feed_all)
49
+ Rpush::Daemon::Feeder.start(true)
50
+ end
51
+
52
+ it "enqueues the notifications" do
53
+ expect(Rpush::Daemon::AppRunner).to receive(:enqueue).with([notification])
54
+ start_and_stop
55
+ end
56
+
57
+ it "logs errors" do
58
+ e = StandardError.new("bork")
59
+ allow(Rpush::Daemon.store).to receive(:deliverable_notifications).and_raise(e)
60
+ expect(Rpush.logger).to receive(:error).with(e)
61
+ start_and_stop
62
+ end
63
+
64
+ describe 'stop' do
65
+ it 'interrupts sleep' do
66
+ expect(interruptible_sleeper).to receive(:stop)
67
+ start_and_stop
68
+ end
69
+
70
+ it 'releases the store connection' do
71
+ expect(Rpush::Daemon.store).to receive(:release_connection)
72
+ start_and_stop
73
+ end
74
+ end
75
+
76
+ it 'enqueues notifications when started' do
77
+ expect(Rpush::Daemon::Feeder).to receive(:enqueue_notifications).at_least(:once)
78
+ allow(Rpush::Daemon::Feeder).to receive(:loop).and_yield
79
+ start_and_stop
80
+ end
81
+
82
+ it 'sleeps' do
83
+ expect(interruptible_sleeper).to receive(:sleep)
84
+ start_and_stop
85
+ end
86
+
87
+ describe 'wakeup' do
88
+ it 'interrupts sleep' do
89
+ expect(interruptible_sleeper).to receive(:stop)
90
+ Rpush::Daemon::Feeder.start
91
+ Rpush::Daemon::Feeder.wakeup
92
+ end
93
+
94
+ after { Rpush::Daemon::Feeder.stop }
95
+ end
96
+ end