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,99 @@
1
+ require 'unit_spec_helper'
2
+
3
+ describe Rpush::Daemon::SignalHandler do
4
+ def signal_handler(sig)
5
+ Process.kill(sig, Process.pid)
6
+ sleep 0.1
7
+ end
8
+
9
+ def with_handler_start_stop
10
+ Rpush::Daemon::SignalHandler.start
11
+ yield
12
+ ensure
13
+ Rpush::Daemon::SignalHandler.stop
14
+ end
15
+
16
+ describe 'shutdown signals' do
17
+ unless Rpush.jruby? # These tests do not work on JRuby.
18
+ it "shuts down when signaled signaled SIGINT" do
19
+ with_handler_start_stop do
20
+ expect(Rpush::Daemon).to receive(:shutdown)
21
+ signal_handler('SIGINT')
22
+ end
23
+ end
24
+
25
+ it "shuts down when signaled signaled SIGTERM" do
26
+ with_handler_start_stop do
27
+ expect(Rpush::Daemon).to receive(:shutdown)
28
+ signal_handler('SIGTERM')
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ describe 'config.embedded = true' do
35
+ before { Rpush.config.embedded = true }
36
+
37
+ it 'does not trap signals' do
38
+ expect(Signal).not_to receive(:trap)
39
+ Rpush::Daemon::SignalHandler.start
40
+ end
41
+ end
42
+
43
+ describe 'HUP' do
44
+ before do
45
+ allow(Rpush::Daemon::Synchronizer).to receive(:sync)
46
+ allow(Rpush::Daemon::Feeder).to receive(:wakeup)
47
+ allow(Rpush::Daemon).to receive_messages(store: double(reopen_log: nil))
48
+ end
49
+
50
+ it 'syncs' do
51
+ with_handler_start_stop do
52
+ expect(Rpush::Daemon::Synchronizer).to receive(:sync)
53
+ signal_handler('HUP')
54
+ end
55
+ end
56
+
57
+ it 'wakes up the Feeder' do
58
+ with_handler_start_stop do
59
+ expect(Rpush::Daemon::Feeder).to receive(:wakeup)
60
+ signal_handler('HUP')
61
+ end
62
+ end
63
+ end
64
+
65
+ describe 'USR2' do
66
+ it 'instructs the AppRunner to print debug information' do
67
+ with_handler_start_stop do
68
+ expect(Rpush::Daemon::AppRunner).to receive(:debug)
69
+ signal_handler('USR2')
70
+ end
71
+ end
72
+ end
73
+
74
+ describe 'error handing' do
75
+ let(:error) { StandardError.new('test') }
76
+
77
+ before do
78
+ allow(Rpush).to receive_messages(logger: double(error: nil, info: nil, reopen: nil))
79
+ allow(Rpush::Daemon).to receive_messages(store: double(reopen_log: nil))
80
+ end
81
+
82
+ it 'logs errors received when handling a signal' do
83
+ allow(Rpush::Daemon::Synchronizer).to receive(:sync).and_raise(error)
84
+ expect(Rpush.logger).to receive(:error).with(error)
85
+ with_handler_start_stop do
86
+ signal_handler('HUP')
87
+ end
88
+ end
89
+
90
+ it 'does not interrupt processing of further errors' do
91
+ allow(Rpush::Daemon::Synchronizer).to receive(:sync).and_raise(error)
92
+ expect(Rpush::Daemon::AppRunner).to receive(:debug)
93
+ with_handler_start_stop do
94
+ signal_handler('HUP')
95
+ signal_handler('USR2')
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,165 @@
1
+ require 'unit_spec_helper'
2
+ require 'rpush/daemon/store/active_record/reconnectable'
3
+
4
+ describe Rpush::Daemon::Store::ActiveRecord::Reconnectable do
5
+ class TestDouble
6
+ include Rpush::Daemon::Store::ActiveRecord::Reconnectable
7
+
8
+ attr_reader :name
9
+
10
+ def initialize(error, max_calls)
11
+ @error = error
12
+ @max_calls = max_calls
13
+ @calls = 0
14
+ end
15
+
16
+ def perform
17
+ with_database_reconnect_and_retry do
18
+ @calls += 1
19
+ fail @error if @calls <= @max_calls
20
+ end
21
+ end
22
+ end
23
+
24
+ let(:adapter_error_class) do
25
+ case SPEC_ADAPTER
26
+ when 'postgresql'
27
+ PGError
28
+ when 'mysql'
29
+ Mysql::Error
30
+ when 'mysql2'
31
+ Mysql2::Error
32
+ when 'jdbcpostgresql'
33
+ ActiveRecord::JDBCError
34
+ when 'jdbcmysql'
35
+ ActiveRecord::JDBCError
36
+ when 'jdbch2'
37
+ ActiveRecord::JDBCError
38
+ when 'sqlite3'
39
+ SQLite3::Exception
40
+ else
41
+ fail "Please update #{__FILE__} for adapter #{SPEC_ADAPTER}"
42
+ end
43
+ end
44
+
45
+ let(:error) { adapter_error_class.new("db down!") }
46
+ let(:timeout) { ActiveRecord::ConnectionTimeoutError.new("db lazy!") }
47
+ let(:test_doubles) { [TestDouble.new(error, 1), TestDouble.new(timeout, 1)] }
48
+
49
+ before do
50
+ @logger = double("Logger", info: nil, error: nil, warn: nil)
51
+ allow(Rpush).to receive(:logger).and_return(@logger)
52
+
53
+ allow(ActiveRecord::Base).to receive(:clear_all_connections!)
54
+ allow(ActiveRecord::Base).to receive(:establish_connection)
55
+ test_doubles.each { |td| allow(td).to receive(:sleep) }
56
+ end
57
+
58
+ it "should log the error raised" do
59
+ expect(Rpush.logger).to receive(:error).with(error)
60
+ test_doubles.each(&:perform)
61
+ end
62
+
63
+ it "should log that the database is being reconnected" do
64
+ expect(Rpush.logger).to receive(:warn).with("Lost connection to database, reconnecting...")
65
+ test_doubles.each(&:perform)
66
+ end
67
+
68
+ it "should log the reconnection attempt" do
69
+ expect(Rpush.logger).to receive(:warn).with("Attempt 1")
70
+ test_doubles.each(&:perform)
71
+ end
72
+
73
+ it "should clear all connections" do
74
+ expect(ActiveRecord::Base).to receive(:clear_all_connections!)
75
+ test_doubles.each(&:perform)
76
+ end
77
+
78
+ it "should establish a new connection" do
79
+ expect(ActiveRecord::Base).to receive(:establish_connection)
80
+ test_doubles.each(&:perform)
81
+ end
82
+
83
+ it "should test out the new connection by performing a count" do
84
+ expect(Rpush::Client::ActiveRecord::Notification).to receive(:count).twice
85
+ test_doubles.each(&:perform)
86
+ end
87
+
88
+ context "should reconnect on" do
89
+ [
90
+ ::ActiveRecord::ConnectionNotEstablished,
91
+ ::ActiveRecord::ConnectionTimeoutError,
92
+ ::ActiveRecord::JDBCError,
93
+ ::ActiveRecord::StatementInvalid,
94
+ Mysql::Error,
95
+ Mysql2::Error,
96
+ PG::Error,
97
+ PGError,
98
+ SQLite3::Exception
99
+ ].each do |error_class|
100
+ let(:error) { error_class.new }
101
+
102
+ it error_class.name do
103
+ expect(ActiveRecord::Base).to receive(:establish_connection)
104
+ test_doubles.each(&:perform)
105
+ end
106
+ end
107
+ end
108
+
109
+ context "should not reconnect on" do
110
+ let(:error) { ActiveRecord::ActiveRecordError.new }
111
+
112
+ it "ActiveRecord::ActiveRecordError" do
113
+ expect(ActiveRecord::Base).not_to receive(:establish_connection)
114
+ expect { test_doubles.each(&:perform) }.to raise_error(ActiveRecord::ActiveRecordError)
115
+ end
116
+ end
117
+
118
+ context "when the reconnection attempt is not successful" do
119
+ before do
120
+ class << Rpush::Client::ActiveRecord::Notification
121
+ def count
122
+ @count_calls += 1
123
+ return if @count_calls == 2
124
+ fail @error
125
+ end
126
+ end
127
+ Rpush::Client::ActiveRecord::Notification.instance_variable_set("@count_calls", 0)
128
+ Rpush::Client::ActiveRecord::Notification.instance_variable_set("@error", error)
129
+ end
130
+
131
+ describe "error behaviour" do
132
+ it "should log the 2nd attempt" do
133
+ expect(Rpush.logger).to receive(:warn).with("Attempt 2")
134
+ test_doubles[0].perform
135
+ end
136
+
137
+ it "should log errors raised when the reconnection is not successful" do
138
+ expect(Rpush.logger).to receive(:error).with(error)
139
+ test_doubles[0].perform
140
+ end
141
+
142
+ it "should sleep to avoid thrashing when the database is down" do
143
+ expect(test_doubles[0]).to receive(:sleep).with(2)
144
+ test_doubles[0].perform
145
+ end
146
+ end
147
+
148
+ describe "timeout behaviour" do
149
+ it "should log the 2nd attempt" do
150
+ expect(Rpush.logger).to receive(:warn).with("Attempt 2")
151
+ test_doubles[1].perform
152
+ end
153
+
154
+ it "should log errors raised when the reconnection is not successful" do
155
+ expect(Rpush.logger).to receive(:error).with(error)
156
+ test_doubles[1].perform
157
+ end
158
+
159
+ it "should sleep to avoid thrashing when the database is down" do
160
+ expect(test_doubles[1]).to receive(:sleep).with(2)
161
+ test_doubles[1].perform
162
+ end
163
+ end
164
+ end
165
+ end if active_record?
@@ -0,0 +1,357 @@
1
+ require 'unit_spec_helper'
2
+ require 'rpush/daemon/store/active_record'
3
+
4
+ describe Rpush::Daemon::Store::ActiveRecord do
5
+ let(:app) { Rpush::Client::ActiveRecord::Apns::App.create!(name: 'my_app', environment: 'development', certificate: TEST_CERT) }
6
+ let(:notification) { Rpush::Client::ActiveRecord::Apns::Notification.create!(device_token: "a" * 64, app: app) }
7
+ let(:store) { Rpush::Daemon::Store::ActiveRecord.new }
8
+ let(:time) { Time.now.utc }
9
+ let(:logger) { double(Rpush::Logger, error: nil, internal_logger: nil) }
10
+
11
+ before do
12
+ allow(Rpush).to receive_messages(logger: logger)
13
+ allow(Time).to receive_messages(now: time)
14
+ end
15
+
16
+ it 'updates an notification' do
17
+ expect(notification).to receive(:save!)
18
+ store.update_notification(notification)
19
+ end
20
+
21
+ it 'updates an app' do
22
+ expect(app).to receive(:save!)
23
+ store.update_app(app)
24
+ end
25
+
26
+ it 'finds an app by ID' do
27
+ expect(store.app(app.id)).to eq(app)
28
+ end
29
+
30
+ it 'finds all apps' do
31
+ app
32
+ expect(store.all_apps).to eq([app])
33
+ end
34
+
35
+ it 'translates an Integer notification ID' do
36
+ expect(store.translate_integer_notification_id(notification.id)).to eq(notification.id)
37
+ end
38
+
39
+ it 'returns the pending notification count' do
40
+ notification
41
+ expect(store.pending_delivery_count).to eq(1)
42
+ end
43
+
44
+ it 'can release a connection' do
45
+ expect(ActiveRecord::Base.connection).to receive(:close)
46
+ store.release_connection
47
+ end
48
+
49
+ it 'logs errors raised when trying to release the connection' do
50
+ e = StandardError.new
51
+ allow(ActiveRecord::Base.connection).to receive(:close).and_raise(e)
52
+ expect(Rpush.logger).to receive(:error).with(e)
53
+ store.release_connection
54
+ end
55
+
56
+ describe 'deliverable_notifications' do
57
+ it 'checks for new notifications with the ability to reconnect the database' do
58
+ expect(store).to receive(:with_database_reconnect_and_retry)
59
+ store.deliverable_notifications(Rpush.config.batch_size)
60
+ end
61
+
62
+ it 'loads notifications in batches' do
63
+ Rpush.config.batch_size = 5000
64
+ relation = double.as_null_object
65
+ expect(relation).to receive(:limit).with(5000)
66
+ allow(relation).to receive_messages(pluck: [])
67
+ allow(store).to receive_messages(ready_for_delivery: relation)
68
+ store.deliverable_notifications(Rpush.config.batch_size)
69
+ end
70
+
71
+ it 'loads an undelivered notification without deliver_after set' do
72
+ notification.update_attributes!(delivered: false, deliver_after: nil)
73
+ expect(store.deliverable_notifications(Rpush.config.batch_size)).to eq [notification]
74
+ end
75
+
76
+ it 'loads an notification with a deliver_after time in the past' do
77
+ notification.update_attributes!(delivered: false, deliver_after: 1.hour.ago)
78
+ expect(store.deliverable_notifications(Rpush.config.batch_size)).to eq [notification]
79
+ end
80
+
81
+ it 'does not load an notification with a deliver_after time in the future' do
82
+ notification.update_attributes!(delivered: false, deliver_after: 1.hour.from_now)
83
+ expect(store.deliverable_notifications(Rpush.config.batch_size)).to be_empty
84
+ end
85
+
86
+ it 'does not load a previously delivered notification' do
87
+ notification.update_attributes!(delivered: true, delivered_at: time)
88
+ expect(store.deliverable_notifications(Rpush.config.batch_size)).to be_empty
89
+ end
90
+
91
+ it "does not enqueue a notification that has previously failed delivery" do
92
+ notification.update_attributes!(delivered: false, failed: true)
93
+ expect(store.deliverable_notifications(Rpush.config.batch_size)).to be_empty
94
+ end
95
+ end
96
+
97
+ describe 'mark_retryable' do
98
+ it 'increments the retry count' do
99
+ expect do
100
+ store.mark_retryable(notification, time)
101
+ end.to change(notification, :retries).by(1)
102
+ end
103
+
104
+ it 'sets the deliver after timestamp' do
105
+ deliver_after = time + 10.seconds
106
+ expect do
107
+ store.mark_retryable(notification, deliver_after)
108
+ end.to change(notification, :deliver_after).to(deliver_after)
109
+ end
110
+
111
+ it 'saves the notification without validation' do
112
+ expect(notification).to receive(:save!).with(validate: false)
113
+ store.mark_retryable(notification, time)
114
+ end
115
+
116
+ it 'does not save the notification if persist: false' do
117
+ expect(notification).not_to receive(:save!)
118
+ store.mark_retryable(notification, time, persist: false)
119
+ end
120
+ end
121
+
122
+ describe 'mark_batch_retryable' do
123
+ let(:deliver_after) { time + 10.seconds }
124
+
125
+ it 'sets the attributes on the object for use in reflections' do
126
+ store.mark_batch_retryable([notification], deliver_after)
127
+ expect(notification.deliver_after).to eq deliver_after
128
+ expect(notification.retries).to eq 1
129
+ end
130
+
131
+ it 'increments the retired count' do
132
+ expect do
133
+ store.mark_batch_retryable([notification], deliver_after)
134
+ notification.reload
135
+ end.to change(notification, :retries).by(1)
136
+ end
137
+
138
+ it 'sets the deliver after timestamp' do
139
+ expect do
140
+ store.mark_batch_retryable([notification], deliver_after)
141
+ notification.reload
142
+ end.to change { notification.deliver_after.try(:utc).to_s }.to(deliver_after.utc.to_s)
143
+ end
144
+ end
145
+
146
+ describe 'mark_delivered' do
147
+ it 'marks the notification as delivered' do
148
+ expect do
149
+ store.mark_delivered(notification, time)
150
+ end.to change(notification, :delivered).to(true)
151
+ end
152
+
153
+ it 'sets the time the notification was delivered' do
154
+ expect do
155
+ store.mark_delivered(notification, time)
156
+ notification.reload
157
+ end.to change { notification.delivered_at.try(:utc).to_s }.to(time.to_s)
158
+ end
159
+
160
+ it 'saves the notification without validation' do
161
+ expect(notification).to receive(:save!).with(validate: false)
162
+ store.mark_delivered(notification, time)
163
+ end
164
+
165
+ it 'does not save the notification if persist: false' do
166
+ expect(notification).not_to receive(:save!)
167
+ store.mark_delivered(notification, time, persist: false)
168
+ end
169
+ end
170
+
171
+ describe 'mark_batch_delivered' do
172
+ it 'sets the attributes on the object for use in reflections' do
173
+ store.mark_batch_delivered([notification])
174
+ expect(notification.delivered_at).to eq time
175
+ expect(notification.delivered).to be_truthy
176
+ end
177
+
178
+ it 'marks the notifications as delivered' do
179
+ expect do
180
+ store.mark_batch_delivered([notification])
181
+ notification.reload
182
+ end.to change(notification, :delivered).to(true)
183
+ end
184
+
185
+ it 'sets the time the notifications were delivered' do
186
+ expect do
187
+ store.mark_batch_delivered([notification])
188
+ notification.reload
189
+ end.to change { notification.delivered_at.try(:utc).to_s }.to(time.to_s)
190
+ end
191
+ end
192
+
193
+ describe 'mark_failed' do
194
+ it 'marks the notification as not delivered' do
195
+ store.mark_failed(notification, nil, '', time)
196
+ expect(notification.delivered).to eq(false)
197
+ end
198
+
199
+ it 'marks the notification as failed' do
200
+ expect do
201
+ store.mark_failed(notification, nil, '', time)
202
+ notification.reload
203
+ end.to change(notification, :failed).to(true)
204
+ end
205
+
206
+ it 'sets the time the notification delivery failed' do
207
+ expect do
208
+ store.mark_failed(notification, nil, '', time)
209
+ notification.reload
210
+ end.to change { notification.failed_at.try(:utc).to_s }.to(time.to_s)
211
+ end
212
+
213
+ it 'sets the error code' do
214
+ expect do
215
+ store.mark_failed(notification, 42, '', time)
216
+ end.to change(notification, :error_code).to(42)
217
+ end
218
+
219
+ it 'sets the error description' do
220
+ expect do
221
+ store.mark_failed(notification, 42, 'Weeee', time)
222
+ end.to change(notification, :error_description).to('Weeee')
223
+ end
224
+
225
+ it 'saves the notification without validation' do
226
+ expect(notification).to receive(:save!).with(validate: false)
227
+ store.mark_failed(notification, nil, '', time)
228
+ end
229
+
230
+ it 'does not save the notification if persist: false' do
231
+ expect(notification).not_to receive(:save!)
232
+ store.mark_failed(notification, nil, '', time, persist: false)
233
+ end
234
+ end
235
+
236
+ describe 'mark_batch_failed' do
237
+ it 'sets the attributes on the object for use in reflections' do
238
+ store.mark_batch_failed([notification], 123, 'an error')
239
+ expect(notification.failed_at).to eq time
240
+ expect(notification.delivered_at).to be_nil
241
+ expect(notification.delivered).to eq(false)
242
+ expect(notification.failed).to be_truthy
243
+ expect(notification.error_code).to eq 123
244
+ expect(notification.error_description).to eq 'an error'
245
+ end
246
+
247
+ it 'marks the notification as not delivered' do
248
+ store.mark_batch_failed([notification], nil, '')
249
+ notification.reload
250
+ expect(notification.delivered).to be_falsey
251
+ end
252
+
253
+ it 'marks the notification as failed' do
254
+ expect do
255
+ store.mark_batch_failed([notification], nil, '')
256
+ notification.reload
257
+ end.to change(notification, :failed).to(true)
258
+ end
259
+
260
+ it 'sets the time the notification delivery failed' do
261
+ expect do
262
+ store.mark_batch_failed([notification], nil, '')
263
+ notification.reload
264
+ end.to change { notification.failed_at.try(:utc).to_s }.to(time.to_s)
265
+ end
266
+
267
+ it 'sets the error code' do
268
+ expect do
269
+ store.mark_batch_failed([notification], 42, '')
270
+ notification.reload
271
+ end.to change(notification, :error_code).to(42)
272
+ end
273
+
274
+ it 'sets the error description' do
275
+ expect do
276
+ store.mark_batch_failed([notification], 42, 'Weeee')
277
+ notification.reload
278
+ end.to change(notification, :error_description).to('Weeee')
279
+ end
280
+ end
281
+
282
+ describe 'create_apns_feedback' do
283
+ it 'creates the Feedback record' do
284
+ expect(Rpush::Client::ActiveRecord::Apns::Feedback).to receive(:create!).with(
285
+ failed_at: time, device_token: 'ab' * 32, app_id: app.id)
286
+ store.create_apns_feedback(time, 'ab' * 32, app)
287
+ end
288
+ end
289
+
290
+ describe 'create_gcm_notification' do
291
+ let(:data) { { data: true } }
292
+ let(:attributes) { { device_token: 'ab' * 32 } }
293
+ let(:registration_ids) { %w(123 456) }
294
+ let(:deliver_after) { time + 10.seconds }
295
+ let(:args) { [attributes, data, registration_ids, deliver_after, app] }
296
+
297
+ it 'sets the given attributes' do
298
+ new_notification = store.create_gcm_notification(*args)
299
+ expect(new_notification.device_token).to eq 'ab' * 32
300
+ end
301
+
302
+ it 'sets the given data' do
303
+ new_notification = store.create_gcm_notification(*args)
304
+ expect(new_notification.data['data']).to be_truthy
305
+ end
306
+
307
+ it 'sets the given registration IDs' do
308
+ new_notification = store.create_gcm_notification(*args)
309
+ expect(new_notification.registration_ids).to eq registration_ids
310
+ end
311
+
312
+ it 'sets the deliver_after timestamp' do
313
+ new_notification = store.create_gcm_notification(*args)
314
+ expect(new_notification.deliver_after.to_s).to eq deliver_after.to_s
315
+ end
316
+
317
+ it 'saves the new notification' do
318
+ new_notification = store.create_gcm_notification(*args)
319
+ expect(new_notification.new_record?).to be_falsey
320
+ end
321
+ end
322
+
323
+ describe 'create_adm_notification' do
324
+ let(:data) { { data: true } }
325
+ let(:attributes) { { app_id: app.id, collapse_key: 'ckey', delay_while_idle: true } }
326
+ let(:registration_ids) { %w(123 456) }
327
+ let(:deliver_after) { time + 10.seconds }
328
+ let(:args) { [attributes, data, registration_ids, deliver_after, app] }
329
+
330
+ it 'sets the given attributes' do
331
+ new_notification = store.create_adm_notification(*args)
332
+ expect(new_notification.app_id).to eq app.id
333
+ expect(new_notification.collapse_key).to eq 'ckey'
334
+ expect(new_notification.delay_while_idle).to be_truthy
335
+ end
336
+
337
+ it 'sets the given data' do
338
+ new_notification = store.create_adm_notification(*args)
339
+ expect(new_notification.data['data']).to be_truthy
340
+ end
341
+
342
+ it 'sets the given registration IDs' do
343
+ new_notification = store.create_adm_notification(*args)
344
+ expect(new_notification.registration_ids).to eq registration_ids
345
+ end
346
+
347
+ it 'sets the deliver_after timestamp' do
348
+ new_notification = store.create_adm_notification(*args)
349
+ expect(new_notification.deliver_after.to_s).to eq deliver_after.to_s
350
+ end
351
+
352
+ it 'saves the new notification' do
353
+ new_notification = store.create_adm_notification(*args)
354
+ expect(new_notification.new_record?).to be_falsey
355
+ end
356
+ end
357
+ end if active_record?