rpush 1.0.0 → 2.0.0.beta1
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 +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +12 -14
- data/bin/rpush +11 -2
- data/lib/generators/rpush_generator.rb +2 -0
- data/lib/generators/templates/add_adm.rb +5 -5
- data/lib/generators/templates/add_alert_is_json_to_rapns_notifications.rb +1 -1
- data/lib/generators/templates/add_app_to_rapns.rb +2 -2
- data/lib/generators/templates/add_fail_after_to_rpush_notifications.rb +1 -1
- data/lib/generators/templates/add_gcm.rb +32 -32
- data/lib/generators/templates/add_rpush.rb +67 -67
- data/lib/generators/templates/add_wpns.rb +2 -2
- data/lib/generators/templates/create_rapns_apps.rb +5 -5
- data/lib/generators/templates/create_rapns_feedback.rb +2 -2
- data/lib/generators/templates/create_rapns_notifications.rb +15 -15
- data/lib/generators/templates/rpush.rb +10 -7
- data/lib/generators/templates/rpush_2_0_0_updates.rb +23 -0
- data/lib/rpush.rb +4 -28
- data/lib/rpush/client/active_model.rb +21 -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 +90 -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 +31 -0
- data/lib/rpush/client/active_model/notification.rb +26 -0
- data/lib/rpush/client/active_model/payload_data_size_validator.rb +13 -0
- data/lib/rpush/client/active_model/registration_ids_count_validator.rb +13 -0
- data/lib/rpush/client/active_model/wpns/app.rb +13 -0
- data/lib/rpush/client/active_model/wpns/notification.rb +17 -0
- data/lib/rpush/client/active_record.rb +19 -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 +20 -0
- data/lib/rpush/client/active_record/apns/notification.rb +46 -0
- data/lib/rpush/client/active_record/app.rb +17 -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 +38 -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/redis.rb +35 -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/app.rb +22 -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 +68 -0
- data/lib/rpush/client/redis/wpns/app.rb +11 -0
- data/lib/rpush/client/redis/wpns/notification.rb +11 -0
- data/lib/rpush/configuration.rb +27 -6
- data/lib/rpush/daemon.rb +36 -56
- data/lib/rpush/daemon/adm/delivery.rb +50 -52
- data/lib/rpush/daemon/apns.rb +6 -5
- data/lib/rpush/daemon/apns/delivery.rb +20 -44
- data/lib/rpush/daemon/apns/feedback_receiver.rb +11 -8
- data/lib/rpush/daemon/app_runner.rb +67 -60
- data/lib/rpush/daemon/batch.rb +54 -40
- data/lib/rpush/daemon/delivery.rb +13 -3
- data/lib/rpush/daemon/delivery_error.rb +10 -2
- data/lib/rpush/daemon/dispatcher/apns_tcp.rb +106 -0
- data/lib/rpush/daemon/dispatcher/http.rb +3 -3
- data/lib/rpush/daemon/dispatcher/tcp.rb +3 -3
- data/lib/rpush/daemon/dispatcher_loop.rb +15 -6
- data/lib/rpush/daemon/errors.rb +18 -0
- data/lib/rpush/daemon/feeder.rb +28 -39
- data/lib/rpush/daemon/gcm/delivery.rb +19 -20
- data/lib/rpush/daemon/interruptible_sleep.rb +26 -45
- data/lib/rpush/daemon/loggable.rb +2 -4
- data/lib/rpush/daemon/proc_title.rb +16 -0
- data/lib/rpush/daemon/queue_payload.rb +12 -0
- data/lib/rpush/daemon/reflectable.rb +3 -5
- data/lib/rpush/daemon/retry_header_parser.rb +6 -6
- data/lib/rpush/daemon/ring_buffer.rb +16 -0
- data/lib/rpush/daemon/service_config_methods.rb +23 -7
- data/lib/rpush/daemon/signal_handler.rb +51 -0
- data/lib/rpush/daemon/store/active_record.rb +71 -38
- data/lib/rpush/daemon/store/active_record/reconnectable.rb +15 -15
- data/lib/rpush/daemon/store/interface.rb +19 -0
- data/lib/rpush/daemon/store/redis.rb +149 -0
- data/lib/rpush/daemon/tcp_connection.rb +6 -11
- data/lib/rpush/daemon/wpns/delivery.rb +21 -30
- data/lib/rpush/deprecatable.rb +4 -3
- data/lib/rpush/deprecation.rb +7 -10
- data/lib/rpush/embed.rb +7 -2
- data/lib/rpush/logger.rb +11 -15
- data/lib/rpush/push.rb +0 -1
- data/lib/rpush/reflection.rb +6 -12
- data/lib/rpush/version.rb +1 -1
- data/lib/tasks/quality.rake +34 -0
- data/spec/.rubocop.yml +4 -0
- data/spec/functional/adm_spec.rb +3 -6
- data/spec/functional/apns_spec.rb +118 -24
- data/spec/functional/embed_spec.rb +22 -20
- data/spec/functional/gcm_spec.rb +4 -7
- data/spec/functional/new_app_spec.rb +61 -0
- data/spec/functional/retry_spec.rb +46 -0
- data/spec/functional/wpns_spec.rb +3 -6
- data/spec/functional_spec_helper.rb +26 -0
- data/spec/integration/rpush_spec.rb +13 -0
- data/spec/integration/support/gcm_success_response.json +1 -0
- data/spec/spec_helper.rb +60 -0
- data/spec/support/active_record_setup.rb +48 -0
- data/{config → spec/support/config}/database.yml +0 -0
- data/spec/support/install.sh +43 -7
- data/spec/support/simplecov_helper.rb +9 -5
- data/spec/support/simplecov_quality_formatter.rb +10 -6
- data/spec/unit/apns_feedback_spec.rb +3 -3
- data/spec/unit/{adm → client/active_record/adm}/app_spec.rb +3 -3
- data/spec/unit/{adm → client/active_record/adm}/notification_spec.rb +5 -7
- 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 +231 -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/{gcm → client/active_record/gcm}/notification_spec.rb +5 -7
- data/spec/unit/client/active_record/notification_spec.rb +15 -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 +12 -5
- data/spec/unit/daemon/adm/delivery_spec.rb +57 -54
- data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +3 -3
- data/spec/unit/daemon/apns/delivery_spec.rb +90 -83
- data/spec/unit/daemon/apns/feedback_receiver_spec.rb +24 -17
- data/spec/unit/daemon/app_runner_spec.rb +66 -123
- data/spec/unit/daemon/batch_spec.rb +52 -115
- data/spec/unit/daemon/delivery_spec.rb +15 -1
- data/spec/unit/daemon/dispatcher/http_spec.rb +3 -2
- data/spec/unit/daemon/dispatcher/tcp_spec.rb +10 -9
- data/spec/unit/daemon/dispatcher_loop_spec.rb +7 -12
- data/spec/unit/daemon/feeder_spec.rb +40 -39
- data/spec/unit/daemon/gcm/delivery_spec.rb +108 -89
- data/spec/unit/daemon/reflectable_spec.rb +2 -2
- data/spec/unit/daemon/retryable_error_spec.rb +1 -1
- data/spec/unit/daemon/service_config_methods_spec.rb +6 -3
- data/spec/unit/daemon/signal_handler_spec.rb +72 -0
- data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +9 -9
- data/spec/unit/daemon/store/active_record_spec.rb +38 -47
- data/spec/unit/daemon/tcp_connection_spec.rb +22 -34
- data/spec/unit/daemon/too_many_requests_error_spec.rb +1 -1
- data/spec/unit/daemon/wpns/delivery_spec.rb +61 -50
- data/spec/unit/daemon_spec.rb +46 -81
- data/spec/unit/embed_spec.rb +4 -2
- data/spec/unit/logger_spec.rb +30 -40
- data/spec/unit/notification_shared.rb +9 -79
- data/spec/unit/push_spec.rb +3 -8
- data/spec/unit/reflection_spec.rb +25 -25
- data/spec/unit/rpush_spec.rb +1 -2
- data/spec/unit_spec_helper.rb +33 -88
- metadata +119 -67
- data/lib/rpush/TODO +0 -3
- data/lib/rpush/adm/app.rb +0 -15
- data/lib/rpush/adm/data_validator.rb +0 -11
- data/lib/rpush/adm/notification.rb +0 -29
- data/lib/rpush/apns/app.rb +0 -29
- data/lib/rpush/apns/binary_notification_validator.rb +0 -12
- data/lib/rpush/apns/device_token_format_validator.rb +0 -12
- data/lib/rpush/apns/feedback.rb +0 -16
- data/lib/rpush/apns/notification.rb +0 -84
- data/lib/rpush/app.rb +0 -18
- data/lib/rpush/daemon/apns/certificate_expired_error.rb +0 -20
- data/lib/rpush/daemon/apns/disconnection_error.rb +0 -20
- data/lib/rpush/gcm/app.rb +0 -11
- data/lib/rpush/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +0 -11
- data/lib/rpush/gcm/notification.rb +0 -30
- data/lib/rpush/notification.rb +0 -69
- data/lib/rpush/notifier.rb +0 -52
- data/lib/rpush/payload_data_size_validator.rb +0 -10
- data/lib/rpush/railtie.rb +0 -11
- data/lib/rpush/registration_ids_count_validator.rb +0 -10
- data/lib/rpush/wpns/app.rb +0 -9
- data/lib/rpush/wpns/notification.rb +0 -26
- data/lib/tasks/cane.rake +0 -18
- data/lib/tasks/rpush.rake +0 -16
- data/spec/unit/apns/app_spec.rb +0 -29
- data/spec/unit/apns/feedback_spec.rb +0 -9
- data/spec/unit/apns/notification_spec.rb +0 -208
- data/spec/unit/app_spec.rb +0 -30
- data/spec/unit/daemon/apns/disconnection_error_spec.rb +0 -18
- data/spec/unit/daemon/interruptible_sleep_spec.rb +0 -68
- data/spec/unit/gcm/app_spec.rb +0 -4
- data/spec/unit/notification_spec.rb +0 -15
- data/spec/unit/notifier_spec.rb +0 -49
- data/spec/unit/wpns/app_spec.rb +0 -4
- data/spec/unit/wpns/notification_spec.rb +0 -30
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'unit_spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Rpush::Client::ActiveRecord::App do
|
|
4
|
+
it 'validates the uniqueness of name within type and environment' do
|
|
5
|
+
Rpush::Client::ActiveRecord::Apns::App.create!(name: 'test', environment: 'production', certificate: TEST_CERT)
|
|
6
|
+
app = Rpush::Client::ActiveRecord::Apns::App.new(name: 'test', environment: 'production', certificate: TEST_CERT)
|
|
7
|
+
app.valid?.should be_false
|
|
8
|
+
app.errors[:name].should eq ['has already been taken']
|
|
9
|
+
|
|
10
|
+
app = Rpush::Client::ActiveRecord::Apns::App.new(name: 'test', environment: 'development', certificate: TEST_CERT)
|
|
11
|
+
app.valid?.should be_true
|
|
12
|
+
|
|
13
|
+
app = Rpush::Client::ActiveRecord::Gcm::App.new(name: 'test', environment: 'production', auth_key: TEST_CERT)
|
|
14
|
+
app.valid?.should be_true
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
context 'validating certificates' do
|
|
18
|
+
it 'rescues from certificate error' do
|
|
19
|
+
app = Rpush::Client::ActiveRecord::Apns::App.new(name: 'test', environment: 'development', certificate: 'bad')
|
|
20
|
+
expect { app.valid? }.not_to raise_error
|
|
21
|
+
expect(app.valid?).to be_false
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it 'raises other errors' do
|
|
25
|
+
app = Rpush::Client::ActiveRecord::Apns::App.new(name: 'test', environment: 'development', certificate: 'bad')
|
|
26
|
+
OpenSSL::X509::Certificate.stub(:new).and_raise(NameError, 'simulating no openssl')
|
|
27
|
+
expect { app.valid? }.to raise_error(NameError)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
require 'unit_spec_helper'
|
|
2
2
|
require 'unit/notification_shared.rb'
|
|
3
3
|
|
|
4
|
-
describe Rpush::Gcm::Notification do
|
|
4
|
+
describe Rpush::Client::ActiveRecord::Gcm::Notification do
|
|
5
5
|
it_should_behave_like 'an Notification subclass'
|
|
6
6
|
|
|
7
|
-
let(:app) { Rpush::Gcm::App.create!(:
|
|
8
|
-
let(:notification_class) { Rpush::Gcm::Notification }
|
|
7
|
+
let(:app) { Rpush::Client::ActiveRecord::Gcm::App.create!(name: 'test', auth_key: 'abc') }
|
|
8
|
+
let(:notification_class) { Rpush::Client::ActiveRecord::Gcm::Notification }
|
|
9
9
|
let(:notification) { notification_class.new }
|
|
10
|
-
let(:data_setter) { 'data=' }
|
|
11
|
-
let(:data_getter) { 'data' }
|
|
12
10
|
|
|
13
11
|
it "has a 'data' payload limit of 4096 bytes" do
|
|
14
|
-
notification.data = { :
|
|
12
|
+
notification.data = { key: "a" * 4096 }
|
|
15
13
|
notification.valid?.should be_false
|
|
16
14
|
notification.errors[:base].should eq ["Notification payload data cannot be larger than 4096 bytes."]
|
|
17
15
|
end
|
|
18
16
|
|
|
19
17
|
it 'limits the number of registration ids to 1000' do
|
|
20
|
-
notification.registration_ids = ['a']*(1000+1)
|
|
18
|
+
notification.registration_ids = ['a'] * (1000 + 1)
|
|
21
19
|
notification.valid?.should be_false
|
|
22
20
|
notification.errors[:base].should eq ["Number of registration_ids cannot be larger than 1000."]
|
|
23
21
|
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'unit_spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Rpush::Client::ActiveRecord::Notification do
|
|
4
|
+
let(:notification) { Rpush::Client::ActiveRecord::Notification.new }
|
|
5
|
+
|
|
6
|
+
it 'allows assignment of many registration IDs' do
|
|
7
|
+
notification.registration_ids = %w(a b)
|
|
8
|
+
notification.registration_ids.should eq %w(a b)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it 'allows assignment of a single registration ID' do
|
|
12
|
+
notification.registration_ids = 'a'
|
|
13
|
+
notification.registration_ids.should eq ['a']
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'unit_spec_helper'
|
|
2
|
+
require 'unit/notification_shared.rb'
|
|
3
|
+
|
|
4
|
+
describe Rpush::Client::ActiveRecord::Wpns::Notification do
|
|
5
|
+
it_should_behave_like 'an Notification subclass'
|
|
6
|
+
let(:app) { Rpush::Client::ActiveRecord::Wpns::App.create!(name: 'test', auth_key: 'abc') }
|
|
7
|
+
let(:notification_class) { Rpush::Client::ActiveRecord::Wpns::Notification }
|
|
8
|
+
let(:notification) { notification_class.new }
|
|
9
|
+
|
|
10
|
+
it "should have an url in the uri parameter" do
|
|
11
|
+
notification = Rpush::Client::ActiveRecord::Wpns::Notification.new(uri: "somthing")
|
|
12
|
+
notification.valid?
|
|
13
|
+
notification.errors[:uri].include?("is invalid").should be_true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should be invalid if there's no message" do
|
|
17
|
+
notification = Rpush::Client::ActiveRecord::Wpns::Notification.new(alert: "")
|
|
18
|
+
notification.valid?
|
|
19
|
+
notification.errors[:alert].include?("can't be blank").should be_true
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
require 'unit_spec_helper'
|
|
2
2
|
|
|
3
3
|
describe Rpush do
|
|
4
|
-
let(:config) {
|
|
4
|
+
let(:config) { Rpush.config }
|
|
5
5
|
|
|
6
|
-
before
|
|
6
|
+
before do
|
|
7
|
+
Rpush.stub(require: nil)
|
|
8
|
+
Rpush.stub(config: config)
|
|
9
|
+
end
|
|
7
10
|
|
|
8
|
-
it '
|
|
11
|
+
it 'yields a configure block' do
|
|
9
12
|
expect { |b| Rpush.configure(&b) }.to yield_with_args(config)
|
|
10
13
|
end
|
|
11
14
|
end
|
|
@@ -26,9 +29,8 @@ describe Rpush::Configuration do
|
|
|
26
29
|
end
|
|
27
30
|
|
|
28
31
|
it 'sets the pid_file relative if not absolute' do
|
|
29
|
-
Rails.stub(:root => '/rails')
|
|
30
32
|
config.pid_file = 'tmp/rpush.pid'
|
|
31
|
-
config.pid_file.should eq '/
|
|
33
|
+
config.pid_file.should eq '/tmp/rails_root/tmp/rpush.pid'
|
|
32
34
|
end
|
|
33
35
|
|
|
34
36
|
it 'does not alter an absolute pid_file path' do
|
|
@@ -42,4 +44,9 @@ describe Rpush::Configuration do
|
|
|
42
44
|
config.foreground = false
|
|
43
45
|
config.foreground.should be_true
|
|
44
46
|
end
|
|
47
|
+
|
|
48
|
+
it 'delegate redis_options to Modis' do
|
|
49
|
+
Rpush.config.redis_options = { hi: :mom }
|
|
50
|
+
Modis.redis_options.should eq(hi: :mom)
|
|
51
|
+
end
|
|
45
52
|
end
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
require 'unit_spec_helper'
|
|
2
2
|
|
|
3
3
|
describe Rpush::Daemon::Adm::Delivery do
|
|
4
|
-
let(:app) { Rpush::Adm::App.
|
|
5
|
-
let(:notification) { Rpush::Adm::Notification.create!(:
|
|
6
|
-
let(:logger) { double(:
|
|
7
|
-
let(:response) { double(:
|
|
8
|
-
let(:http) { double(:
|
|
4
|
+
let(:app) { Rpush::Adm::App.create!(name: 'MyApp', client_id: 'CLIENT_ID', client_secret: 'CLIENT_SECRET') }
|
|
5
|
+
let(:notification) { Rpush::Adm::Notification.create!(app: app, registration_ids: ['xyz'], deliver_after: Time.now, data: { 'message' => 'test' }) }
|
|
6
|
+
let(:logger) { double(error: nil, info: nil, warn: nil) }
|
|
7
|
+
let(:response) { double(code: 200, header: {}) }
|
|
8
|
+
let(:http) { double(shutdown: nil, request: response) }
|
|
9
9
|
let(:now) { Time.parse('2012-10-14 00:00:00') }
|
|
10
|
-
let(:batch) { double(:
|
|
10
|
+
let(:batch) { double(mark_failed: nil, mark_delivered: nil, mark_retryable: nil, notification_processed: nil) }
|
|
11
11
|
let(:delivery) { Rpush::Daemon::Adm::Delivery.new(app, http, notification, batch) }
|
|
12
|
-
let(:store) { double(:
|
|
12
|
+
let(:store) { double(create_adm_notification: double(id: 2)) }
|
|
13
13
|
|
|
14
14
|
def perform
|
|
15
15
|
delivery.perform
|
|
@@ -19,44 +19,45 @@ describe Rpush::Daemon::Adm::Delivery do
|
|
|
19
19
|
app.access_token = 'ACCESS_TOKEN'
|
|
20
20
|
app.access_token_expiration = Time.now + 1.month
|
|
21
21
|
|
|
22
|
-
delivery.stub(:
|
|
23
|
-
Rpush::Daemon.stub(:
|
|
24
|
-
Time.stub(:
|
|
25
|
-
Rpush.stub(:
|
|
22
|
+
delivery.stub(reflect: nil)
|
|
23
|
+
Rpush::Daemon.stub(store: store)
|
|
24
|
+
Time.stub(now: now)
|
|
25
|
+
Rpush.stub(logger: logger)
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
describe 'unknown error response' do
|
|
29
29
|
before do
|
|
30
|
-
response.stub(:
|
|
30
|
+
response.stub(code: 408)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
it 'marks the notification as failed because no successful delivery was made' do
|
|
34
|
-
response.stub(:
|
|
35
|
-
|
|
34
|
+
response.stub(body: JSON.dump('reason' => 'InvalidData'))
|
|
35
|
+
error = Rpush::DeliveryError.new(408, notification.id, 'Request Timeout')
|
|
36
|
+
delivery.should_receive(:mark_failed).with(error)
|
|
36
37
|
expect { perform }.to raise_error(Rpush::DeliveryError)
|
|
37
38
|
end
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
describe 'a 200 (Ok) response' do
|
|
41
42
|
before do
|
|
42
|
-
response.stub(:
|
|
43
|
+
response.stub(code: 200)
|
|
43
44
|
end
|
|
44
45
|
|
|
45
46
|
it 'marks the notification as delivered if delivered successfully to all devices' do
|
|
46
|
-
response.stub(:
|
|
47
|
+
response.stub(body: JSON.dump('registrationID' => 'xyz'))
|
|
47
48
|
delivery.should_receive(:mark_delivered)
|
|
48
49
|
perform
|
|
49
50
|
end
|
|
50
51
|
|
|
51
52
|
it 'logs that the notification was delivered' do
|
|
52
|
-
response.stub(:
|
|
53
|
+
response.stub(body: JSON.dump('registrationID' => 'xyz'))
|
|
53
54
|
logger.should_receive(:info).with("[MyApp] #{notification.id} sent to xyz")
|
|
54
55
|
perform
|
|
55
56
|
end
|
|
56
57
|
|
|
57
58
|
it 'reflects on canonical IDs' do
|
|
58
|
-
response.stub(:
|
|
59
|
-
notification.stub(:
|
|
59
|
+
response.stub(body: JSON.dump('registrationID' => 'canonical123'))
|
|
60
|
+
notification.stub(registration_ids: ['1'])
|
|
60
61
|
delivery.should_receive(:reflect).with(:adm_canonical_id, '1', 'canonical123')
|
|
61
62
|
perform
|
|
62
63
|
end
|
|
@@ -64,31 +65,32 @@ describe Rpush::Daemon::Adm::Delivery do
|
|
|
64
65
|
|
|
65
66
|
describe 'a 400 (Bad Request) response' do
|
|
66
67
|
before do
|
|
67
|
-
response.stub(:
|
|
68
|
+
response.stub(code: 400)
|
|
68
69
|
end
|
|
69
70
|
|
|
70
71
|
it 'marks the notification as failed because no successful delivery was made' do
|
|
71
|
-
response.stub(:
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
response.stub(body: JSON.dump('reason' => 'InvalidData'))
|
|
73
|
+
error = Rpush::DeliveryError.new(nil, notification.id, 'Failed to deliver to all recipients.')
|
|
74
|
+
delivery.should_receive(:mark_failed).with(error)
|
|
75
|
+
expect { perform }.to raise_error(error)
|
|
74
76
|
end
|
|
75
77
|
|
|
76
78
|
it 'logs that the notification was not delivered' do
|
|
77
|
-
response.stub(:
|
|
79
|
+
response.stub(body: JSON.dump('reason' => 'InvalidRegistrationId'))
|
|
78
80
|
logger.should_receive(:warn).with("[MyApp] bad_request: xyz (InvalidRegistrationId)")
|
|
79
|
-
expect { perform }.to raise_error
|
|
81
|
+
expect { perform }.to raise_error
|
|
80
82
|
end
|
|
81
83
|
end
|
|
82
84
|
|
|
83
85
|
describe 'a 401 (Unauthorized) response' do
|
|
84
|
-
let(:http) { double(:
|
|
85
|
-
let(:token_response) { double(:
|
|
86
|
+
let(:http) { double(shutdown: nil) }
|
|
87
|
+
let(:token_response) { double(code: 200, header: {}, body: JSON.dump('access_token' => 'ACCESS_TOKEN', 'expires_in' => 60)) }
|
|
86
88
|
|
|
87
89
|
before do
|
|
88
|
-
response.stub(:
|
|
90
|
+
response.stub(code: 401, header: { 'retry-after' => 10 })
|
|
89
91
|
|
|
90
92
|
# first request to deliver message that returns unauthorized response
|
|
91
|
-
adm_uri = URI.parse(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL
|
|
93
|
+
adm_uri = URI.parse(format(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL, notification.registration_ids.first))
|
|
92
94
|
http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(response)
|
|
93
95
|
end
|
|
94
96
|
|
|
@@ -116,7 +118,7 @@ describe Rpush::Daemon::Adm::Delivery do
|
|
|
116
118
|
end
|
|
117
119
|
|
|
118
120
|
it 'should log the error and stop retrying if new access token can\'t be retrieved' do
|
|
119
|
-
token_response.stub(:
|
|
121
|
+
token_response.stub(code: 404, body: "test")
|
|
120
122
|
# request for access token
|
|
121
123
|
http.should_receive(:request).with(Rpush::Daemon::Adm::Delivery::AMAZON_TOKEN_URI, instance_of(Net::HTTP::Post)).and_return(token_response)
|
|
122
124
|
|
|
@@ -130,15 +132,15 @@ describe Rpush::Daemon::Adm::Delivery do
|
|
|
130
132
|
end
|
|
131
133
|
|
|
132
134
|
describe 'a 429 (Too Many Request) response' do
|
|
133
|
-
let(:http) { double(:
|
|
134
|
-
let(:notification) { Rpush::Adm::Notification.create!(:
|
|
135
|
-
let(:too_many_request_response) { double(:
|
|
135
|
+
let(:http) { double(shutdown: nil) }
|
|
136
|
+
let(:notification) { Rpush::Adm::Notification.create!(app: app, registration_ids: %w(abc xyz), deliver_after: Time.now, collapse_key: 'sync', data: { 'message' => 'test' }) }
|
|
137
|
+
let(:too_many_request_response) { double(code: 429, header: { 'retry-after' => 3600 }) }
|
|
136
138
|
|
|
137
139
|
it 'should retry the entire notification respecting the Retry-After header if none sent out yet' do
|
|
138
|
-
response.stub(:
|
|
140
|
+
response.stub(code: 429, header: { 'retry-after' => 3600 })
|
|
139
141
|
|
|
140
142
|
# first request to deliver message that returns too many request response
|
|
141
|
-
adm_uri = URI.parse(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL
|
|
143
|
+
adm_uri = URI.parse(format(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL, notification.registration_ids.first))
|
|
142
144
|
http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(response)
|
|
143
145
|
|
|
144
146
|
delivery.should_receive(:mark_retryable).with(notification, now + 1.hour)
|
|
@@ -146,25 +148,25 @@ describe Rpush::Daemon::Adm::Delivery do
|
|
|
146
148
|
end
|
|
147
149
|
|
|
148
150
|
it 'should retry the entire notification using exponential backoff' do
|
|
149
|
-
response.stub(:
|
|
151
|
+
response.stub(code: 429, header: {})
|
|
150
152
|
|
|
151
153
|
# first request to deliver message that returns too many request response
|
|
152
|
-
adm_uri = URI.parse(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL
|
|
154
|
+
adm_uri = URI.parse(format(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL, notification.registration_ids.first))
|
|
153
155
|
http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(response)
|
|
154
156
|
|
|
155
|
-
delivery.should_receive(:mark_retryable).with(notification, Time.now + 2
|
|
157
|
+
delivery.should_receive(:mark_retryable).with(notification, Time.now + 2**(notification.retries + 1))
|
|
156
158
|
perform
|
|
157
159
|
end
|
|
158
160
|
|
|
159
161
|
it 'should keep sent reg ids in original notification and create new notification with remaining reg ids for retry' do
|
|
160
|
-
response.stub(:
|
|
162
|
+
response.stub(code: 200, body: JSON.dump('registrationID' => 'abc'))
|
|
161
163
|
|
|
162
164
|
# first request to deliver message succeeds
|
|
163
|
-
adm_uri = URI.parse(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL
|
|
165
|
+
adm_uri = URI.parse(format(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL, 'abc'))
|
|
164
166
|
http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(response)
|
|
165
167
|
|
|
166
168
|
# first request to deliver message that returns too many request response
|
|
167
|
-
adm_uri = URI.parse(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL
|
|
169
|
+
adm_uri = URI.parse(format(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL, 'xyz'))
|
|
168
170
|
http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(too_many_request_response)
|
|
169
171
|
|
|
170
172
|
store.should_receive(:update_notification).with do |notif|
|
|
@@ -172,10 +174,10 @@ describe Rpush::Daemon::Adm::Delivery do
|
|
|
172
174
|
notif.registration_ids.include?('xyz').should be_false
|
|
173
175
|
end
|
|
174
176
|
|
|
175
|
-
store.should_receive(:create_adm_notification).with do |attrs,
|
|
176
|
-
attrs.
|
|
177
|
-
attrs.
|
|
178
|
-
attrs.
|
|
177
|
+
store.should_receive(:create_adm_notification).with do |attrs, _notification_data, reg_ids, deliver_after, notification_app|
|
|
178
|
+
attrs.key?('collapse_key').should be_true
|
|
179
|
+
attrs.key?('delay_while_idle').should be_true
|
|
180
|
+
attrs.key?('app_id').should be_true
|
|
179
181
|
|
|
180
182
|
reg_ids.should eq ['xyz']
|
|
181
183
|
deliver_after.should eq now + 1.hour
|
|
@@ -190,11 +192,12 @@ describe Rpush::Daemon::Adm::Delivery do
|
|
|
190
192
|
|
|
191
193
|
describe 'a 500 (Internal Server Error) response' do
|
|
192
194
|
before do
|
|
193
|
-
response.stub(:
|
|
195
|
+
response.stub(code: 500)
|
|
194
196
|
end
|
|
195
197
|
|
|
196
198
|
it 'marks the notification as failed because no successful delivery was made' do
|
|
197
|
-
|
|
199
|
+
error = Rpush::DeliveryError.new(nil, notification.id, 'Failed to deliver to all recipients.')
|
|
200
|
+
delivery.should_receive(:mark_failed).with(error)
|
|
198
201
|
expect { perform }.to raise_error(Rpush::DeliveryError)
|
|
199
202
|
end
|
|
200
203
|
|
|
@@ -206,7 +209,7 @@ describe Rpush::Daemon::Adm::Delivery do
|
|
|
206
209
|
|
|
207
210
|
describe 'a 503 (Service Unavailable) response' do
|
|
208
211
|
before do
|
|
209
|
-
response.stub(:
|
|
212
|
+
response.stub(code: 503, header: { 'retry-after' => 10 })
|
|
210
213
|
end
|
|
211
214
|
|
|
212
215
|
it 'should retry the notification respecting the Retry-After header' do
|
|
@@ -216,19 +219,19 @@ describe Rpush::Daemon::Adm::Delivery do
|
|
|
216
219
|
end
|
|
217
220
|
|
|
218
221
|
describe 'some registration ids succeeding and some failing' do
|
|
219
|
-
let(:http) { double(:
|
|
220
|
-
let(:notification) { Rpush::Adm::Notification.create!(:
|
|
221
|
-
let(:bad_request_response) { double(:
|
|
222
|
+
let(:http) { double(shutdown: nil) }
|
|
223
|
+
let(:notification) { Rpush::Adm::Notification.create!(app: app, registration_ids: %w(abc xyz), deliver_after: Time.now, collapse_key: 'sync', data: { 'message' => 'test' }) }
|
|
224
|
+
let(:bad_request_response) { double(code: 400, body: JSON.dump('reason' => 'InvalidData')) }
|
|
222
225
|
|
|
223
226
|
it 'should keep sent reg ids in original notification and create new notification with remaining reg ids for retry' do
|
|
224
|
-
response.stub(:
|
|
227
|
+
response.stub(code: 200, body: JSON.dump('registrationID' => 'abc'))
|
|
225
228
|
|
|
226
229
|
# first request to deliver message succeeds
|
|
227
|
-
adm_uri = URI.parse(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL
|
|
230
|
+
adm_uri = URI.parse(format(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL, 'abc'))
|
|
228
231
|
http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(response)
|
|
229
232
|
|
|
230
233
|
# first request to deliver message that returns too many request response
|
|
231
|
-
adm_uri = URI.parse(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL
|
|
234
|
+
adm_uri = URI.parse(format(Rpush::Daemon::Adm::Delivery::AMAZON_ADM_URL, 'xyz'))
|
|
232
235
|
http.should_receive(:request).with(adm_uri, instance_of(Net::HTTP::Post)).and_return(bad_request_response)
|
|
233
236
|
|
|
234
237
|
store.should_receive(:update_notification).with do |notif|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
require 'unit_spec_helper'
|
|
2
2
|
|
|
3
|
-
describe Rpush::
|
|
4
|
-
let(:app) { double(:
|
|
5
|
-
let(:error) { Rpush::
|
|
3
|
+
describe Rpush::CertificateExpiredError do
|
|
4
|
+
let(:app) { double(name: 'test') }
|
|
5
|
+
let(:error) { Rpush::CertificateExpiredError.new(app, Time.now) }
|
|
6
6
|
|
|
7
7
|
it 'returns a message' do
|
|
8
8
|
error.message
|
|
@@ -1,101 +1,108 @@
|
|
|
1
1
|
require 'unit_spec_helper'
|
|
2
2
|
|
|
3
3
|
describe Rpush::Daemon::Apns::Delivery do
|
|
4
|
-
let(:app) { double(:
|
|
5
|
-
let(:
|
|
6
|
-
let(:
|
|
7
|
-
let(:
|
|
8
|
-
let(:
|
|
9
|
-
let(:connection) { double(:
|
|
10
|
-
let(:delivery) { Rpush::Daemon::Apns::Delivery.new(app, connection,
|
|
11
|
-
|
|
12
|
-
def perform
|
|
13
|
-
begin
|
|
14
|
-
delivery.perform
|
|
15
|
-
rescue Rpush::DeliveryError, Rpush::Apns::DisconnectionError
|
|
16
|
-
end
|
|
17
|
-
end
|
|
4
|
+
let(:app) { double(name: 'MyApp') }
|
|
5
|
+
let(:notification1) { double.as_null_object }
|
|
6
|
+
let(:notification2) { double.as_null_object }
|
|
7
|
+
let(:batch) { double(mark_all_failed: nil, mark_all_delivered: nil, all_processed: nil) }
|
|
8
|
+
let(:logger) { double(error: nil, info: nil) }
|
|
9
|
+
let(:connection) { double(select: false, write: nil, reconnect: nil, close: nil, connect: nil) }
|
|
10
|
+
let(:delivery) { Rpush::Daemon::Apns::Delivery.new(app, connection, batch) }
|
|
18
11
|
|
|
19
12
|
before do
|
|
20
|
-
|
|
13
|
+
batch.stub(:each_notification) do |&blk|
|
|
14
|
+
[notification1, notification2].each(&blk)
|
|
15
|
+
end
|
|
16
|
+
Rpush.stub(logger: logger)
|
|
21
17
|
end
|
|
22
18
|
|
|
23
|
-
it
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
it 'writes the binary batch' do
|
|
20
|
+
notification1.stub(to_binary: 'binary1')
|
|
21
|
+
notification2.stub(to_binary: 'binary2')
|
|
22
|
+
connection.should_receive(:write).with('binary1binary2')
|
|
23
|
+
delivery.perform
|
|
27
24
|
end
|
|
28
25
|
|
|
29
|
-
it
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
it 'logs the notification deliveries' do
|
|
27
|
+
notification1.stub(id: 666, device_token: 'abc123')
|
|
28
|
+
notification2.stub(id: 42, device_token: 'abc456')
|
|
29
|
+
logger.should_receive(:info).with('[MyApp] 666 sent to abc123')
|
|
30
|
+
logger.should_receive(:info).with('[MyApp] 42 sent to abc456')
|
|
31
|
+
delivery.perform
|
|
33
32
|
end
|
|
34
33
|
|
|
35
|
-
it
|
|
36
|
-
delivery.should_receive(:
|
|
37
|
-
perform
|
|
34
|
+
it 'marks all notifications as delivered' do
|
|
35
|
+
delivery.should_receive(:mark_batch_delivered)
|
|
36
|
+
delivery.perform
|
|
38
37
|
end
|
|
39
38
|
|
|
40
|
-
it '
|
|
41
|
-
|
|
42
|
-
delivery.
|
|
43
|
-
perform
|
|
39
|
+
it 'notifies the batch all notifications have been processed' do
|
|
40
|
+
batch.should_receive(:all_processed)
|
|
41
|
+
delivery.perform
|
|
44
42
|
end
|
|
45
43
|
|
|
46
|
-
describe
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
delivery.should_receive(:
|
|
51
|
-
perform
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
it "logs the delivery error" do
|
|
55
|
-
# checking for the doublebed error doesn't work in jruby, but checking
|
|
56
|
-
# for the exception by class does.
|
|
57
|
-
|
|
58
|
-
#error = Rpush::DeliveryError.new(4, 12, "Missing payload")
|
|
59
|
-
#Rpush::DeliveryError.stub(:new => error)
|
|
60
|
-
#expect { delivery.perform }.to raise_error(error)
|
|
61
|
-
|
|
62
|
-
expect { delivery.perform }.to raise_error(Rpush::DeliveryError)
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
it "reads 6 bytes from the socket" do
|
|
66
|
-
connection.should_receive(:read).with(6).and_return(nil)
|
|
67
|
-
perform
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
it "does not attempt to read from the socket if the socket was not selected for reading after the timeout" do
|
|
71
|
-
connection.stub(:select => nil)
|
|
72
|
-
connection.should_not_receive(:read)
|
|
73
|
-
perform
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
it "reconnects the socket" do
|
|
77
|
-
connection.should_receive(:reconnect)
|
|
78
|
-
perform
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
it "logs that the connection is being reconnected" do
|
|
82
|
-
Rpush.logger.should_receive(:error).with("[MyApp] Error received, reconnecting...")
|
|
83
|
-
perform
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
context "when the APNs disconnects without returning an error" do
|
|
87
|
-
before do
|
|
88
|
-
connection.stub(:read => nil)
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
it 'raises a DisconnectError error if the connection is closed without an error being returned' do
|
|
92
|
-
expect { delivery.perform }.to raise_error(Rpush::Apns::DisconnectionError)
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
it 'marks the notification as failed' do
|
|
96
|
-
delivery.should_receive(:mark_failed).with(nil, "APNs disconnected without returning an error.")
|
|
97
|
-
perform
|
|
98
|
-
end
|
|
44
|
+
describe 'when an error is raised' do
|
|
45
|
+
it 'marks all notifications as failed' do
|
|
46
|
+
error = StandardError.new
|
|
47
|
+
connection.stub(:write).and_raise(error)
|
|
48
|
+
delivery.should_receive(:mark_batch_failed).with(error)
|
|
49
|
+
expect { delivery.perform }.to raise_error(error)
|
|
99
50
|
end
|
|
100
51
|
end
|
|
52
|
+
|
|
53
|
+
# describe "when delivery fails" do
|
|
54
|
+
# before { connection.stub(select: true, read: [8, 4, 69].pack("ccN")) }
|
|
55
|
+
#
|
|
56
|
+
# it "marks the notification as failed" do
|
|
57
|
+
# delivery.should_receive(:mark_failed).with(4, "Unable to deliver notification 69, received error 4 (Missing payload)")
|
|
58
|
+
# perform
|
|
59
|
+
# end
|
|
60
|
+
#
|
|
61
|
+
# it "logs the delivery error" do
|
|
62
|
+
# # checking for the doublebed error doesn't work in jruby, but checking
|
|
63
|
+
# # for the exception by class does.
|
|
64
|
+
#
|
|
65
|
+
# # error = Rpush::DeliveryError.new(4, 12, "Missing payload")
|
|
66
|
+
# # Rpush::DeliveryError.stub(new: error)
|
|
67
|
+
# # expect { delivery.perform }.to raise_error(error)
|
|
68
|
+
#
|
|
69
|
+
# expect { delivery.perform }.to raise_error(Rpush::DeliveryError)
|
|
70
|
+
# end
|
|
71
|
+
#
|
|
72
|
+
# it "reads 6 bytes from the socket" do
|
|
73
|
+
# connection.should_receive(:read).with(6).and_return(nil)
|
|
74
|
+
# perform
|
|
75
|
+
# end
|
|
76
|
+
#
|
|
77
|
+
# it "does not attempt to read from the socket if the socket was not selected for reading after the timeout" do
|
|
78
|
+
# connection.stub(select: nil)
|
|
79
|
+
# connection.should_not_receive(:read)
|
|
80
|
+
# perform
|
|
81
|
+
# end
|
|
82
|
+
#
|
|
83
|
+
# it "reconnects the socket" do
|
|
84
|
+
# connection.should_receive(:reconnect)
|
|
85
|
+
# perform
|
|
86
|
+
# end
|
|
87
|
+
#
|
|
88
|
+
# it "logs that the connection is being reconnected" do
|
|
89
|
+
# Rpush.logger.should_receive(:error).with("[MyApp] Error received, reconnecting...")
|
|
90
|
+
# perform
|
|
91
|
+
# end
|
|
92
|
+
#
|
|
93
|
+
# context "when the APNs disconnects without returning an error" do
|
|
94
|
+
# before do
|
|
95
|
+
# connection.stub(read: nil)
|
|
96
|
+
# end
|
|
97
|
+
#
|
|
98
|
+
# it 'raises a DisconnectError error if the connection is closed without an error being returned' do
|
|
99
|
+
# expect { delivery.perform }.to raise_error(Rpush::DisconnectionError)
|
|
100
|
+
# end
|
|
101
|
+
#
|
|
102
|
+
# it 'marks the notification as failed' do
|
|
103
|
+
# delivery.should_receive(:mark_failed).with(nil, "The APNs disconnected without returning an error. This may indicate you are using an invalid certificate for the host.")
|
|
104
|
+
# perform
|
|
105
|
+
# end
|
|
106
|
+
# end
|
|
107
|
+
# end
|
|
101
108
|
end
|