rpush_extended 3.2.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +365 -0
- data/LICENSE +7 -0
- data/README.md +393 -0
- data/bin/rpush +4 -0
- data/lib/generators/rpush_config_generator.rb +7 -0
- data/lib/generators/rpush_migration_generator.rb +66 -0
- data/lib/generators/templates/add_adm.rb +23 -0
- data/lib/generators/templates/add_alert_is_json_to_rapns_notifications.rb +9 -0
- data/lib/generators/templates/add_app_to_rapns.rb +11 -0
- data/lib/generators/templates/add_fail_after_to_rpush_notifications.rb +9 -0
- data/lib/generators/templates/add_gcm.rb +117 -0
- data/lib/generators/templates/add_rpush.rb +402 -0
- data/lib/generators/templates/add_wpns.rb +16 -0
- data/lib/generators/templates/create_rapns_apps.rb +16 -0
- data/lib/generators/templates/create_rapns_feedback.rb +25 -0
- data/lib/generators/templates/create_rapns_notifications.rb +36 -0
- data/lib/generators/templates/rename_rapns_to_rpush.rb +87 -0
- data/lib/generators/templates/rpush.rb +135 -0
- data/lib/generators/templates/rpush_2_0_0_updates.rb +79 -0
- data/lib/generators/templates/rpush_2_1_0_updates.rb +11 -0
- data/lib/generators/templates/rpush_2_6_0_updates.rb +10 -0
- data/lib/generators/templates/rpush_2_7_0_updates.rb +12 -0
- data/lib/generators/templates/rpush_3_0_0_updates.rb +11 -0
- data/lib/generators/templates/rpush_3_0_1_updates.rb +13 -0
- data/lib/generators/templates/rpush_3_1_0_add_pushy.rb +9 -0
- data/lib/generators/templates/rpush_3_1_1_updates.rb +15 -0
- data/lib/generators/templates/rpush_3_2_0_add_apns_p8.rb +15 -0
- data/lib/generators/templates/rpush_3_2_4_updates.rb +9 -0
- data/lib/generators/templates/rpush_3_3_0_updates.rb +9 -0
- data/lib/generators/templates/rpush_3_3_1_updates.rb +11 -0
- data/lib/rpush/apns_feedback.rb +17 -0
- data/lib/rpush/cli.rb +213 -0
- data/lib/rpush/client/active_model/adm/app.rb +23 -0
- data/lib/rpush/client/active_model/adm/data_validator.rb +14 -0
- data/lib/rpush/client/active_model/adm/notification.rb +28 -0
- data/lib/rpush/client/active_model/apns/app.rb +37 -0
- data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +16 -0
- data/lib/rpush/client/active_model/apns/device_token_format_validator.rb +14 -0
- data/lib/rpush/client/active_model/apns/notification.rb +104 -0
- data/lib/rpush/client/active_model/apns2/app.rb +15 -0
- data/lib/rpush/client/active_model/apns2/notification.rb +9 -0
- data/lib/rpush/client/active_model/apnsp8/app.rb +23 -0
- data/lib/rpush/client/active_model/apnsp8/notification.rb +9 -0
- data/lib/rpush/client/active_model/gcm/app.rb +19 -0
- data/lib/rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +14 -0
- data/lib/rpush/client/active_model/gcm/notification.rb +59 -0
- data/lib/rpush/client/active_model/notification.rb +22 -0
- data/lib/rpush/client/active_model/payload_data_size_validator.rb +13 -0
- data/lib/rpush/client/active_model/pushy/app.rb +20 -0
- data/lib/rpush/client/active_model/pushy/notification.rb +31 -0
- data/lib/rpush/client/active_model/pushy/time_to_live_validator.rb +14 -0
- data/lib/rpush/client/active_model/registration_ids_count_validator.rb +13 -0
- data/lib/rpush/client/active_model/wns/app.rb +23 -0
- data/lib/rpush/client/active_model/wns/notification.rb +32 -0
- data/lib/rpush/client/active_model/wpns/app.rb +13 -0
- data/lib/rpush/client/active_model/wpns/notification.rb +28 -0
- data/lib/rpush/client/active_model.rb +34 -0
- data/lib/rpush/client/active_record/adm/app.rb +11 -0
- data/lib/rpush/client/active_record/adm/notification.rb +11 -0
- data/lib/rpush/client/active_record/apns/app.rb +11 -0
- data/lib/rpush/client/active_record/apns/feedback.rb +18 -0
- data/lib/rpush/client/active_record/apns/notification.rb +40 -0
- data/lib/rpush/client/active_record/apns2/app.rb +11 -0
- data/lib/rpush/client/active_record/apns2/notification.rb +10 -0
- data/lib/rpush/client/active_record/apnsp8/app.rb +11 -0
- data/lib/rpush/client/active_record/apnsp8/notification.rb +10 -0
- data/lib/rpush/client/active_record/app.rb +13 -0
- data/lib/rpush/client/active_record/gcm/app.rb +11 -0
- data/lib/rpush/client/active_record/gcm/notification.rb +11 -0
- data/lib/rpush/client/active_record/notification.rb +42 -0
- data/lib/rpush/client/active_record/pushy/app.rb +11 -0
- data/lib/rpush/client/active_record/pushy/notification.rb +11 -0
- data/lib/rpush/client/active_record/wns/app.rb +11 -0
- data/lib/rpush/client/active_record/wns/badge_notification.rb +15 -0
- data/lib/rpush/client/active_record/wns/notification.rb +11 -0
- data/lib/rpush/client/active_record/wns/raw_notification.rb +13 -0
- data/lib/rpush/client/active_record/wpns/app.rb +11 -0
- data/lib/rpush/client/active_record/wpns/notification.rb +11 -0
- data/lib/rpush/client/active_record.rb +33 -0
- data/lib/rpush/client/redis/adm/app.rb +14 -0
- data/lib/rpush/client/redis/adm/notification.rb +11 -0
- data/lib/rpush/client/redis/apns/app.rb +11 -0
- data/lib/rpush/client/redis/apns/feedback.rb +20 -0
- data/lib/rpush/client/redis/apns/notification.rb +11 -0
- data/lib/rpush/client/redis/apns2/app.rb +11 -0
- data/lib/rpush/client/redis/apns2/notification.rb +11 -0
- data/lib/rpush/client/redis/apnsp8/app.rb +11 -0
- data/lib/rpush/client/redis/apnsp8/notification.rb +11 -0
- data/lib/rpush/client/redis/app.rb +29 -0
- data/lib/rpush/client/redis/gcm/app.rb +11 -0
- data/lib/rpush/client/redis/gcm/notification.rb +11 -0
- data/lib/rpush/client/redis/notification.rb +74 -0
- data/lib/rpush/client/redis/pushy/app.rb +16 -0
- data/lib/rpush/client/redis/pushy/notification.rb +18 -0
- data/lib/rpush/client/redis/wns/app.rb +14 -0
- data/lib/rpush/client/redis/wns/badge_notification.rb +15 -0
- data/lib/rpush/client/redis/wns/notification.rb +11 -0
- data/lib/rpush/client/redis/wns/raw_notification.rb +11 -0
- data/lib/rpush/client/redis/wpns/app.rb +11 -0
- data/lib/rpush/client/redis/wpns/notification.rb +11 -0
- data/lib/rpush/client/redis.rb +56 -0
- data/lib/rpush/configuration.rb +115 -0
- data/lib/rpush/daemon/adm/delivery.rb +226 -0
- data/lib/rpush/daemon/adm.rb +9 -0
- data/lib/rpush/daemon/apns/delivery.rb +43 -0
- data/lib/rpush/daemon/apns/feedback_receiver.rb +90 -0
- data/lib/rpush/daemon/apns.rb +17 -0
- data/lib/rpush/daemon/apns2/delivery.rb +127 -0
- data/lib/rpush/daemon/apns2.rb +10 -0
- data/lib/rpush/daemon/apnsp8/delivery.rb +166 -0
- data/lib/rpush/daemon/apnsp8/token.rb +43 -0
- data/lib/rpush/daemon/apnsp8.rb +10 -0
- data/lib/rpush/daemon/app_runner.rb +190 -0
- data/lib/rpush/daemon/batch.rb +138 -0
- data/lib/rpush/daemon/constants.rb +59 -0
- data/lib/rpush/daemon/delivery.rb +46 -0
- data/lib/rpush/daemon/delivery_error.rb +27 -0
- data/lib/rpush/daemon/dispatcher/apns_http2.rb +51 -0
- data/lib/rpush/daemon/dispatcher/apns_tcp.rb +152 -0
- data/lib/rpush/daemon/dispatcher/apnsp8_http2.rb +33 -0
- data/lib/rpush/daemon/dispatcher/http.rb +21 -0
- data/lib/rpush/daemon/dispatcher/tcp.rb +22 -0
- data/lib/rpush/daemon/dispatcher_loop.rb +73 -0
- data/lib/rpush/daemon/errors.rb +18 -0
- data/lib/rpush/daemon/feeder.rb +69 -0
- data/lib/rpush/daemon/gcm/delivery.rb +241 -0
- data/lib/rpush/daemon/gcm.rb +9 -0
- data/lib/rpush/daemon/interruptible_sleep.rb +24 -0
- data/lib/rpush/daemon/loggable.rb +33 -0
- data/lib/rpush/daemon/proc_title.rb +17 -0
- data/lib/rpush/daemon/pushy/delivery.rb +90 -0
- data/lib/rpush/daemon/pushy.rb +9 -0
- data/lib/rpush/daemon/queue_payload.rb +12 -0
- data/lib/rpush/daemon/retry_header_parser.rb +23 -0
- data/lib/rpush/daemon/retryable_error.rb +22 -0
- data/lib/rpush/daemon/ring_buffer.rb +16 -0
- data/lib/rpush/daemon/rpc/client.rb +27 -0
- data/lib/rpush/daemon/rpc/server.rb +82 -0
- data/lib/rpush/daemon/rpc.rb +9 -0
- data/lib/rpush/daemon/service_config_methods.rb +51 -0
- data/lib/rpush/daemon/signal_handler.rb +75 -0
- data/lib/rpush/daemon/store/active_record/reconnectable.rb +80 -0
- data/lib/rpush/daemon/store/active_record.rb +214 -0
- data/lib/rpush/daemon/store/interface.rb +20 -0
- data/lib/rpush/daemon/store/redis.rb +166 -0
- data/lib/rpush/daemon/string_helpers.rb +15 -0
- data/lib/rpush/daemon/synchronizer.rb +62 -0
- data/lib/rpush/daemon/tcp_connection.rb +190 -0
- data/lib/rpush/daemon/wns/badge_request.rb +32 -0
- data/lib/rpush/daemon/wns/delivery.rb +178 -0
- data/lib/rpush/daemon/wns/post_request.rb +33 -0
- data/lib/rpush/daemon/wns/raw_request.rb +22 -0
- data/lib/rpush/daemon/wns/toast_request.rb +54 -0
- data/lib/rpush/daemon/wns.rb +9 -0
- data/lib/rpush/daemon/wpns/delivery.rb +132 -0
- data/lib/rpush/daemon/wpns.rb +9 -0
- data/lib/rpush/daemon.rb +179 -0
- data/lib/rpush/deprecatable.rb +24 -0
- data/lib/rpush/deprecation.rb +26 -0
- data/lib/rpush/embed.rb +41 -0
- data/lib/rpush/logger.rb +92 -0
- data/lib/rpush/multi_json_helper.rb +16 -0
- data/lib/rpush/plugin.rb +44 -0
- data/lib/rpush/push.rb +11 -0
- data/lib/rpush/reflectable.rb +13 -0
- data/lib/rpush/reflection_collection.rb +44 -0
- data/lib/rpush/reflection_public_methods.rb +11 -0
- data/lib/rpush/version.rb +14 -0
- data/lib/rpush.rb +43 -0
- data/lib/tasks/quality.rake +35 -0
- data/lib/tasks/test.rake +69 -0
- data/spec/.rubocop.yml +4 -0
- data/spec/functional/adm_spec.rb +50 -0
- data/spec/functional/apns2_spec.rb +232 -0
- data/spec/functional/apns_spec.rb +162 -0
- data/spec/functional/cli_spec.rb +36 -0
- data/spec/functional/embed_spec.rb +49 -0
- data/spec/functional/gcm_spec.rb +46 -0
- data/spec/functional/new_app_spec.rb +44 -0
- data/spec/functional/pushy_spec.rb +22 -0
- data/spec/functional/retry_spec.rb +42 -0
- data/spec/functional/synchronization_spec.rb +97 -0
- data/spec/functional/wpns_spec.rb +71 -0
- data/spec/functional_spec_helper.rb +32 -0
- data/spec/spec_helper.rb +69 -0
- data/spec/support/active_record_setup.rb +73 -0
- data/spec/support/cert_with_password.pem +90 -0
- data/spec/support/cert_without_password.pem +59 -0
- data/spec/support/config/database.yml +44 -0
- data/spec/support/simplecov_helper.rb +24 -0
- data/spec/support/simplecov_quality_formatter.rb +12 -0
- data/spec/tmp/.gitkeep +0 -0
- data/spec/unit/apns_feedback_spec.rb +28 -0
- data/spec/unit/client/active_record/adm/app_spec.rb +58 -0
- data/spec/unit/client/active_record/adm/notification_spec.rb +43 -0
- data/spec/unit/client/active_record/apns/app_spec.rb +29 -0
- data/spec/unit/client/active_record/apns/feedback_spec.rb +9 -0
- data/spec/unit/client/active_record/apns/notification_spec.rb +324 -0
- data/spec/unit/client/active_record/app_spec.rb +30 -0
- data/spec/unit/client/active_record/gcm/app_spec.rb +4 -0
- data/spec/unit/client/active_record/gcm/notification_spec.rb +67 -0
- data/spec/unit/client/active_record/notification_spec.rb +21 -0
- data/spec/unit/client/active_record/pushy/app_spec.rb +17 -0
- data/spec/unit/client/active_record/pushy/notification_spec.rb +65 -0
- data/spec/unit/client/active_record/wns/badge_notification_spec.rb +15 -0
- data/spec/unit/client/active_record/wns/raw_notification_spec.rb +26 -0
- data/spec/unit/client/active_record/wpns/app_spec.rb +4 -0
- data/spec/unit/client/active_record/wpns/notification_spec.rb +21 -0
- data/spec/unit/configuration_spec.rb +46 -0
- data/spec/unit/daemon/adm/delivery_spec.rb +253 -0
- data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +11 -0
- data/spec/unit/daemon/apns/delivery_spec.rb +108 -0
- data/spec/unit/daemon/apns/feedback_receiver_spec.rb +119 -0
- data/spec/unit/daemon/app_runner_spec.rb +188 -0
- data/spec/unit/daemon/batch_spec.rb +169 -0
- data/spec/unit/daemon/delivery_error_spec.rb +13 -0
- data/spec/unit/daemon/delivery_spec.rb +51 -0
- data/spec/unit/daemon/dispatcher/http_spec.rb +34 -0
- data/spec/unit/daemon/dispatcher/tcp_spec.rb +32 -0
- data/spec/unit/daemon/dispatcher_loop_spec.rb +53 -0
- data/spec/unit/daemon/feeder_spec.rb +96 -0
- data/spec/unit/daemon/gcm/delivery_spec.rb +387 -0
- data/spec/unit/daemon/proc_title_spec.rb +11 -0
- data/spec/unit/daemon/pushy/delivery_spec.rb +159 -0
- data/spec/unit/daemon/retryable_error_spec.rb +14 -0
- data/spec/unit/daemon/service_config_methods_spec.rb +36 -0
- data/spec/unit/daemon/signal_handler_spec.rb +99 -0
- data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +165 -0
- data/spec/unit/daemon/store/active_record_spec.rb +357 -0
- data/spec/unit/daemon/store/redis_spec.rb +365 -0
- data/spec/unit/daemon/tcp_connection_spec.rb +292 -0
- data/spec/unit/daemon/wns/delivery_spec.rb +176 -0
- data/spec/unit/daemon/wns/post_request_spec.rb +117 -0
- data/spec/unit/daemon/wpns/delivery_spec.rb +167 -0
- data/spec/unit/daemon_spec.rb +138 -0
- data/spec/unit/deprecatable_spec.rb +32 -0
- data/spec/unit/deprecation_spec.rb +15 -0
- data/spec/unit/embed_spec.rb +47 -0
- data/spec/unit/logger_spec.rb +127 -0
- data/spec/unit/notification_shared.rb +53 -0
- data/spec/unit/plugin_spec.rb +36 -0
- data/spec/unit/push_spec.rb +34 -0
- data/spec/unit/reflectable_spec.rb +27 -0
- data/spec/unit/reflection_collection_spec.rb +26 -0
- data/spec/unit/rpush_spec.rb +8 -0
- data/spec/unit_spec_helper.rb +26 -0
- 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
|