rpush 4.2.0 → 5.4.0
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 +248 -163
- data/README.md +103 -17
- data/lib/generators/templates/add_gcm.rb +4 -4
- data/lib/generators/templates/add_rpush.rb +4 -4
- data/lib/generators/templates/rpush.rb +4 -0
- data/lib/generators/templates/rpush_3_3_1_updates.rb +2 -2
- data/lib/rpush/cli.rb +1 -1
- data/lib/rpush/client/active_model.rb +4 -1
- data/lib/rpush/client/active_model/adm/data_validator.rb +1 -1
- data/lib/rpush/client/active_model/apns/device_token_format_validator.rb +2 -2
- data/lib/rpush/client/active_model/apns/notification.rb +9 -1
- data/lib/rpush/client/active_model/apns/notification_payload_size_validator.rb +15 -0
- data/lib/rpush/client/active_model/apns2/notification.rb +14 -0
- data/lib/rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +1 -1
- data/lib/rpush/client/active_model/gcm/notification.rb +2 -2
- data/lib/rpush/client/active_model/payload_data_size_validator.rb +1 -1
- data/lib/rpush/client/active_model/registration_ids_count_validator.rb +1 -1
- data/lib/rpush/client/active_model/webpush/app.rb +41 -0
- data/lib/rpush/client/active_model/webpush/notification.rb +66 -0
- data/lib/rpush/client/active_record.rb +4 -0
- data/lib/rpush/client/active_record/apns/active_record_serializable_notification.rb +65 -0
- data/lib/rpush/client/active_record/apns/notification.rb +1 -57
- data/lib/rpush/client/active_record/apns2/notification.rb +4 -1
- data/lib/rpush/client/active_record/apnsp8/notification.rb +1 -0
- data/lib/rpush/client/active_record/webpush/app.rb +11 -0
- data/lib/rpush/client/active_record/webpush/notification.rb +12 -0
- data/lib/rpush/client/redis.rb +3 -0
- data/lib/rpush/client/redis/apns2/notification.rb +1 -0
- data/lib/rpush/client/redis/apnsp8/notification.rb +2 -0
- data/lib/rpush/client/redis/pushy/notification.rb +0 -1
- data/lib/rpush/client/redis/webpush/app.rb +15 -0
- data/lib/rpush/client/redis/webpush/notification.rb +15 -0
- data/lib/rpush/configuration.rb +3 -2
- data/lib/rpush/daemon.rb +4 -1
- data/lib/rpush/daemon/apns/feedback_receiver.rb +1 -1
- data/lib/rpush/daemon/apns2/delivery.rb +13 -2
- data/lib/rpush/daemon/apnsp8/delivery.rb +7 -2
- data/lib/rpush/daemon/app_runner.rb +1 -1
- data/lib/rpush/daemon/batch.rb +12 -5
- data/lib/rpush/daemon/delivery.rb +1 -2
- data/lib/rpush/daemon/store/active_record/reconnectable.rb +1 -1
- data/lib/rpush/daemon/webpush.rb +10 -0
- data/lib/rpush/daemon/webpush/delivery.rb +114 -0
- data/lib/rpush/logger.rb +1 -0
- data/lib/rpush/version.rb +2 -2
- data/spec/functional/apns2_spec.rb +97 -2
- data/spec/functional/gcm_priority_spec.rb +40 -0
- data/spec/functional/webpush_spec.rb +30 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/simplecov_helper.rb +1 -1
- data/spec/unit/client/active_record/adm/app_spec.rb +2 -54
- data/spec/unit/client/active_record/adm/notification_spec.rb +2 -39
- data/spec/unit/client/active_record/apns/app_spec.rb +3 -26
- data/spec/unit/client/active_record/apns/feedback_spec.rb +1 -5
- data/spec/unit/client/active_record/apns/notification_spec.rb +29 -293
- data/spec/unit/client/active_record/apns2/app_spec.rb +4 -0
- data/spec/unit/client/active_record/apns2/notification_spec.rb +65 -0
- data/spec/unit/client/active_record/apnsp8/notification_spec.rb +28 -0
- data/spec/unit/client/active_record/app_spec.rb +1 -26
- data/spec/unit/client/active_record/gcm/app_spec.rb +3 -1
- data/spec/unit/client/active_record/gcm/notification_spec.rb +6 -88
- data/spec/unit/client/active_record/notification_spec.rb +3 -11
- data/spec/unit/client/active_record/pushy/app_spec.rb +2 -13
- data/spec/unit/client/active_record/pushy/notification_spec.rb +2 -55
- data/spec/unit/client/active_record/shared/app.rb +14 -0
- data/spec/unit/{notification_shared.rb → client/active_record/shared/notification.rb} +12 -7
- data/spec/unit/client/active_record/webpush/app_spec.rb +6 -0
- data/spec/unit/client/active_record/webpush/notification_spec.rb +6 -0
- data/spec/unit/client/active_record/wns/badge_notification_spec.rb +1 -11
- data/spec/unit/client/active_record/wns/raw_notification_spec.rb +3 -12
- data/spec/unit/client/active_record/wpns/app_spec.rb +3 -1
- data/spec/unit/client/active_record/wpns/notification_spec.rb +2 -17
- data/spec/unit/client/redis/adm/app_spec.rb +5 -0
- data/spec/unit/client/redis/adm/notification_spec.rb +5 -0
- data/spec/unit/client/redis/apns/app_spec.rb +5 -0
- data/spec/unit/client/redis/apns/feedback_spec.rb +5 -0
- data/spec/unit/client/redis/apns/notification_spec.rb +50 -0
- data/spec/unit/client/redis/apns2/app_spec.rb +4 -0
- data/spec/unit/client/redis/apns2/notification_spec.rb +50 -0
- data/spec/unit/client/redis/apnsp8/notification_spec.rb +29 -0
- data/spec/unit/client/redis/app_spec.rb +5 -0
- data/spec/unit/client/redis/gcm/app_spec.rb +5 -0
- data/spec/unit/client/redis/gcm/notification_spec.rb +5 -0
- data/spec/unit/client/redis/notification_spec.rb +5 -0
- data/spec/unit/client/redis/pushy/app_spec.rb +5 -0
- data/spec/unit/client/redis/pushy/notification_spec.rb +5 -0
- data/spec/unit/client/redis/webpush/app_spec.rb +5 -0
- data/spec/unit/client/redis/webpush/notification_spec.rb +5 -0
- data/spec/unit/client/redis/wns/badge_notification_spec.rb +5 -0
- data/spec/unit/client/redis/wns/raw_notification_spec.rb +22 -0
- data/spec/unit/client/redis/wpns/app_spec.rb +5 -0
- data/spec/unit/client/redis/wpns/notification_spec.rb +5 -0
- data/spec/unit/client/shared/adm/app.rb +51 -0
- data/spec/unit/client/shared/adm/notification.rb +39 -0
- data/spec/unit/client/shared/apns/app.rb +29 -0
- data/spec/unit/client/shared/apns/feedback.rb +9 -0
- data/spec/unit/client/shared/apns/notification.rb +262 -0
- data/spec/unit/client/shared/app.rb +17 -0
- data/spec/unit/client/shared/gcm/app.rb +4 -0
- data/spec/unit/client/shared/gcm/notification.rb +77 -0
- data/spec/unit/client/shared/notification.rb +10 -0
- data/spec/unit/client/shared/pushy/app.rb +17 -0
- data/spec/unit/client/shared/pushy/notification.rb +55 -0
- data/spec/unit/client/shared/webpush/app.rb +33 -0
- data/spec/unit/client/shared/webpush/notification.rb +83 -0
- data/spec/unit/client/shared/wns/badge_notification.rb +15 -0
- data/spec/unit/client/shared/wns/raw_notification.rb +21 -0
- data/spec/unit/client/shared/wpns/app.rb +4 -0
- data/spec/unit/client/shared/wpns/notification.rb +18 -0
- data/spec/unit/daemon/batch_spec.rb +50 -2
- data/spec/unit/daemon/delivery_spec.rb +10 -0
- data/spec/unit/daemon/pushy/delivery_spec.rb +5 -3
- data/spec/unit/daemon/shared/store.rb +312 -0
- data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +7 -7
- data/spec/unit/daemon/store/active_record_spec.rb +2 -290
- data/spec/unit/daemon/store/redis_spec.rb +2 -291
- data/spec/unit/daemon/webpush/delivery_spec.rb +144 -0
- data/spec/unit_spec_helper.rb +3 -0
- metadata +135 -12
- data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +0 -16
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'unit_spec_helper'
|
|
2
|
+
|
|
3
|
+
shared_examples 'Rpush::Client::Webpush::App' do
|
|
4
|
+
describe 'validates' do
|
|
5
|
+
subject { described_class.new }
|
|
6
|
+
|
|
7
|
+
it 'validates presence of name' do
|
|
8
|
+
is_expected.not_to be_valid
|
|
9
|
+
expect(subject.errors[:name]).to eq ["can't be blank"]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'validates presence of vapid_keypair' do
|
|
13
|
+
is_expected.not_to be_valid
|
|
14
|
+
expect(subject.errors[:vapid_keypair]).to eq ["can't be blank"]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'should require the vapid keypair to have subject, public and private key' do
|
|
18
|
+
subject.vapid_keypair = {}.to_json
|
|
19
|
+
is_expected.not_to be_valid
|
|
20
|
+
expect(subject.errors[:vapid_keypair].sort).to eq [
|
|
21
|
+
'must have a private_key entry',
|
|
22
|
+
'must have a public_key entry',
|
|
23
|
+
'must have a subject entry',
|
|
24
|
+
]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'should require valid json for the keypair' do
|
|
28
|
+
subject.vapid_keypair = 'invalid'
|
|
29
|
+
is_expected.not_to be_valid
|
|
30
|
+
expect(subject.errors[:vapid_keypair].sort).to eq [ 'must be valid JSON' ]
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require 'unit_spec_helper'
|
|
2
|
+
|
|
3
|
+
shared_examples 'Rpush::Client::Webpush::Notification' do
|
|
4
|
+
subject(:notification) { described_class.new }
|
|
5
|
+
|
|
6
|
+
describe 'notification attributes' do
|
|
7
|
+
describe 'data' do
|
|
8
|
+
subject { described_class.new(data: { message: 'test', urgency: 'normal' } ) }
|
|
9
|
+
it 'has a message' do
|
|
10
|
+
expect(subject.message).to eq "test"
|
|
11
|
+
end
|
|
12
|
+
it 'has an urgency' do
|
|
13
|
+
expect(subject.urgency).to eq "normal"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
describe 'subscription' do
|
|
18
|
+
let(:subscription){ { endpoint: 'https://push.example.org/foo', keys: {'foo' => 'bar'}} }
|
|
19
|
+
subject { described_class.new(registration_ids: [subscription]) }
|
|
20
|
+
|
|
21
|
+
it "has a subscription" do
|
|
22
|
+
expect(subject.subscription).to eq({ endpoint: 'https://push.example.org/foo', keys: {foo: 'bar'} })
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
describe 'validates' do
|
|
29
|
+
let(:app) { Rpush::Webpush::App.create!(name: 'MyApp', vapid_keypair: VAPID_KEYPAIR) }
|
|
30
|
+
|
|
31
|
+
describe 'data' do
|
|
32
|
+
subject { described_class.new(app: app, registration_ids: [{endpoint: 'https://push.example.org/foo', keys: {'foo' => 'bar'}}]) }
|
|
33
|
+
it 'validates presence' do
|
|
34
|
+
is_expected.not_to be_valid
|
|
35
|
+
expect(subject.errors[:data]).to eq ["can't be blank"]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "has a 'data' payload limit of 4096 bytes" do
|
|
39
|
+
subject.data = { message: 'a' * 4096 }
|
|
40
|
+
is_expected.not_to be_valid
|
|
41
|
+
expected_errors = ["Notification payload data cannot be larger than 4096 bytes."]
|
|
42
|
+
expect(subject.errors[:base]).to eq expected_errors
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe 'registration_ids' do
|
|
47
|
+
subject { described_class.new(app: app, data: { message: 'test' }) }
|
|
48
|
+
it 'validates presence' do
|
|
49
|
+
is_expected.not_to be_valid
|
|
50
|
+
expect(subject.errors[:registration_ids]).to eq ["can't be blank"]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'limits the number of registration ids to exactly 1' do
|
|
54
|
+
subject.registration_ids = [{endpoint: 'string', keys: { 'a' => 'hash' }}] * 2
|
|
55
|
+
is_expected.not_to be_valid
|
|
56
|
+
expected_errors = ["Number of registration_ids cannot be larger than 1."]
|
|
57
|
+
expect(subject.errors[:base]).to eq expected_errors
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it 'validates the structure of the registration' do
|
|
61
|
+
subject.registration_ids = ['a']
|
|
62
|
+
is_expected.not_to be_valid
|
|
63
|
+
expect(subject.errors[:base]).to eq [
|
|
64
|
+
"Registration must have :endpoint (String) and :keys (Hash) keys"
|
|
65
|
+
]
|
|
66
|
+
|
|
67
|
+
subject.registration_ids = [{endpoint: 'string', keys: { 'a' => 'hash' }}]
|
|
68
|
+
is_expected.to be_valid
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe 'time_to_live' do
|
|
73
|
+
subject { described_class.new(app: app, data: { message: 'test' }, registration_ids: [{endpoint: 'https://push.example.org/foo', keys: {'foo' => 'bar'}}]) }
|
|
74
|
+
|
|
75
|
+
it 'should be > 0' do
|
|
76
|
+
subject.time_to_live = -1
|
|
77
|
+
is_expected.not_to be_valid
|
|
78
|
+
expect(subject.errors[:time_to_live]).to eq ['must be greater than 0']
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
require 'unit_spec_helper'
|
|
2
|
+
|
|
3
|
+
shared_examples 'Rpush::Client::Wns::BadgeNotification' do
|
|
4
|
+
let(:notification) do
|
|
5
|
+
notif = described_class.new
|
|
6
|
+
notif.app = Rpush::Wns::App.create!(name: "MyApp", client_id: "someclient", client_secret: "somesecret")
|
|
7
|
+
notif.uri = 'https://db5.notify.windows.com/?token=TOKEN'
|
|
8
|
+
notif.badge = 42
|
|
9
|
+
notif
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'should allow a notification without data' do
|
|
13
|
+
expect(notification.valid?).to be(true)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'unit_spec_helper'
|
|
2
|
+
|
|
3
|
+
shared_examples 'Rpush::Client::Wns::RawNotification' do
|
|
4
|
+
let(:notification) do
|
|
5
|
+
notif = described_class.new
|
|
6
|
+
notif.app = Rpush::Wns::App.create!(name: "MyApp", client_id: "someclient", client_secret: "somesecret")
|
|
7
|
+
notif.uri = 'https://db5.notify.windows.com/?token=TOKEN'
|
|
8
|
+
notif.data = { foo: 'foo', bar: 'bar' }
|
|
9
|
+
notif
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'allows exact payload of 5 KB' do
|
|
13
|
+
allow(notification).to receive(:payload_data_size) { 5120 }
|
|
14
|
+
expect(notification.valid?).to be(true)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'allows the size of payload under 5 KB' do
|
|
18
|
+
allow(notification).to receive(:payload_data_size) { 5119 }
|
|
19
|
+
expect(notification.valid?).to be(true)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'unit_spec_helper'
|
|
2
|
+
|
|
3
|
+
shared_examples 'Rpush::Client::Wpns::Notification' do
|
|
4
|
+
let(:app) { Rpush::Wpns::App.create!(name: 'test', auth_key: 'abc') }
|
|
5
|
+
let(:notification) { described_class.new }
|
|
6
|
+
|
|
7
|
+
it "should have an url in the uri parameter" do
|
|
8
|
+
notification = described_class.new(uri: "somthing")
|
|
9
|
+
notification.valid?
|
|
10
|
+
expect(notification.errors[:uri]).to include('is invalid')
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "should be invalid if there's no data" do
|
|
14
|
+
notification = described_class.new(data: {})
|
|
15
|
+
notification.valid?
|
|
16
|
+
expect(notification.errors[:data]).to include("can't be blank")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
require 'unit_spec_helper'
|
|
2
2
|
|
|
3
3
|
describe Rpush::Daemon::Batch do
|
|
4
|
-
let(:notification1) { double(:notification1, id: 1) }
|
|
5
|
-
let(:notification2) { double(:notification2, id: 2) }
|
|
4
|
+
let(:notification1) { double(:notification1, id: 1, delivered: false, failed: false) }
|
|
5
|
+
let(:notification2) { double(:notification2, id: 2, delivered: false, failed: false) }
|
|
6
6
|
let(:batch) { Rpush::Daemon::Batch.new([notification1, notification2]) }
|
|
7
7
|
let(:store) { double.as_null_object }
|
|
8
8
|
let(:time) { Time.now }
|
|
@@ -50,6 +50,54 @@ describe Rpush::Daemon::Batch do
|
|
|
50
50
|
end
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
describe 'mark_all_retryable' do
|
|
54
|
+
let(:error) { StandardError.new('Exception') }
|
|
55
|
+
|
|
56
|
+
it 'marks all notifications as retryable without persisting' do
|
|
57
|
+
expect(store).to receive(:mark_retryable).ordered.with(notification1, time, persist: false)
|
|
58
|
+
expect(store).to receive(:mark_retryable).ordered.with(notification2, time, persist: false)
|
|
59
|
+
|
|
60
|
+
batch.mark_all_retryable(time, error)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it 'defers persisting' do
|
|
64
|
+
batch.mark_all_retryable(time, error)
|
|
65
|
+
expect(batch.retryable).to eq(time => [notification1, notification2])
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
context 'when one of the notifications delivered' do
|
|
69
|
+
let(:notification2) { double(:notification2, id: 2, delivered: true, failed: false) }
|
|
70
|
+
|
|
71
|
+
it 'marks all only pending notification as retryable without persisting' do
|
|
72
|
+
expect(store).to receive(:mark_retryable).ordered.with(notification1, time, persist: false)
|
|
73
|
+
expect(store).not_to receive(:mark_retryable).ordered.with(notification2, time, persist: false)
|
|
74
|
+
|
|
75
|
+
batch.mark_all_retryable(time, error)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it 'defers persisting' do
|
|
79
|
+
batch.mark_all_retryable(time, error)
|
|
80
|
+
expect(batch.retryable).to eq(time => [notification1])
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
context 'when one of the notifications failed' do
|
|
85
|
+
let(:notification2) { double(:notification2, id: 2, delivered: false, failed: true) }
|
|
86
|
+
|
|
87
|
+
it 'marks all only pending notification as retryable without persisting' do
|
|
88
|
+
expect(store).to receive(:mark_retryable).ordered.with(notification1, time, persist: false)
|
|
89
|
+
expect(store).not_to receive(:mark_retryable).ordered.with(notification2, time, persist: false)
|
|
90
|
+
|
|
91
|
+
batch.mark_all_retryable(time, error)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'defers persisting' do
|
|
95
|
+
batch.mark_all_retryable(time, error)
|
|
96
|
+
expect(batch.retryable).to eq(time => [notification1])
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
53
101
|
describe 'mark_failed' do
|
|
54
102
|
it 'marks the notification as failed without persisting' do
|
|
55
103
|
expect(store).to receive(:mark_failed).with(notification1, 1, 'an error', time, persist: false)
|
|
@@ -41,6 +41,16 @@ describe Rpush::Daemon::Delivery do
|
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
describe 'mark_batch_retryable' do
|
|
45
|
+
let(:batch) { double(Rpush::Daemon::Batch) }
|
|
46
|
+
let(:error) { StandardError.new('Exception') }
|
|
47
|
+
|
|
48
|
+
it 'marks all notifications as retryable' do
|
|
49
|
+
expect(batch).to receive(:mark_all_retryable)
|
|
50
|
+
delivery.mark_batch_retryable(Time.now + 1.hour, error)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
44
54
|
describe 'mark_batch_failed' do
|
|
45
55
|
it 'marks all notifications as delivered' do
|
|
46
56
|
error = Rpush::DeliveryError.new(1, 42, 'an error')
|
|
@@ -61,10 +61,12 @@ describe Rpush::Daemon::Pushy::Delivery do
|
|
|
61
61
|
it_behaves_like 'process notification'
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
shared_examples 'retry delivery' do |
|
|
65
|
-
let(:response_code) { response_code }
|
|
64
|
+
shared_examples 'retry delivery' do |options|
|
|
65
|
+
let(:response_code) { options[:response_code] }
|
|
66
|
+
|
|
67
|
+
shared_examples 'logs' do |log_options|
|
|
68
|
+
let(:deliver_after) { log_options[:deliver_after] }
|
|
66
69
|
|
|
67
|
-
shared_examples 'logs' do |deliver_after:|
|
|
68
70
|
let(:expected_log_message) do
|
|
69
71
|
"Pushy responded with a #{response_code} error. Notification #{notification.id} " \
|
|
70
72
|
"will be retried after #{deliver_after} (retry 1)."
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
require 'unit_spec_helper'
|
|
2
|
+
|
|
3
|
+
shared_examples 'Rpush::Daemon::Store' do
|
|
4
|
+
subject(:store) { described_class.new }
|
|
5
|
+
|
|
6
|
+
let(:app) { Rpush::Apns::App.create!(name: 'my_app', environment: 'development', certificate: TEST_CERT) }
|
|
7
|
+
let(:notification) { Rpush::Apns::Notification.create!(device_token: "a" * 64, app: app) }
|
|
8
|
+
let(:time) { Time.parse('2019/06/06 02:45').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
|
+
end
|
|
14
|
+
|
|
15
|
+
before(:each) do
|
|
16
|
+
Timecop.freeze(time)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
after do
|
|
20
|
+
Timecop.return
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'updates an notification' do
|
|
24
|
+
expect(notification).to receive(:save!)
|
|
25
|
+
store.update_notification(notification)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'updates an app' do
|
|
29
|
+
expect(app).to receive(:save!)
|
|
30
|
+
store.update_app(app)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'finds an app by ID' do
|
|
34
|
+
expect(store.app(app.id)).to eq(app)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'finds all apps' do
|
|
38
|
+
app
|
|
39
|
+
expect(store.all_apps).to eq([app])
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it 'translates an Integer notification ID' do
|
|
43
|
+
expect(store.translate_integer_notification_id(notification.id)).to eq(notification.id)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'returns the pending notification count' do
|
|
47
|
+
notification
|
|
48
|
+
expect(store.pending_delivery_count).to eq(1)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
describe 'mark_retryable' do
|
|
52
|
+
it 'increments the retry count' do
|
|
53
|
+
expect do
|
|
54
|
+
store.mark_retryable(notification, time)
|
|
55
|
+
end.to change(notification, :retries).by(1)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'sets the deliver after timestamp' do
|
|
59
|
+
deliver_after = (time + 10.seconds)
|
|
60
|
+
expect do
|
|
61
|
+
store.mark_retryable(notification, deliver_after)
|
|
62
|
+
end.to change(notification, :deliver_after).to(deliver_after)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it 'saves the notification without validation' do
|
|
66
|
+
expect(notification).to receive(:save!).with(validate: false)
|
|
67
|
+
store.mark_retryable(notification, time)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it 'does not save the notification if persist: false' do
|
|
71
|
+
expect(notification).not_to receive(:save!)
|
|
72
|
+
store.mark_retryable(notification, time, persist: false)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
describe 'mark_batch_retryable' do
|
|
77
|
+
let(:deliver_after) { time + 10.seconds }
|
|
78
|
+
|
|
79
|
+
it 'sets the attributes on the object for use in reflections' do
|
|
80
|
+
store.mark_batch_retryable([notification], deliver_after)
|
|
81
|
+
expect(notification.deliver_after.to_s).to eq deliver_after.to_s
|
|
82
|
+
expect(notification.retries).to eq 1
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it 'increments the retired count' do
|
|
86
|
+
expect do
|
|
87
|
+
store.mark_batch_retryable([notification], deliver_after)
|
|
88
|
+
notification.reload
|
|
89
|
+
end.to change(notification, :retries).by(1)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it 'sets the deliver after timestamp' do
|
|
93
|
+
expect do
|
|
94
|
+
store.mark_batch_retryable([notification], deliver_after)
|
|
95
|
+
notification.reload
|
|
96
|
+
end.to change { notification.deliver_after.try(:utc).to_s }.to(deliver_after.utc.to_s)
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
describe 'mark_delivered' do
|
|
101
|
+
it 'marks the notification as delivered' do
|
|
102
|
+
expect do
|
|
103
|
+
store.mark_delivered(notification, time)
|
|
104
|
+
end.to change(notification, :delivered).to(true)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it 'sets the time the notification was delivered' do
|
|
108
|
+
expect do
|
|
109
|
+
store.mark_delivered(notification, time)
|
|
110
|
+
notification.reload
|
|
111
|
+
end.to change { notification.delivered_at.try(:utc).to_s }.to(time.to_s)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it 'saves the notification without validation' do
|
|
115
|
+
expect(notification).to receive(:save!).with(validate: false)
|
|
116
|
+
store.mark_delivered(notification, time)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it 'does not save the notification if persist: false' do
|
|
120
|
+
expect(notification).not_to receive(:save!)
|
|
121
|
+
store.mark_delivered(notification, time, persist: false)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
describe 'mark_batch_delivered' do
|
|
126
|
+
it 'sets the attributes on the object for use in reflections' do
|
|
127
|
+
store.mark_batch_delivered([notification])
|
|
128
|
+
expect(notification.delivered_at.to_s).to eq time.to_s
|
|
129
|
+
expect(notification.delivered).to be_truthy
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it 'marks the notifications as delivered' do
|
|
133
|
+
expect do
|
|
134
|
+
store.mark_batch_delivered([notification])
|
|
135
|
+
notification.reload
|
|
136
|
+
end.to change(notification, :delivered).to(true)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it 'sets the time the notifications were delivered' do
|
|
140
|
+
expect do
|
|
141
|
+
store.mark_batch_delivered([notification])
|
|
142
|
+
notification.reload
|
|
143
|
+
end.to change { notification.delivered_at.try(:utc)&.to_s }.to(time.to_s)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
describe 'mark_failed' do
|
|
148
|
+
it 'marks the notification as not delivered' do
|
|
149
|
+
store.mark_failed(notification, nil, '', time)
|
|
150
|
+
expect(notification.delivered).to eq(false)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it 'marks the notification as failed' do
|
|
154
|
+
expect do
|
|
155
|
+
store.mark_failed(notification, nil, '', time)
|
|
156
|
+
notification.reload
|
|
157
|
+
end.to change(notification, :failed).to(true)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
it 'sets the time the notification delivery failed' do
|
|
161
|
+
expect do
|
|
162
|
+
store.mark_failed(notification, nil, '', time)
|
|
163
|
+
notification.reload
|
|
164
|
+
end.to change { notification.failed_at.try(:utc).to_s }.to(time.to_s)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
it 'sets the error code' do
|
|
168
|
+
expect do
|
|
169
|
+
store.mark_failed(notification, 42, '', time)
|
|
170
|
+
end.to change(notification, :error_code).to(42)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
it 'sets the error description' do
|
|
174
|
+
expect do
|
|
175
|
+
store.mark_failed(notification, 42, 'Weeee', time)
|
|
176
|
+
end.to change(notification, :error_description).to('Weeee')
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
it 'saves the notification without validation' do
|
|
180
|
+
expect(notification).to receive(:save!).with(validate: false)
|
|
181
|
+
store.mark_failed(notification, nil, '', time)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it 'does not save the notification if persist: false' do
|
|
185
|
+
expect(notification).not_to receive(:save!)
|
|
186
|
+
store.mark_failed(notification, nil, '', time, persist: false)
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
describe 'mark_batch_failed' do
|
|
191
|
+
it 'sets the attributes on the object for use in reflections' do
|
|
192
|
+
store.mark_batch_failed([notification], 123, 'an error')
|
|
193
|
+
expect(notification.failed_at.to_s).to eq time.to_s
|
|
194
|
+
expect(notification.delivered_at).to be_nil
|
|
195
|
+
expect(notification.delivered).to eq(false)
|
|
196
|
+
expect(notification.failed).to be_truthy
|
|
197
|
+
expect(notification.error_code).to eq 123
|
|
198
|
+
expect(notification.error_description).to eq 'an error'
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
it 'marks the notification as not delivered' do
|
|
202
|
+
store.mark_batch_failed([notification], nil, '')
|
|
203
|
+
notification.reload
|
|
204
|
+
expect(notification.delivered).to be_falsey
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
it 'marks the notification as failed' do
|
|
208
|
+
expect do
|
|
209
|
+
store.mark_batch_failed([notification], nil, '')
|
|
210
|
+
notification.reload
|
|
211
|
+
end.to change(notification, :failed).to(true)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
it 'sets the time the notification delivery failed' do
|
|
215
|
+
expect do
|
|
216
|
+
store.mark_batch_failed([notification], nil, '')
|
|
217
|
+
notification.reload
|
|
218
|
+
end.to change { notification.failed_at.try(:utc) }.to(time)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
it 'sets the error code' do
|
|
222
|
+
expect do
|
|
223
|
+
store.mark_batch_failed([notification], 42, '')
|
|
224
|
+
notification.reload
|
|
225
|
+
end.to change(notification, :error_code).to(42)
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
it 'sets the error description' do
|
|
229
|
+
expect do
|
|
230
|
+
store.mark_batch_failed([notification], 42, 'Weeee')
|
|
231
|
+
notification.reload
|
|
232
|
+
end.to change(notification, :error_description).to('Weeee')
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
describe 'create_apns_feedback' do
|
|
237
|
+
it 'creates the Feedback record' do
|
|
238
|
+
expect(Rpush::Apns::Feedback).to receive(:create!).with(
|
|
239
|
+
failed_at: time, device_token: 'ab' * 32, app_id: app.id
|
|
240
|
+
)
|
|
241
|
+
store.create_apns_feedback(time, 'ab' * 32, app)
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
describe 'create_gcm_notification' do
|
|
246
|
+
let(:data) { { 'data' => true } }
|
|
247
|
+
let(:attributes) { { device_token: 'ab' * 32 } }
|
|
248
|
+
let(:registration_ids) { %w[123 456] }
|
|
249
|
+
let(:deliver_after) { time + 10.seconds }
|
|
250
|
+
let(:args) { [attributes, data, registration_ids, deliver_after, app] }
|
|
251
|
+
|
|
252
|
+
it 'sets the given attributes' do
|
|
253
|
+
new_notification = store.create_gcm_notification(*args)
|
|
254
|
+
expect(new_notification.device_token).to eq 'ab' * 32
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
it 'sets the given data' do
|
|
258
|
+
new_notification = store.create_gcm_notification(*args)
|
|
259
|
+
expect(new_notification.data['data']).to be_truthy
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
it 'sets the given registration IDs' do
|
|
263
|
+
new_notification = store.create_gcm_notification(*args)
|
|
264
|
+
expect(new_notification.registration_ids).to eq registration_ids
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
it 'sets the deliver_after timestamp' do
|
|
268
|
+
new_notification = store.create_gcm_notification(*args)
|
|
269
|
+
expect(new_notification.deliver_after).to eq deliver_after
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
it 'saves the new notification' do
|
|
273
|
+
new_notification = store.create_gcm_notification(*args)
|
|
274
|
+
expect(new_notification.new_record?).to be_falsey
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
describe 'create_adm_notification' do
|
|
279
|
+
let(:data) { { 'data' => true } }
|
|
280
|
+
let(:attributes) { { app_id: app.id, collapse_key: 'ckey', delay_while_idle: true } }
|
|
281
|
+
let(:registration_ids) { %w[123 456] }
|
|
282
|
+
let(:deliver_after) { time + 10.seconds }
|
|
283
|
+
let(:args) { [attributes, data, registration_ids, deliver_after, app] }
|
|
284
|
+
|
|
285
|
+
it 'sets the given attributes' do
|
|
286
|
+
new_notification = store.create_adm_notification(*args)
|
|
287
|
+
expect(new_notification.app_id).to eq app.id
|
|
288
|
+
expect(new_notification.collapse_key).to eq 'ckey'
|
|
289
|
+
expect(new_notification.delay_while_idle).to be_truthy
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
it 'sets the given data' do
|
|
293
|
+
new_notification = store.create_adm_notification(*args)
|
|
294
|
+
expect(new_notification.data['data']).to be_truthy
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
it 'sets the given registration IDs' do
|
|
298
|
+
new_notification = store.create_adm_notification(*args)
|
|
299
|
+
expect(new_notification.registration_ids).to eq registration_ids
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
it 'sets the deliver_after timestamp' do
|
|
303
|
+
new_notification = store.create_adm_notification(*args)
|
|
304
|
+
expect(new_notification.deliver_after.to_s).to eq deliver_after.to_s
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
it 'saves the new notification' do
|
|
308
|
+
new_notification = store.create_adm_notification(*args)
|
|
309
|
+
expect(new_notification.new_record?).to be_falsey
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
end
|