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,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