rpush 4.1.0 → 5.2.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 +254 -162
- data/README.md +57 -16
- data/lib/generators/rpush_migration_generator.rb +2 -0
- data/lib/generators/templates/rpush.rb +4 -0
- data/lib/generators/templates/rpush_4_1_1_updates.rb +9 -0
- data/lib/generators/templates/rpush_4_2_0_updates.rb +10 -0
- data/lib/rpush/apns_feedback.rb +1 -0
- data/lib/rpush/cli.rb +9 -22
- data/lib/rpush/client/active_model.rb +1 -1
- 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/notification.rb +4 -3
- data/lib/rpush/client/active_model/wns/notification.rb +8 -0
- data/lib/rpush/client/active_record.rb +1 -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 -29
- data/lib/rpush/client/active_record/apns2/notification.rb +4 -1
- data/lib/rpush/client/active_record/app.rb +1 -1
- data/lib/rpush/client/active_record/notification.rb +1 -1
- data/lib/rpush/client/redis/apns2/notification.rb +1 -0
- data/lib/rpush/client/redis/app.rb +2 -1
- data/lib/rpush/client/redis/notification.rb +2 -1
- data/lib/rpush/client/redis/pushy/notification.rb +0 -1
- data/lib/rpush/configuration.rb +2 -1
- data/lib/rpush/daemon.rb +2 -2
- data/lib/rpush/daemon/apns/feedback_receiver.rb +2 -1
- data/lib/rpush/daemon/apns2/delivery.rb +6 -1
- 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/dispatcher/apns_http2.rb +4 -2
- data/lib/rpush/daemon/dispatcher/apnsp8_http2.rb +2 -1
- data/lib/rpush/daemon/signal_handler.rb +1 -1
- data/lib/rpush/daemon/store/active_record.rb +1 -1
- data/lib/rpush/daemon/store/active_record/reconnectable.rb +1 -1
- data/lib/rpush/daemon/store/redis.rb +1 -1
- data/lib/rpush/daemon/wns/badge_request.rb +8 -3
- data/lib/rpush/daemon/wns/raw_request.rb +9 -2
- data/lib/rpush/daemon/wns/toast_request.rb +6 -2
- data/lib/rpush/logger.rb +1 -0
- data/lib/rpush/version.rb +2 -2
- data/spec/.rubocop.yml +1 -1
- data/spec/functional/apns2_spec.rb +85 -0
- data/spec/functional/gcm_priority_spec.rb +40 -0
- data/spec/support/active_record_setup.rb +5 -1
- data/spec/support/simplecov_helper.rb +1 -1
- data/spec/unit/apns_feedback_spec.rb +17 -6
- 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 -288
- 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/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 -83
- data/spec/unit/client/active_record/notification_spec.rb +10 -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/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/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/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/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/apns/feedback_receiver_spec.rb +19 -1
- data/spec/unit/daemon/batch_spec.rb +50 -2
- data/spec/unit/daemon/delivery_spec.rb +10 -0
- data/spec/unit/daemon/gcm/delivery_spec.rb +1 -1
- 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 +7 -295
- data/spec/unit/daemon/store/redis_spec.rb +4 -293
- data/spec/unit/daemon/wns/post_request_spec.rb +64 -0
- data/spec/unit_spec_helper.rb +3 -0
- metadata +114 -14
- data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +0 -16
|
@@ -177,6 +177,13 @@ describe 'APNs http2 adapter' do
|
|
|
177
177
|
end
|
|
178
178
|
|
|
179
179
|
context 'when there is SocketError' do
|
|
180
|
+
let(:fake_http_resp_headers) {
|
|
181
|
+
{
|
|
182
|
+
":status" => "500",
|
|
183
|
+
"apns-id"=>"C6D65840-5E3F-785A-4D91-B97D305C12F6"
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
180
187
|
before(:each) do
|
|
181
188
|
expect(fake_client).to receive(:call_async) { raise(SocketError) }
|
|
182
189
|
end
|
|
@@ -201,6 +208,24 @@ describe 'APNs http2 adapter' do
|
|
|
201
208
|
notification = create_notification
|
|
202
209
|
Rpush.push
|
|
203
210
|
end
|
|
211
|
+
|
|
212
|
+
context 'when specific notification was delivered before request failed' do
|
|
213
|
+
let(:fake_http_resp_headers) {
|
|
214
|
+
{
|
|
215
|
+
":status" => "200",
|
|
216
|
+
"apns-id"=>"C6D65840-5E3F-785A-4D91-B97D305C12F6"
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
it 'fails but will not retry this notification' do
|
|
221
|
+
notification = create_notification
|
|
222
|
+
expect do
|
|
223
|
+
Rpush.push
|
|
224
|
+
notification.reload
|
|
225
|
+
end.to change(notification, :retries).by(0)
|
|
226
|
+
.and change(notification, :delivered).to(true)
|
|
227
|
+
end
|
|
228
|
+
end
|
|
204
229
|
end
|
|
205
230
|
|
|
206
231
|
context 'when any StandardError occurs' do
|
|
@@ -228,5 +253,65 @@ describe 'APNs http2 adapter' do
|
|
|
228
253
|
Rpush.push
|
|
229
254
|
end
|
|
230
255
|
end
|
|
256
|
+
|
|
257
|
+
context 'when waiting for requests to complete times out' do
|
|
258
|
+
let(:on_close) do
|
|
259
|
+
proc { |&block| @thread = Thread.new { sleep(0.01) } }
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
before(:each) do
|
|
263
|
+
@thread = nil
|
|
264
|
+
|
|
265
|
+
expect(fake_http2_request).
|
|
266
|
+
to receive(:on).with(:close), &on_close
|
|
267
|
+
|
|
268
|
+
expect(fake_client).to receive(:join) { @thread.join; raise(NetHttp2::AsyncRequestTimeout) }
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
it 'closes the client' do
|
|
272
|
+
create_notification
|
|
273
|
+
expect(fake_client).to receive(:close)
|
|
274
|
+
Rpush.push
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
it 'reflects :error' do
|
|
278
|
+
reflected_error = false
|
|
279
|
+
Rpush.reflect do |on|
|
|
280
|
+
on.error do |error|
|
|
281
|
+
reflected_error = true
|
|
282
|
+
expect(error).to be_kind_of(StandardError)
|
|
283
|
+
reflector.accept
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
notification = create_notification
|
|
288
|
+
Rpush.push
|
|
289
|
+
|
|
290
|
+
expect(reflected_error).to be true
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
it 'fails but retries delivery several times' do
|
|
294
|
+
notification = create_notification
|
|
295
|
+
expect do
|
|
296
|
+
Rpush.push
|
|
297
|
+
notification.reload
|
|
298
|
+
end.to change(notification, :retries)
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
context 'when specific notification was delivered before another async call failed' do
|
|
302
|
+
let(:on_close) do
|
|
303
|
+
proc { |&block| @thread = Thread.new { sleep(0.01); block.call } }
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
it 'fails but retries delivery several times' do
|
|
307
|
+
notification = create_notification
|
|
308
|
+
expect do
|
|
309
|
+
Rpush.push
|
|
310
|
+
notification.reload
|
|
311
|
+
end.to change(notification, :retries).by(0)
|
|
312
|
+
.and change(notification, :delivered).to(true)
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
end
|
|
231
316
|
end
|
|
232
317
|
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'functional_spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'GCM priority' do
|
|
4
|
+
let(:app) { Rpush::Gcm::App.new }
|
|
5
|
+
let(:notification) { Rpush::Gcm::Notification.new }
|
|
6
|
+
let(:hydrated_notification) { Rpush::Gcm::Notification.find(notification.id) }
|
|
7
|
+
let(:response) { double(Net::HTTPResponse, code: 200) }
|
|
8
|
+
let(:http) { double(Net::HTTP::Persistent, request: response, shutdown: nil) }
|
|
9
|
+
let(:priority) { 'normal' }
|
|
10
|
+
|
|
11
|
+
before do
|
|
12
|
+
app.name = 'test'
|
|
13
|
+
app.auth_key = 'abc123'
|
|
14
|
+
app.save!
|
|
15
|
+
|
|
16
|
+
notification.app_id = app.id
|
|
17
|
+
notification.registration_ids = ['foo']
|
|
18
|
+
notification.data = { message: 'test' }
|
|
19
|
+
notification.priority = priority
|
|
20
|
+
notification.save!
|
|
21
|
+
|
|
22
|
+
allow(Net::HTTP::Persistent).to receive_messages(new: http)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'supports normal priority' do
|
|
26
|
+
expect(hydrated_notification.as_json['priority']).to eq('normal')
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
context 'high priority' do
|
|
30
|
+
let(:priority) { 'high' }
|
|
31
|
+
|
|
32
|
+
it 'supports high priority' do
|
|
33
|
+
expect(hydrated_notification.as_json['priority']).to eq('high')
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'does not add an error when receiving expected priority' do
|
|
38
|
+
expect(hydrated_notification.errors.messages[:priority]).to be_empty
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -40,6 +40,8 @@ require 'generators/templates/rpush_3_2_4_updates'
|
|
|
40
40
|
require 'generators/templates/rpush_3_3_0_updates'
|
|
41
41
|
require 'generators/templates/rpush_3_3_1_updates'
|
|
42
42
|
require 'generators/templates/rpush_4_1_0_updates'
|
|
43
|
+
require 'generators/templates/rpush_4_1_1_updates'
|
|
44
|
+
require 'generators/templates/rpush_4_2_0_updates'
|
|
43
45
|
|
|
44
46
|
migrations = [
|
|
45
47
|
AddRpush,
|
|
@@ -55,7 +57,9 @@ migrations = [
|
|
|
55
57
|
Rpush324Updates,
|
|
56
58
|
Rpush330Updates,
|
|
57
59
|
Rpush331Updates,
|
|
58
|
-
Rpush410Updates
|
|
60
|
+
Rpush410Updates,
|
|
61
|
+
Rpush411Updates,
|
|
62
|
+
Rpush420Updates
|
|
59
63
|
]
|
|
60
64
|
|
|
61
65
|
unless ENV['TRAVIS']
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
require 'unit_spec_helper'
|
|
2
2
|
|
|
3
3
|
describe Rpush, 'apns_feedback' do
|
|
4
|
-
let!(:apns_app)
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
let!(:apns_app) { Rpush::Apns::App.create!(apns_app_params) }
|
|
5
|
+
let(:apns_app_params) do
|
|
6
|
+
{
|
|
7
|
+
name: 'test',
|
|
8
|
+
environment: 'production',
|
|
9
|
+
certificate: TEST_CERT
|
|
10
|
+
}
|
|
10
11
|
end
|
|
12
|
+
let!(:gcm_app) { Rpush::Gcm::App.create!(name: 'MyApp', auth_key: 'abc123') }
|
|
11
13
|
|
|
12
14
|
let(:receiver) { double(check_for_feedback: nil) }
|
|
13
15
|
|
|
@@ -25,4 +27,13 @@ describe Rpush, 'apns_feedback' do
|
|
|
25
27
|
expect(receiver).to receive(:check_for_feedback)
|
|
26
28
|
Rpush.apns_feedback
|
|
27
29
|
end
|
|
30
|
+
|
|
31
|
+
context 'feedback disabled' do
|
|
32
|
+
let(:apns_app_params) { super().merge(feedback_enabled: false) }
|
|
33
|
+
|
|
34
|
+
it 'does not initialize feedback receiver' do
|
|
35
|
+
expect(Rpush::Daemon::Apns::FeedbackReceiver).not_to receive(:new)
|
|
36
|
+
Rpush.apns_feedback
|
|
37
|
+
end
|
|
38
|
+
end
|
|
28
39
|
end
|
|
@@ -1,58 +1,6 @@
|
|
|
1
1
|
require 'unit_spec_helper'
|
|
2
2
|
|
|
3
3
|
describe Rpush::Client::ActiveRecord::Adm::App do
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
it 'should be valid if properly instantiated' do
|
|
8
|
-
expect(subject).to be_valid
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
it 'should be invalid if name' do
|
|
12
|
-
subject.name = nil
|
|
13
|
-
expect(subject).not_to be_valid
|
|
14
|
-
expect(subject.errors[:name]).to eq ["can't be blank"]
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
it 'should be invalid if name is not unique within scope' do
|
|
18
|
-
subject.name = existing_app.name
|
|
19
|
-
expect(subject).not_to be_valid
|
|
20
|
-
expect(subject.errors[:name]).to eq ["has already been taken"]
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
it 'should be invalid if missing client_id' do
|
|
24
|
-
subject.client_id = nil
|
|
25
|
-
expect(subject).not_to be_valid
|
|
26
|
-
expect(subject.errors[:client_id]).to eq ["can't be blank"]
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
it 'should be invalid if missing client_secret' do
|
|
30
|
-
subject.client_secret = nil
|
|
31
|
-
expect(subject).not_to be_valid
|
|
32
|
-
expect(subject.errors[:client_secret]).to eq ["can't be blank"]
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
describe '#access_token_expired?' do
|
|
36
|
-
before(:each) do
|
|
37
|
-
Timecop.freeze(Time.now)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
after do
|
|
41
|
-
Timecop.return
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
it 'should return true if access_token_expiration is nil' do
|
|
45
|
-
expect(subject.access_token_expired?).to eq(true)
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it 'should return true if expired' do
|
|
49
|
-
subject.access_token_expiration = Time.now - 5.minutes
|
|
50
|
-
expect(subject.access_token_expired?).to eq(true)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
it 'should return false if not expired' do
|
|
54
|
-
subject.access_token_expiration = Time.now + 5.minutes
|
|
55
|
-
expect(subject.access_token_expired?).to eq(false)
|
|
56
|
-
end
|
|
57
|
-
end
|
|
4
|
+
it_behaves_like 'Rpush::Client::Adm::App'
|
|
5
|
+
it_behaves_like 'Rpush::Client::ActiveRecord::App'
|
|
58
6
|
end if active_record?
|
|
@@ -1,43 +1,6 @@
|
|
|
1
1
|
require 'unit_spec_helper'
|
|
2
|
-
require 'unit/notification_shared.rb'
|
|
3
2
|
|
|
4
3
|
describe Rpush::Client::ActiveRecord::Adm::Notification do
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
let(:app) { Rpush::Client::ActiveRecord::Adm::App.create!(name: 'test', client_id: 'CLIENT_ID', client_secret: 'CLIENT_SECRET') }
|
|
8
|
-
let(:notification_class) { Rpush::Client::ActiveRecord::Adm::Notification }
|
|
9
|
-
let(:notification) { notification_class.new }
|
|
10
|
-
|
|
11
|
-
it "has a 'data' payload limit of 6144 bytes" do
|
|
12
|
-
notification.data = { key: "a" * 6144 }
|
|
13
|
-
expect(notification.valid?).to eq(false)
|
|
14
|
-
expect(notification.errors[:base]).to eq ["Notification payload data cannot be larger than 6144 bytes."]
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
it 'limits the number of registration ids to 100' do
|
|
18
|
-
notification.registration_ids = ['a'] * (100 + 1)
|
|
19
|
-
expect(notification.valid?).to eq(false)
|
|
20
|
-
expect(notification.errors[:base]).to eq ["Number of registration_ids cannot be larger than 100."]
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
it 'validates data can be blank if collapse_key is set' do
|
|
24
|
-
notification.app = app
|
|
25
|
-
notification.registration_ids = 'a'
|
|
26
|
-
notification.collapse_key = 'test'
|
|
27
|
-
notification.data = nil
|
|
28
|
-
expect(notification.valid?).to eq(true)
|
|
29
|
-
expect(notification.errors[:data]).to be_empty
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
it 'validates data is present if collapse_key is not set' do
|
|
33
|
-
notification.collapse_key = nil
|
|
34
|
-
notification.data = nil
|
|
35
|
-
expect(notification.valid?).to eq(false)
|
|
36
|
-
expect(notification.errors[:data]).to eq ['must be set unless collapse_key is specified']
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
it 'includes expiresAfter in the payload' do
|
|
40
|
-
notification.expiry = 100
|
|
41
|
-
expect(notification.as_json['expiresAfter']).to eq 100
|
|
42
|
-
end
|
|
4
|
+
it_behaves_like 'Rpush::Client::Adm::Notification'
|
|
5
|
+
it_behaves_like 'Rpush::Client::ActiveRecord::Notification'
|
|
43
6
|
end if active_record?
|
|
@@ -1,29 +1,6 @@
|
|
|
1
1
|
require 'unit_spec_helper'
|
|
2
2
|
|
|
3
|
-
describe Rpush::Client::ActiveRecord::App do
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
app.valid?
|
|
7
|
-
expect(app.errors[:certificate]).to eq ['value must contain a certificate and a private key.']
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
it 'validates a certificate without a password' do
|
|
11
|
-
app = Rpush::Client::ActiveRecord::Apns::App.new name: 'test', environment: 'development', certificate: TEST_CERT
|
|
12
|
-
app.valid?
|
|
13
|
-
expect(app.errors[:certificate]).to eq []
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
it 'validates a certificate with a password' do
|
|
17
|
-
app = Rpush::Client::ActiveRecord::Apns::App.new name: 'test', environment: 'development',
|
|
18
|
-
certificate: TEST_CERT_WITH_PASSWORD, password: 'fubar'
|
|
19
|
-
app.valid?
|
|
20
|
-
expect(app.errors[:certificate]).to eq []
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
it 'validates a certificate with an incorrect password' do
|
|
24
|
-
app = Rpush::Client::ActiveRecord::Apns::App.new name: 'test', environment: 'development',
|
|
25
|
-
certificate: TEST_CERT_WITH_PASSWORD, password: 'incorrect'
|
|
26
|
-
app.valid?
|
|
27
|
-
expect(app.errors[:certificate]).to eq ['value must contain a certificate and a private key.']
|
|
28
|
-
end
|
|
3
|
+
describe Rpush::Client::ActiveRecord::Apns::App do
|
|
4
|
+
it_behaves_like 'Rpush::Client::Apns::App'
|
|
5
|
+
it_behaves_like 'Rpush::Client::ActiveRecord::App'
|
|
29
6
|
end if active_record?
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
require 'unit_spec_helper'
|
|
2
2
|
|
|
3
3
|
describe Rpush::Client::ActiveRecord::Apns::Feedback do
|
|
4
|
-
|
|
5
|
-
notification = Rpush::Client::ActiveRecord::Apns::Feedback.new(device_token: "{$%^&*()}")
|
|
6
|
-
expect(notification.valid?).to be_falsey
|
|
7
|
-
expect(notification.errors[:device_token]).to include('is invalid')
|
|
8
|
-
end
|
|
4
|
+
it_behaves_like 'Rpush::Client::Apns::Feedback'
|
|
9
5
|
end if active_record?
|
|
@@ -1,324 +1,65 @@
|
|
|
1
|
-
# encoding: US-ASCII
|
|
2
|
-
|
|
3
1
|
require "unit_spec_helper"
|
|
4
|
-
require 'unit/notification_shared.rb'
|
|
5
2
|
|
|
6
3
|
describe Rpush::Client::ActiveRecord::Apns::Notification do
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
let(:app) { Rpush::Client::ActiveRecord::Apns::App.create!(name: 'my_app', environment: 'development', certificate: TEST_CERT) }
|
|
10
|
-
let(:notification_class) { Rpush::Client::ActiveRecord::Apns::Notification }
|
|
11
|
-
let(:notification) { notification_class.new }
|
|
4
|
+
subject(:notification) { described_class.new }
|
|
12
5
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
expect(notification.valid?).to be_falsey
|
|
16
|
-
expect(notification.errors[:device_token].include?("is invalid")).to be_truthy
|
|
17
|
-
end
|
|
6
|
+
it_behaves_like 'Rpush::Client::Apns::Notification'
|
|
7
|
+
it_behaves_like 'Rpush::Client::ActiveRecord::Notification'
|
|
18
8
|
|
|
19
9
|
it "should validate the length of the binary conversion of the notification" do
|
|
10
|
+
notification = described_class.new
|
|
11
|
+
notification.app = Rpush::Apns2::App.create(name: 'test', environment: 'development')
|
|
20
12
|
notification.device_token = "a" * 108
|
|
21
|
-
notification.alert = "
|
|
22
|
-
expect(notification.valid?).to be_falsey
|
|
23
|
-
expect(notification.errors[:base].include?("APN notification cannot be larger than 2048 bytes. Try condensing your alert and device attributes.")).to be_truthy
|
|
24
|
-
end
|
|
13
|
+
notification.alert = ""
|
|
25
14
|
|
|
26
|
-
|
|
27
|
-
notification.app = app
|
|
28
|
-
notification.device_token = "a" * 108
|
|
29
|
-
notification.alert = "*" * 300
|
|
15
|
+
notification.alert << "a" until notification.payload.bytesize == 2048
|
|
30
16
|
expect(notification.valid?).to be_truthy
|
|
17
|
+
expect(notification.errors[:base]).to be_empty
|
|
31
18
|
|
|
32
|
-
notification.
|
|
33
|
-
notification.
|
|
34
|
-
expect(notification.
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
it "should default the sound to nil" do
|
|
38
|
-
expect(notification.sound).to be_nil
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
it "should default the expiry to 1 day" do
|
|
42
|
-
expect(notification.expiry).to eq 1.day.to_i
|
|
43
|
-
end
|
|
44
|
-
end if active_record?
|
|
45
|
-
|
|
46
|
-
describe Rpush::Client::ActiveRecord::Apns::Notification, "when assigning the device token" do
|
|
47
|
-
it "should strip spaces from the given string" do
|
|
48
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new(device_token: "o m g")
|
|
49
|
-
expect(notification.device_token).to eq "omg"
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
it "should strip chevrons from the given string" do
|
|
53
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new(device_token: "<omg>")
|
|
54
|
-
expect(notification.device_token).to eq "omg"
|
|
55
|
-
end
|
|
56
|
-
end if active_record?
|
|
57
|
-
|
|
58
|
-
describe Rpush::Client::ActiveRecord::Apns::Notification, "as_json" do
|
|
59
|
-
it "should include the alert if present" do
|
|
60
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new(alert: "hi mom")
|
|
61
|
-
expect(notification.as_json["aps"]["alert"]).to eq "hi mom"
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
it "should not include the alert key if the alert is not present" do
|
|
65
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new(alert: nil)
|
|
66
|
-
expect(notification.as_json["aps"].key?("alert")).to be_falsey
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
it "should encode the alert as JSON if it is a Hash" do
|
|
70
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new(alert: { 'body' => "hi mom", 'alert-loc-key' => "View" })
|
|
71
|
-
expect(notification.as_json["aps"]["alert"]).to eq('body' => "hi mom", 'alert-loc-key' => "View")
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
it "should include the badge if present" do
|
|
75
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new(badge: 6)
|
|
76
|
-
expect(notification.as_json["aps"]["badge"]).to eq 6
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
it "should not include the badge key if the badge is not present" do
|
|
80
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new(badge: nil)
|
|
81
|
-
expect(notification.as_json["aps"].key?("badge")).to be_falsey
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
it "should include the sound if present" do
|
|
85
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new(alert: "my_sound.aiff")
|
|
86
|
-
expect(notification.as_json["aps"]["alert"]).to eq "my_sound.aiff"
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
it "should not include the sound key if the sound is not present" do
|
|
90
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new(sound: nil)
|
|
91
|
-
expect(notification.as_json["aps"].key?("sound")).to be_falsey
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
it "should include attributes for the device" do
|
|
95
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new
|
|
96
|
-
notification.data = { omg: :lol, wtf: :dunno }
|
|
97
|
-
expect(notification.as_json["omg"]).to eq "lol"
|
|
98
|
-
expect(notification.as_json["wtf"]).to eq "dunno"
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
it "should allow attributes to include a hash" do
|
|
102
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new
|
|
103
|
-
notification.data = { omg: { ilike: :hashes } }
|
|
104
|
-
expect(notification.as_json["omg"]["ilike"]).to eq "hashes"
|
|
105
|
-
end
|
|
106
|
-
end if active_record?
|
|
107
|
-
|
|
108
|
-
describe Rpush::Client::ActiveRecord::Apns::Notification, 'MDM' do
|
|
109
|
-
let(:magic) { 'abc123' }
|
|
110
|
-
let(:notification) { Rpush::Client::ActiveRecord::Apns::Notification.new }
|
|
111
|
-
|
|
112
|
-
before do
|
|
113
|
-
notification.device_token = "a" * 108
|
|
114
|
-
notification.id = 1234
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
it 'includes the mdm magic in the payload' do
|
|
118
|
-
notification.mdm = magic
|
|
119
|
-
expect(notification.as_json).to eq('mdm' => magic)
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
it 'does not include aps attribute' do
|
|
123
|
-
notification.alert = "i'm doomed"
|
|
124
|
-
notification.mdm = magic
|
|
125
|
-
expect(notification.as_json.key?('aps')).to be_falsey
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
it 'can be converted to binary' do
|
|
129
|
-
notification.mdm = magic
|
|
130
|
-
expect(notification.to_binary).to be_present
|
|
19
|
+
notification.alert << "a"
|
|
20
|
+
expect(notification.valid?).to be_falsey
|
|
21
|
+
expect(notification.errors[:base].include?("APN notification cannot be larger than 2048 bytes. Try condensing your alert and device attributes.")).to be_truthy
|
|
131
22
|
end
|
|
132
|
-
end if active_record?
|
|
133
23
|
|
|
134
|
-
describe
|
|
135
|
-
|
|
24
|
+
describe "multi_json usage" do
|
|
25
|
+
describe "alert" do
|
|
26
|
+
subject(:notification) { described_class.new(alert: { a: 1 }, alert_is_json: true) }
|
|
136
27
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
28
|
+
it "should call MultiJson.load when multi_json version is 1.3.0" do
|
|
29
|
+
allow(Gem).to receive(:loaded_specs).and_return('multi_json' => Gem::Specification.new('multi_json', '1.3.0'))
|
|
30
|
+
expect(MultiJson).to receive(:load).with(any_args)
|
|
31
|
+
notification.alert
|
|
32
|
+
end
|
|
141
33
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
expect(notification.as_json.key?('mutable-content')).to be_falsey
|
|
34
|
+
it "should call MultiJson.decode when multi_json version is 1.2.9" do
|
|
35
|
+
allow(Gem).to receive(:loaded_specs).and_return('multi_json' => Gem::Specification.new('multi_json', '1.2.9'))
|
|
36
|
+
expect(MultiJson).to receive(:decode).with(any_args)
|
|
37
|
+
notification.alert
|
|
38
|
+
end
|
|
39
|
+
end
|
|
149
40
|
end
|
|
150
41
|
|
|
151
|
-
it
|
|
152
|
-
notification.
|
|
153
|
-
notification.mutable_content = true
|
|
154
|
-
expect(notification.as_json['aps']['mutable-content']).to eq 1
|
|
155
|
-
expect(notification.as_json['hi']).to eq 'mom'
|
|
42
|
+
it "should default the sound to nil" do
|
|
43
|
+
expect(notification.sound).to be_nil
|
|
156
44
|
end
|
|
157
45
|
|
|
158
46
|
it 'does not overwrite the mutable-content flag when setting attributes for the device' do
|
|
159
47
|
notification.mutable_content = true
|
|
160
|
-
notification.data = { hi
|
|
48
|
+
notification.data = { 'hi' => 'mom' }
|
|
161
49
|
expect(notification.as_json['aps']['mutable-content']).to eq 1
|
|
162
50
|
expect(notification.as_json['hi']).to eq 'mom'
|
|
163
51
|
end
|
|
164
|
-
end if active_record?
|
|
165
|
-
|
|
166
|
-
describe Rpush::Client::ActiveRecord::Apns::Notification, 'content-available' do
|
|
167
|
-
let(:notification) { Rpush::Client::ActiveRecord::Apns::Notification.new }
|
|
168
|
-
|
|
169
|
-
it 'includes content-available in the payload' do
|
|
170
|
-
notification.content_available = true
|
|
171
|
-
expect(notification.as_json['aps']['content-available']).to eq 1
|
|
172
|
-
end
|
|
173
|
-
|
|
174
|
-
it 'does not include content-available in the payload if not set' do
|
|
175
|
-
expect(notification.as_json['aps'].key?('content-available')).to be_falsey
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
it 'does not include content-available as a non-aps attribute' do
|
|
179
|
-
notification.content_available = true
|
|
180
|
-
expect(notification.as_json.key?('content-available')).to be_falsey
|
|
181
|
-
end
|
|
182
|
-
|
|
183
|
-
it 'does not overwrite existing attributes for the device' do
|
|
184
|
-
notification.data = { hi: :mom }
|
|
185
|
-
notification.content_available = true
|
|
186
|
-
expect(notification.as_json['aps']['content-available']).to eq 1
|
|
187
|
-
expect(notification.as_json['hi']).to eq 'mom'
|
|
188
|
-
end
|
|
189
52
|
|
|
190
53
|
it 'does not overwrite the content-available flag when setting attributes for the device' do
|
|
191
54
|
notification.content_available = true
|
|
192
|
-
notification.data = { hi
|
|
55
|
+
notification.data = { 'hi' => 'mom' }
|
|
193
56
|
expect(notification.as_json['aps']['content-available']).to eq 1
|
|
194
57
|
expect(notification.as_json['hi']).to eq 'mom'
|
|
195
58
|
end
|
|
196
|
-
end if active_record?
|
|
197
|
-
|
|
198
|
-
describe Rpush::Client::ActiveRecord::Apns::Notification, 'url-args' do
|
|
199
|
-
let(:notification) { Rpush::Client::ActiveRecord::Apns::Notification.new }
|
|
200
|
-
|
|
201
|
-
it 'includes url-args in the payload' do
|
|
202
|
-
notification.url_args = ['url-arg-1']
|
|
203
|
-
expect(notification.as_json['aps']['url-args']).to eq ['url-arg-1']
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
it 'does not include url-args in the payload if not set' do
|
|
207
|
-
expect(notification.as_json['aps'].key?('url-args')).to be_falsey
|
|
208
|
-
end
|
|
209
|
-
end if active_record?
|
|
210
|
-
|
|
211
|
-
describe Rpush::Client::ActiveRecord::Apns::Notification, 'category' do
|
|
212
|
-
let(:notification) { Rpush::Client::ActiveRecord::Apns::Notification.new }
|
|
213
|
-
|
|
214
|
-
it 'includes category in the payload' do
|
|
215
|
-
notification.category = 'INVITE_CATEGORY'
|
|
216
|
-
expect(notification.as_json['aps']['category']).to eq 'INVITE_CATEGORY'
|
|
217
|
-
end
|
|
218
|
-
|
|
219
|
-
it 'does not include category in the payload if not set' do
|
|
220
|
-
expect(notification.as_json['aps'].key?('category')).to be_falsey
|
|
221
|
-
end
|
|
222
|
-
end if active_record?
|
|
223
|
-
|
|
224
|
-
describe Rpush::Client::ActiveRecord::Apns::Notification, 'to_binary' do
|
|
225
|
-
let(:notification) { Rpush::Client::ActiveRecord::Apns::Notification.new }
|
|
226
|
-
|
|
227
|
-
before do
|
|
228
|
-
notification.device_token = "a" * 108
|
|
229
|
-
notification.id = 1234
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
it 'uses APNS_PRIORITY_CONSERVE_POWER if content-available is the only key' do
|
|
233
|
-
notification.alert = nil
|
|
234
|
-
notification.badge = nil
|
|
235
|
-
notification.sound = nil
|
|
236
|
-
notification.content_available = true
|
|
237
|
-
bytes = notification.to_binary.bytes.to_a[-4..-1]
|
|
238
|
-
expect(bytes.first).to eq 5 # priority item ID
|
|
239
|
-
expect(bytes.last).to eq Rpush::Client::ActiveRecord::Apns::Notification::APNS_PRIORITY_CONSERVE_POWER
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
it 'uses APNS_PRIORITY_IMMEDIATE if content-available is not the only key' do
|
|
243
|
-
notification.alert = "New stuff!"
|
|
244
|
-
notification.badge = nil
|
|
245
|
-
notification.sound = nil
|
|
246
|
-
notification.content_available = true
|
|
247
|
-
bytes = notification.to_binary.bytes.to_a[-4..-1]
|
|
248
|
-
expect(bytes.first).to eq 5 # priority item ID
|
|
249
|
-
expect(bytes.last).to eq Rpush::Client::ActiveRecord::Apns::Notification::APNS_PRIORITY_IMMEDIATE
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
it "should correctly convert the notification to binary" do
|
|
253
|
-
notification.sound = "1.aiff"
|
|
254
|
-
notification.badge = 3
|
|
255
|
-
notification.alert = "Don't panic Mr Mainwaring, don't panic!"
|
|
256
|
-
notification.data = { hi: :mom }
|
|
257
|
-
notification.expiry = 86_400 # 1 day
|
|
258
|
-
notification.priority = Rpush::Client::ActiveRecord::Apns::Notification::APNS_PRIORITY_IMMEDIATE
|
|
259
|
-
notification.app = Rpush::Client::ActiveRecord::Apns::App.new(name: 'my_app', environment: 'development', certificate: TEST_CERT)
|
|
260
|
-
now = Time.now
|
|
261
|
-
allow(Time).to receive_messages(now: now)
|
|
262
|
-
expect(notification.to_binary).to eq "\x02\x00\x00\x00\xAF\x01\x00 \xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\x02\x00a{\"aps\":{\"alert\":\"Don't panic Mr Mainwaring, don't panic!\",\"badge\":3,\"sound\":\"1.aiff\"},\"hi\":\"mom\"}\x03\x00\x04\x00\x00\x04\xD2\x04\x00\x04#{[now.to_i + 86_400].pack('N')}\x05\x00\x01\n"
|
|
263
|
-
end
|
|
264
|
-
end if active_record?
|
|
265
|
-
|
|
266
|
-
describe Rpush::Client::ActiveRecord::Apns::Notification, "bug #31" do
|
|
267
|
-
it 'does not confuse a JSON looking string as JSON' do
|
|
268
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new
|
|
269
|
-
notification.alert = "{\"one\":2}"
|
|
270
|
-
expect(notification.alert).to eq "{\"one\":2}"
|
|
271
|
-
end
|
|
272
59
|
|
|
273
60
|
it 'does confuse a JSON looking string as JSON if the alert_is_json attribute is not present' do
|
|
274
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new
|
|
275
61
|
allow(notification).to receive_messages(has_attribute?: false)
|
|
276
62
|
notification.alert = "{\"one\":2}"
|
|
277
63
|
expect(notification.alert).to eq('one' => 2)
|
|
278
64
|
end
|
|
279
65
|
end if active_record?
|
|
280
|
-
|
|
281
|
-
describe Rpush::Client::ActiveRecord::Apns::Notification, "bug #35" do
|
|
282
|
-
it "should limit payload size to 256 bytes but not the entire packet" do
|
|
283
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new do |n|
|
|
284
|
-
n.device_token = "a" * 108
|
|
285
|
-
n.alert = "a" * 210
|
|
286
|
-
n.app = Rpush::Client::ActiveRecord::Apns::App.create!(name: 'my_app', environment: 'development', certificate: TEST_CERT)
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
expect(notification.to_binary(for_validation: true).bytesize).to be > 256
|
|
290
|
-
expect(notification.payload.bytesize).to be < 256
|
|
291
|
-
expect(notification).to be_valid
|
|
292
|
-
end
|
|
293
|
-
end if active_record?
|
|
294
|
-
|
|
295
|
-
describe Rpush::Client::ActiveRecord::Apns::Notification, "multi_json usage" do
|
|
296
|
-
describe Rpush::Client::ActiveRecord::Apns::Notification, "alert" do
|
|
297
|
-
it "should call MultiJson.load when multi_json version is 1.3.0" do
|
|
298
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new(alert: { a: 1 }, alert_is_json: true)
|
|
299
|
-
allow(Gem).to receive(:loaded_specs).and_return('multi_json' => Gem::Specification.new('multi_json', '1.3.0'))
|
|
300
|
-
expect(MultiJson).to receive(:load).with(any_args)
|
|
301
|
-
notification.alert
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
it "should call MultiJson.decode when multi_json version is 1.2.9" do
|
|
305
|
-
notification = Rpush::Client::ActiveRecord::Apns::Notification.new(alert: { a: 1 }, alert_is_json: true)
|
|
306
|
-
allow(Gem).to receive(:loaded_specs).and_return('multi_json' => Gem::Specification.new('multi_json', '1.2.9'))
|
|
307
|
-
expect(MultiJson).to receive(:decode).with(any_args)
|
|
308
|
-
notification.alert
|
|
309
|
-
end
|
|
310
|
-
end
|
|
311
|
-
end if active_record?
|
|
312
|
-
|
|
313
|
-
describe Rpush::Client::ActiveRecord::Apns::Notification, 'thread-id' do
|
|
314
|
-
let(:notification) { Rpush::Client::ActiveRecord::Apns::Notification.new }
|
|
315
|
-
|
|
316
|
-
it 'includes thread-id in the payload' do
|
|
317
|
-
notification.thread_id = 'THREAD-ID'
|
|
318
|
-
expect(notification.as_json['aps']['thread-id']).to eq 'THREAD-ID'
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
it 'does not include thread-id in the payload if not set' do
|
|
322
|
-
expect(notification.as_json['aps']).to_not have_key('thread-id')
|
|
323
|
-
end
|
|
324
|
-
end if active_record?
|