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.
- 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,365 @@
|
|
|
1
|
+
require 'unit_spec_helper'
|
|
2
|
+
require 'rpush/daemon/store/redis'
|
|
3
|
+
|
|
4
|
+
describe Rpush::Daemon::Store::Redis do
|
|
5
|
+
let(:app) { Rpush::Client::Redis::Apns::App.create!(name: 'my_app', environment: 'development', certificate: TEST_CERT) }
|
|
6
|
+
let(:notification) { Rpush::Client::Redis::Apns::Notification.create!(device_token: "a" * 64, app: app) }
|
|
7
|
+
let(:store) { Rpush::Daemon::Store::Redis.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
|
+
app
|
|
28
|
+
expect(store.app(app.id)).to eq(app)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'finds all apps' do
|
|
32
|
+
app
|
|
33
|
+
expect(store.all_apps).to eq([app])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'translates an Integer notification ID' do
|
|
37
|
+
expect(store.translate_integer_notification_id(notification.id)).to eq(notification.id)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'returns the pending notification count' do
|
|
41
|
+
notification
|
|
42
|
+
expect(store.pending_delivery_count).to eq(1)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe 'deliverable_notifications' do
|
|
46
|
+
it 'loads notifications in batches' do
|
|
47
|
+
Rpush.config.batch_size = 100
|
|
48
|
+
allow(store).to receive_messages(pending_notification_ids: [1, 2, 3, 4])
|
|
49
|
+
expect(Rpush::Client::Redis::Notification).to receive(:find).exactly(4).times
|
|
50
|
+
store.deliverable_notifications(Rpush.config.batch_size)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'loads an undelivered notification without deliver_after set' do
|
|
54
|
+
notification.update_attributes!(delivered: false, deliver_after: nil)
|
|
55
|
+
expect(store.deliverable_notifications(Rpush.config.batch_size)).to eq [notification]
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'loads an notification with a deliver_after time in the past' do
|
|
59
|
+
notification.update_attributes!(delivered: false, deliver_after: 1.hour.ago)
|
|
60
|
+
expect(store.deliverable_notifications(Rpush.config.batch_size)).to eq [notification]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'does not load an notification with a deliver_after time in the future' do
|
|
64
|
+
notification
|
|
65
|
+
notification = store.deliverable_notifications(Rpush.config.batch_size).first
|
|
66
|
+
store.mark_retryable(notification, 1.hour.from_now)
|
|
67
|
+
expect(store.deliverable_notifications(Rpush.config.batch_size)).to be_empty
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'does not load a previously delivered notification' do
|
|
71
|
+
notification
|
|
72
|
+
notification = store.deliverable_notifications(Rpush.config.batch_size).first
|
|
73
|
+
store.mark_delivered(notification, Time.now)
|
|
74
|
+
expect(store.deliverable_notifications(Rpush.config.batch_size)).to be_empty
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "does not enqueue a notification that has previously failed delivery" do
|
|
78
|
+
notification
|
|
79
|
+
notification = store.deliverable_notifications(Rpush.config.batch_size).first
|
|
80
|
+
store.mark_failed(notification, 0, "failed", Time.now)
|
|
81
|
+
expect(store.deliverable_notifications(Rpush.config.batch_size)).to be_empty
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe 'mark_retryable' do
|
|
86
|
+
it 'increments the retry count' do
|
|
87
|
+
expect do
|
|
88
|
+
store.mark_retryable(notification, time)
|
|
89
|
+
end.to change(notification, :retries).by(1)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it 'sets the deliver after timestamp' do
|
|
93
|
+
deliver_after = time + 10.seconds
|
|
94
|
+
expect do
|
|
95
|
+
store.mark_retryable(notification, deliver_after)
|
|
96
|
+
end.to change(notification, :deliver_after).to(deliver_after)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
it 'saves the notification without validation' do
|
|
100
|
+
expect(notification).to receive(:save!).with(validate: false)
|
|
101
|
+
store.mark_retryable(notification, time)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
it 'does not save the notification if persist: false' do
|
|
105
|
+
expect(notification).not_to receive(:save!)
|
|
106
|
+
store.mark_retryable(notification, time, persist: false)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
describe 'mark_ids_retryable' do
|
|
111
|
+
let(:deliver_after) { time + 10.seconds }
|
|
112
|
+
|
|
113
|
+
it 'sets the deliver after timestamp' do
|
|
114
|
+
expect do
|
|
115
|
+
store.mark_ids_retryable([notification.id], deliver_after)
|
|
116
|
+
notification.reload
|
|
117
|
+
end.to change { notification.deliver_after.try(:utc).to_s }.to(deliver_after.utc.to_s)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
describe 'mark_batch_retryable' do
|
|
122
|
+
let(:deliver_after) { time + 10.seconds }
|
|
123
|
+
|
|
124
|
+
it 'sets the attributes on the object for use in reflections' do
|
|
125
|
+
store.mark_batch_retryable([notification], deliver_after)
|
|
126
|
+
expect(notification.deliver_after).to eq deliver_after
|
|
127
|
+
expect(notification.retries).to eq 1
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it 'increments the retired count' do
|
|
131
|
+
expect do
|
|
132
|
+
store.mark_batch_retryable([notification], deliver_after)
|
|
133
|
+
notification.reload
|
|
134
|
+
end.to change(notification, :retries).by(1)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it 'sets the deliver after timestamp' do
|
|
138
|
+
expect do
|
|
139
|
+
store.mark_batch_retryable([notification], deliver_after)
|
|
140
|
+
notification.reload
|
|
141
|
+
end.to change { notification.deliver_after.try(:utc).to_s }.to(deliver_after.utc.to_s)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
describe 'mark_delivered' do
|
|
146
|
+
it 'marks the notification as delivered' do
|
|
147
|
+
expect do
|
|
148
|
+
store.mark_delivered(notification, time)
|
|
149
|
+
end.to change(notification, :delivered).to(true)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it 'sets the time the notification was delivered' do
|
|
153
|
+
expect do
|
|
154
|
+
store.mark_delivered(notification, time)
|
|
155
|
+
notification.reload
|
|
156
|
+
end.to change { notification.delivered_at.try(:utc).to_s }.to(time.to_s)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it 'saves the notification without validation' do
|
|
160
|
+
expect(notification).to receive(:save!).with(validate: false)
|
|
161
|
+
store.mark_delivered(notification, time)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
it 'does not save the notification if persist: false' do
|
|
165
|
+
expect(notification).not_to receive(:save!)
|
|
166
|
+
store.mark_delivered(notification, time, persist: false)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
describe 'mark_batch_delivered' do
|
|
171
|
+
it 'sets the attributes on the object for use in reflections' do
|
|
172
|
+
store.mark_batch_delivered([notification])
|
|
173
|
+
expect(notification.delivered_at).to eq time
|
|
174
|
+
expect(notification.delivered).to be_truthy
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it 'marks the notifications as delivered' do
|
|
178
|
+
expect do
|
|
179
|
+
store.mark_batch_delivered([notification])
|
|
180
|
+
notification.reload
|
|
181
|
+
end.to change(notification, :delivered).to(true)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it 'sets the time the notifications were delivered' do
|
|
185
|
+
expect do
|
|
186
|
+
store.mark_batch_delivered([notification])
|
|
187
|
+
notification.reload
|
|
188
|
+
end.to change { notification.delivered_at.try(:utc).to_s }.to(time.to_s)
|
|
189
|
+
end
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
describe 'mark_failed' do
|
|
193
|
+
it 'marks the notification as not delivered' do
|
|
194
|
+
store.mark_failed(notification, nil, '', time)
|
|
195
|
+
expect(notification.delivered).to eq(false)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it 'marks the notification as failed' do
|
|
199
|
+
expect do
|
|
200
|
+
store.mark_failed(notification, nil, '', time)
|
|
201
|
+
notification.reload
|
|
202
|
+
end.to change(notification, :failed).to(true)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
it 'sets the time the notification delivery failed' do
|
|
206
|
+
expect do
|
|
207
|
+
store.mark_failed(notification, nil, '', time)
|
|
208
|
+
notification.reload
|
|
209
|
+
end.to change { notification.failed_at.try(:utc).to_s }.to(time.to_s)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
it 'sets the error code' do
|
|
213
|
+
expect do
|
|
214
|
+
store.mark_failed(notification, 42, '', time)
|
|
215
|
+
end.to change(notification, :error_code).to(42)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
it 'sets the error description' do
|
|
219
|
+
expect do
|
|
220
|
+
store.mark_failed(notification, 42, 'Weeee', time)
|
|
221
|
+
end.to change(notification, :error_description).to('Weeee')
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
it 'saves the notification without validation' do
|
|
225
|
+
expect(notification).to receive(:save!).with(validate: false)
|
|
226
|
+
store.mark_failed(notification, nil, '', time)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
it 'does not save the notification if persist: false' do
|
|
230
|
+
expect(notification).not_to receive(:save!)
|
|
231
|
+
store.mark_failed(notification, nil, '', time, persist: false)
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
describe 'mark_ids_failed' do
|
|
236
|
+
it 'marks the notification as failed' do
|
|
237
|
+
expect do
|
|
238
|
+
store.mark_ids_failed([notification.id], nil, '', Time.now)
|
|
239
|
+
notification.reload
|
|
240
|
+
end.to change(notification, :failed).to(true)
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
describe 'mark_batch_failed' do
|
|
245
|
+
it 'sets the attributes on the object for use in reflections' do
|
|
246
|
+
store.mark_batch_failed([notification], 123, 'an error')
|
|
247
|
+
expect(notification.failed_at).to eq time
|
|
248
|
+
expect(notification.delivered_at).to be_nil
|
|
249
|
+
expect(notification.delivered).to eq(false)
|
|
250
|
+
expect(notification.failed).to be_truthy
|
|
251
|
+
expect(notification.error_code).to eq 123
|
|
252
|
+
expect(notification.error_description).to eq 'an error'
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
it 'marks the notification as not delivered' do
|
|
256
|
+
store.mark_batch_failed([notification], nil, '')
|
|
257
|
+
notification.reload
|
|
258
|
+
expect(notification.delivered).to be_falsey
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
it 'marks the notification as failed' do
|
|
262
|
+
expect do
|
|
263
|
+
store.mark_batch_failed([notification], nil, '')
|
|
264
|
+
notification.reload
|
|
265
|
+
end.to change(notification, :failed).to(true)
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
it 'sets the time the notification delivery failed' do
|
|
269
|
+
expect do
|
|
270
|
+
store.mark_batch_failed([notification], nil, '')
|
|
271
|
+
notification.reload
|
|
272
|
+
end.to change { notification.failed_at.try(:utc).to_s }.to(time.to_s)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
it 'sets the error code' do
|
|
276
|
+
expect do
|
|
277
|
+
store.mark_batch_failed([notification], 42, '')
|
|
278
|
+
notification.reload
|
|
279
|
+
end.to change(notification, :error_code).to(42)
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
it 'sets the error description' do
|
|
283
|
+
expect do
|
|
284
|
+
store.mark_batch_failed([notification], 42, 'Weeee')
|
|
285
|
+
notification.reload
|
|
286
|
+
end.to change(notification, :error_description).to('Weeee')
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
describe 'create_apns_feedback' do
|
|
291
|
+
it 'creates the Feedback record' do
|
|
292
|
+
expect(Rpush::Client::Redis::Apns::Feedback).to receive(:create!).with(
|
|
293
|
+
failed_at: time, device_token: 'ab' * 32, app_id: app.id)
|
|
294
|
+
store.create_apns_feedback(time, 'ab' * 32, app)
|
|
295
|
+
end
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
describe 'create_gcm_notification' do
|
|
299
|
+
let(:data) { { data: true } }
|
|
300
|
+
let(:attributes) { { device_token: 'ab' * 32 } }
|
|
301
|
+
let(:registration_ids) { %w(123 456) }
|
|
302
|
+
let(:deliver_after) { time + 10.seconds }
|
|
303
|
+
let(:args) { [attributes, data, registration_ids, deliver_after, app] }
|
|
304
|
+
|
|
305
|
+
it 'sets the given attributes' do
|
|
306
|
+
new_notification = store.create_gcm_notification(*args)
|
|
307
|
+
expect(new_notification.device_token).to eq 'ab' * 32
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
it 'sets the given data' do
|
|
311
|
+
new_notification = store.create_gcm_notification(*args)
|
|
312
|
+
expect(new_notification.data).to eq(data: true)
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
it 'sets the given registration IDs' do
|
|
316
|
+
new_notification = store.create_gcm_notification(*args)
|
|
317
|
+
expect(new_notification.registration_ids).to eq registration_ids
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
it 'sets the deliver_after timestamp' do
|
|
321
|
+
new_notification = store.create_gcm_notification(*args)
|
|
322
|
+
expect(new_notification.deliver_after.utc.to_s).to eq deliver_after.to_s
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
it 'saves the new notification' do
|
|
326
|
+
new_notification = store.create_gcm_notification(*args)
|
|
327
|
+
expect(new_notification.new_record?).to be_falsey
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
describe 'create_adm_notification' do
|
|
332
|
+
let(:data) { { data: true } }
|
|
333
|
+
let(:attributes) { { app_id: app.id, collapse_key: 'ckey', delay_while_idle: true } }
|
|
334
|
+
let(:registration_ids) { %w(123 456) }
|
|
335
|
+
let(:deliver_after) { time + 10.seconds }
|
|
336
|
+
let(:args) { [attributes, data, registration_ids, deliver_after, app] }
|
|
337
|
+
|
|
338
|
+
it 'sets the given attributes' do
|
|
339
|
+
new_notification = store.create_adm_notification(*args)
|
|
340
|
+
expect(new_notification.app_id).to eq app.id
|
|
341
|
+
expect(new_notification.collapse_key).to eq 'ckey'
|
|
342
|
+
expect(new_notification.delay_while_idle).to be_truthy
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
it 'sets the given data' do
|
|
346
|
+
new_notification = store.create_adm_notification(*args)
|
|
347
|
+
expect(new_notification.data).to eq(data: true)
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
it 'sets the given registration IDs' do
|
|
351
|
+
new_notification = store.create_adm_notification(*args)
|
|
352
|
+
expect(new_notification.registration_ids).to eq registration_ids
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
it 'sets the deliver_after timestamp' do
|
|
356
|
+
new_notification = store.create_adm_notification(*args)
|
|
357
|
+
expect(new_notification.deliver_after.utc.to_s).to eq deliver_after.to_s
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
it 'saves the new notification' do
|
|
361
|
+
new_notification = store.create_adm_notification(*args)
|
|
362
|
+
expect(new_notification.new_record?).to be_falsey
|
|
363
|
+
end
|
|
364
|
+
end
|
|
365
|
+
end if redis?
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
require "unit_spec_helper"
|
|
2
|
+
|
|
3
|
+
describe Rpush::Daemon::TcpConnection do
|
|
4
|
+
let(:rsa_key) { double }
|
|
5
|
+
let(:certificate) { double }
|
|
6
|
+
let(:password) { double }
|
|
7
|
+
let(:x509_certificate) { OpenSSL::X509::Certificate.new(TEST_CERT) }
|
|
8
|
+
let(:ssl_context) { double(:key= => nil, :cert= => nil, cert: x509_certificate) }
|
|
9
|
+
let(:host) { 'gateway.push.apple.com' }
|
|
10
|
+
let(:port) { '2195' }
|
|
11
|
+
let(:tcp_socket) { double(setsockopt: nil, close: nil) }
|
|
12
|
+
let(:ssl_socket) { double(:sync= => nil, connect: nil, close: nil, write: nil, flush: nil) }
|
|
13
|
+
let(:logger) { double(info: nil, error: nil, warn: nil) }
|
|
14
|
+
let(:app) { double(name: 'Connection 0', certificate: certificate, password: password) }
|
|
15
|
+
let(:connection) { Rpush::Daemon::TcpConnection.new(app, host, port) }
|
|
16
|
+
|
|
17
|
+
before do
|
|
18
|
+
allow(OpenSSL::SSL::SSLContext).to receive_messages(new: ssl_context)
|
|
19
|
+
allow(OpenSSL::PKey::RSA).to receive_messages(new: rsa_key)
|
|
20
|
+
allow(OpenSSL::X509::Certificate).to receive_messages(new: x509_certificate)
|
|
21
|
+
allow(TCPSocket).to receive_messages(new: tcp_socket)
|
|
22
|
+
allow(OpenSSL::SSL::SSLSocket).to receive_messages(new: ssl_socket)
|
|
23
|
+
allow(Rpush).to receive_messages(logger: logger)
|
|
24
|
+
allow(connection).to receive(:reflect)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "reads the number of bytes from the SSL socket" do
|
|
28
|
+
expect(ssl_socket).to receive(:read).with(123)
|
|
29
|
+
connection.connect
|
|
30
|
+
connection.read(123)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "selects on the SSL socket until the given timeout" do
|
|
34
|
+
expect(IO).to receive(:select).with([ssl_socket], nil, nil, 10)
|
|
35
|
+
connection.connect
|
|
36
|
+
connection.select(10)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
describe "when setting up the SSL context" do
|
|
40
|
+
it "sets the key on the context" do
|
|
41
|
+
expect(OpenSSL::PKey::RSA).to receive(:new).with(certificate, password).and_return(rsa_key)
|
|
42
|
+
expect(ssl_context).to receive(:key=).with(rsa_key)
|
|
43
|
+
connection.connect
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "sets the cert on the context" do
|
|
47
|
+
expect(OpenSSL::X509::Certificate).to receive(:new).with(certificate).and_return(x509_certificate)
|
|
48
|
+
expect(ssl_context).to receive(:cert=).with(x509_certificate)
|
|
49
|
+
connection.connect
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "when connecting the socket" do
|
|
54
|
+
it "creates a TCP socket using the configured host and port" do
|
|
55
|
+
expect(TCPSocket).to receive(:new).with(host, port).and_return(tcp_socket)
|
|
56
|
+
connection.connect
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "creates a new SSL socket using the TCP socket and SSL context" do
|
|
60
|
+
expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(tcp_socket, ssl_context).and_return(ssl_socket)
|
|
61
|
+
connection.connect
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "sets the sync option on the SSL socket" do
|
|
65
|
+
expect(ssl_socket).to receive(:sync=).with(true)
|
|
66
|
+
connection.connect
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "connects the SSL socket" do
|
|
70
|
+
expect(ssl_socket).to receive(:connect)
|
|
71
|
+
connection.connect
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it "sets the socket option TCP_NODELAY" do
|
|
75
|
+
expect(tcp_socket).to receive(:setsockopt).with(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, true)
|
|
76
|
+
connection.connect
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "sets the socket option SO_KEEPALIVE" do
|
|
80
|
+
expect(tcp_socket).to receive(:setsockopt).with(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true)
|
|
81
|
+
connection.connect
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
describe 'certificate expiry' do
|
|
85
|
+
it 'reflects if the certificate will expire soon' do
|
|
86
|
+
cert = OpenSSL::X509::Certificate.new(app.certificate)
|
|
87
|
+
expect(connection).to receive(:reflect).with(:ssl_certificate_will_expire, app, cert.not_after)
|
|
88
|
+
Timecop.freeze(cert.not_after - 3.days) { connection.connect }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it 'logs that the certificate will expire soon' do
|
|
92
|
+
cert = OpenSSL::X509::Certificate.new(app.certificate)
|
|
93
|
+
expect(logger).to receive(:warn).with("[#{app.name}] Certificate will expire at 2022-09-07 03:18:32 UTC.")
|
|
94
|
+
Timecop.freeze(cert.not_after - 3.days) { connection.connect }
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it 'does not reflect if the certificate will not expire soon' do
|
|
98
|
+
cert = OpenSSL::X509::Certificate.new(app.certificate)
|
|
99
|
+
expect(connection).not_to receive(:reflect).with(:ssl_certificate_will_expire, app, kind_of(Time))
|
|
100
|
+
Timecop.freeze(cert.not_after - 2.months) { connection.connect }
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it 'logs that the certificate has expired' do
|
|
104
|
+
cert = OpenSSL::X509::Certificate.new(app.certificate)
|
|
105
|
+
expect(logger).to receive(:error).with("[#{app.name}] Certificate expired at 2022-09-07 03:18:32 UTC.")
|
|
106
|
+
Timecop.freeze(cert.not_after + 1.day) { connection.connect rescue Rpush::CertificateExpiredError }
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it 'raises an error if the certificate has expired' do
|
|
110
|
+
cert = OpenSSL::X509::Certificate.new(app.certificate)
|
|
111
|
+
Timecop.freeze(cert.not_after + 1.day) do
|
|
112
|
+
expect { connection.connect }.to raise_error(Rpush::CertificateExpiredError)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
describe 'certificate revocation' do
|
|
118
|
+
let(:cert_revoked_error) { OpenSSL::SSL::SSLError.new('certificate revoked') }
|
|
119
|
+
before do
|
|
120
|
+
allow(ssl_socket).to receive(:connect).and_raise(cert_revoked_error)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it 'reflects that the certificate has been revoked' do
|
|
124
|
+
expect(connection).to receive(:reflect).with(:ssl_certificate_revoked, app, cert_revoked_error)
|
|
125
|
+
expect { connection.connect }.to raise_error(Rpush::Daemon::TcpConnectionError, 'OpenSSL::SSL::SSLError, certificate revoked')
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it 'logs that the certificate has been revoked' do
|
|
129
|
+
expect(logger).to receive(:error).with('[Connection 0] Certificate has been revoked.')
|
|
130
|
+
expect { connection.connect }.to raise_error(Rpush::Daemon::TcpConnectionError, 'OpenSSL::SSL::SSLError, certificate revoked')
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
describe "when shuting down the connection" do
|
|
136
|
+
it "closes the TCP socket" do
|
|
137
|
+
connection.connect
|
|
138
|
+
expect(tcp_socket).to receive(:close)
|
|
139
|
+
connection.close
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "does not attempt to close the TCP socket if it is not connected" do
|
|
143
|
+
connection.connect
|
|
144
|
+
expect(tcp_socket).not_to receive(:close)
|
|
145
|
+
connection.instance_variable_set("@tcp_socket", nil)
|
|
146
|
+
connection.close
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
it "closes the SSL socket" do
|
|
150
|
+
connection.connect
|
|
151
|
+
expect(ssl_socket).to receive(:close)
|
|
152
|
+
connection.close
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "does not attempt to close the SSL socket if it is not connected" do
|
|
156
|
+
connection.connect
|
|
157
|
+
expect(ssl_socket).not_to receive(:close)
|
|
158
|
+
connection.instance_variable_set("@ssl_socket", nil)
|
|
159
|
+
connection.close
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it "ignores IOError when the socket is already closed" do
|
|
163
|
+
allow(tcp_socket).to receive(:close).and_raise(IOError)
|
|
164
|
+
connection.connect
|
|
165
|
+
connection.close
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
shared_examples_for "when the write fails" do
|
|
170
|
+
before do
|
|
171
|
+
allow(connection).to receive(:sleep)
|
|
172
|
+
connection.connect
|
|
173
|
+
allow(ssl_socket).to receive(:write).and_raise(error)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it 'reflects the connection has been lost' do
|
|
177
|
+
expect(connection).to receive(:reflect).with(:tcp_connection_lost, app, kind_of(error.class))
|
|
178
|
+
expect { connection.write(nil) }.to raise_error(Rpush::Daemon::TcpConnectionError)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it "logs that the connection has been lost once only" do
|
|
182
|
+
expect(logger).to receive(:error).with("[Connection 0] Lost connection to gateway.push.apple.com:2195 (#{error.class.name}, #{error.message}), reconnecting...").once
|
|
183
|
+
expect { connection.write(nil) }.to raise_error(Rpush::Daemon::TcpConnectionError)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it "retries to make a connection 3 times" do
|
|
187
|
+
expect(connection).to receive(:reconnect).exactly(3).times
|
|
188
|
+
expect { connection.write(nil) }.to raise_error(Rpush::Daemon::TcpConnectionError)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
it "raises a TcpConnectionError after 3 attempts at reconnecting" do
|
|
192
|
+
expect do
|
|
193
|
+
connection.write(nil)
|
|
194
|
+
end.to raise_error(Rpush::Daemon::TcpConnectionError, "Connection 0 tried 3 times to reconnect but failed (#{error.class.name}, #{error.message}).")
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
it "sleeps 1 second before retrying the connection" do
|
|
198
|
+
expect(connection).to receive(:sleep).with(1)
|
|
199
|
+
expect { connection.write(nil) }.to raise_error(Rpush::Daemon::TcpConnectionError)
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
describe "when write raises an Errno::EPIPE" do
|
|
204
|
+
it_should_behave_like "when the write fails"
|
|
205
|
+
|
|
206
|
+
def error
|
|
207
|
+
Errno::EPIPE.new('an message')
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
describe "when write raises an Errno::ETIMEDOUT" do
|
|
212
|
+
it_should_behave_like "when the write fails"
|
|
213
|
+
|
|
214
|
+
def error
|
|
215
|
+
Errno::ETIMEDOUT.new('an message')
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
describe "when write raises an OpenSSL::SSL::SSLError" do
|
|
220
|
+
it_should_behave_like "when the write fails"
|
|
221
|
+
|
|
222
|
+
def error
|
|
223
|
+
OpenSSL::SSL::SSLError.new('an message')
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
describe "when write raises an IOError" do
|
|
228
|
+
it_should_behave_like "when the write fails"
|
|
229
|
+
|
|
230
|
+
def error
|
|
231
|
+
IOError.new('an message')
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
describe "when reconnecting" do
|
|
236
|
+
before { connection.connect }
|
|
237
|
+
|
|
238
|
+
it 'closes the socket' do
|
|
239
|
+
expect(connection).to receive(:close)
|
|
240
|
+
connection.send(:reconnect)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
it 'connects the socket' do
|
|
244
|
+
expect(connection).to receive(:connect_socket)
|
|
245
|
+
connection.send(:reconnect)
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
describe "when sending a notification" do
|
|
250
|
+
before { connection.connect }
|
|
251
|
+
|
|
252
|
+
it "writes the data to the SSL socket" do
|
|
253
|
+
expect(ssl_socket).to receive(:write).with("blah")
|
|
254
|
+
connection.write("blah")
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
it "flushes the SSL socket" do
|
|
258
|
+
expect(ssl_socket).to receive(:flush)
|
|
259
|
+
connection.write("blah")
|
|
260
|
+
end
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
describe 'idle period' do
|
|
264
|
+
before { connection.connect }
|
|
265
|
+
|
|
266
|
+
it 'reconnects if the connection has been idle for more than the defined period' do
|
|
267
|
+
allow(Rpush::Daemon::TcpConnection).to receive_messages(idle_period: 60)
|
|
268
|
+
allow(Time).to receive_messages(now: Time.now + 61)
|
|
269
|
+
expect(connection).to receive(:reconnect)
|
|
270
|
+
connection.write('blah')
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
it 'resets the last touch time' do
|
|
274
|
+
now = Time.now
|
|
275
|
+
allow(Time).to receive_messages(now: now)
|
|
276
|
+
connection.write('blah')
|
|
277
|
+
expect(connection.last_touch).to eq now
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
it 'does not reconnect if the connection has not been idle for more than the defined period' do
|
|
281
|
+
expect(connection).not_to receive(:reconnect)
|
|
282
|
+
connection.write('blah')
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
it 'logs the the connection is idle' do
|
|
286
|
+
allow(Rpush::Daemon::TcpConnection).to receive_messages(idle_period: 60)
|
|
287
|
+
allow(Time).to receive_messages(now: Time.now + 61)
|
|
288
|
+
expect(Rpush.logger).to receive(:info).with('[Connection 0] Idle period exceeded, reconnecting...')
|
|
289
|
+
connection.write('blah')
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
end
|