fcm-ruby-push-notifications 1.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 +7 -0
- data/.gitignore +37 -0
- data/.rspec +2 -0
- data/.travis.yml +19 -0
- data/CHANGELOG.md +32 -0
- data/Gemfile +6 -0
- data/LICENSE +22 -0
- data/README.md +82 -0
- data/Rakefile +12 -0
- data/examples/apns.rb +27 -0
- data/examples/gcm.rb +25 -0
- data/examples/mpns.rb +22 -0
- data/examples/wns.rb +25 -0
- data/gemfiles/Gemfile-legacy +8 -0
- data/lib/ruby-push-notifications.rb +7 -0
- data/lib/ruby-push-notifications/apns.rb +44 -0
- data/lib/ruby-push-notifications/apns/apns_connection.rb +70 -0
- data/lib/ruby-push-notifications/apns/apns_notification.rb +91 -0
- data/lib/ruby-push-notifications/apns/apns_pusher.rb +84 -0
- data/lib/ruby-push-notifications/apns/apns_results.rb +30 -0
- data/lib/ruby-push-notifications/fcm.rb +8 -0
- data/lib/ruby-push-notifications/fcm/fcm_connection.rb +60 -0
- data/lib/ruby-push-notifications/fcm/fcm_error.rb +17 -0
- data/lib/ruby-push-notifications/fcm/fcm_notification.rb +31 -0
- data/lib/ruby-push-notifications/fcm/fcm_pusher.rb +29 -0
- data/lib/ruby-push-notifications/fcm/fcm_request.rb +28 -0
- data/lib/ruby-push-notifications/fcm/fcm_response.rb +89 -0
- data/lib/ruby-push-notifications/fcm/fcm_result.rb +52 -0
- data/lib/ruby-push-notifications/gcm.rb +6 -0
- data/lib/ruby-push-notifications/gcm/gcm_connection.rb +54 -0
- data/lib/ruby-push-notifications/gcm/gcm_error.rb +17 -0
- data/lib/ruby-push-notifications/gcm/gcm_notification.rb +31 -0
- data/lib/ruby-push-notifications/gcm/gcm_pusher.rb +35 -0
- data/lib/ruby-push-notifications/gcm/gcm_response.rb +89 -0
- data/lib/ruby-push-notifications/gcm/gcm_result.rb +52 -0
- data/lib/ruby-push-notifications/mpns.rb +5 -0
- data/lib/ruby-push-notifications/mpns/mpns_connection.rb +87 -0
- data/lib/ruby-push-notifications/mpns/mpns_notification.rb +94 -0
- data/lib/ruby-push-notifications/mpns/mpns_pusher.rb +33 -0
- data/lib/ruby-push-notifications/mpns/mpns_response.rb +82 -0
- data/lib/ruby-push-notifications/mpns/mpns_result.rb +182 -0
- data/lib/ruby-push-notifications/notification_results_manager.rb +14 -0
- data/lib/ruby-push-notifications/wns.rb +6 -0
- data/lib/ruby-push-notifications/wns/wns_access.rb +82 -0
- data/lib/ruby-push-notifications/wns/wns_connection.rb +97 -0
- data/lib/ruby-push-notifications/wns/wns_notification.rb +101 -0
- data/lib/ruby-push-notifications/wns/wns_pusher.rb +32 -0
- data/lib/ruby-push-notifications/wns/wns_response.rb +83 -0
- data/lib/ruby-push-notifications/wns/wns_result.rb +208 -0
- data/ruby-push-notifications.gemspec +28 -0
- data/spec/factories.rb +17 -0
- data/spec/factories/notifications.rb +30 -0
- data/spec/ruby-push-notifications/apns/apns_connection_spec.rb +92 -0
- data/spec/ruby-push-notifications/apns/apns_notification_spec.rb +42 -0
- data/spec/ruby-push-notifications/apns/apns_pusher_spec.rb +295 -0
- data/spec/ruby-push-notifications/gcm/gcm_connection_spec.rb +46 -0
- data/spec/ruby-push-notifications/gcm/gcm_notification_spec.rb +37 -0
- data/spec/ruby-push-notifications/gcm/gcm_pusher_spec.rb +45 -0
- data/spec/ruby-push-notifications/gcm/gcm_response_spec.rb +82 -0
- data/spec/ruby-push-notifications/mpns/mpns_connection_spec.rb +46 -0
- data/spec/ruby-push-notifications/mpns/mpns_notification_spec.rb +53 -0
- data/spec/ruby-push-notifications/mpns/mpns_pusher_spec.rb +59 -0
- data/spec/ruby-push-notifications/mpns/mpns_response_spec.rb +64 -0
- data/spec/ruby-push-notifications/wns/wns_access_spec.rb +76 -0
- data/spec/ruby-push-notifications/wns/wns_connection_spec.rb +53 -0
- data/spec/ruby-push-notifications/wns/wns_notification_spec.rb +177 -0
- data/spec/ruby-push-notifications/wns/wns_pusher_spec.rb +58 -0
- data/spec/ruby-push-notifications/wns/wns_response_spec.rb +65 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/support/dummy.pem +44 -0
- data/spec/support/factory_girl.rb +5 -0
- data/spec/support/results_shared_examples.rb +31 -0
- metadata +249 -0
data/spec/factories.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
sequence :apns_token do |i|
|
3
|
+
"ce8be627 2e43e855 16033e24 b4c28922 0eeda487 9c477160 b2545e95 b68b596#{i}"
|
4
|
+
end
|
5
|
+
|
6
|
+
sequence :gcm_registration_id do |i|
|
7
|
+
"APA91bHPRgkF3JUikC4ENAHEeMrd41Zxv3hVZjC9KtT8OvPVGJ-hQMRKRrZuJAEcl7B338qju59zJMjw2DELjzEvxwYv7hH5Ynpc1ODQ0aT4U4OFEeco8ohsN5PjL1iC2dNtk2BAokeMCg2ZXKqpc8FXKmhX94kIxQ#{i}"
|
8
|
+
end
|
9
|
+
|
10
|
+
sequence :mpns_device_url do |i|
|
11
|
+
"http://s.notify.live.net/u/1/bn1/HmQAAACP-0esPuxBSkzBNNXH4W0lV3lK-stEw6eRfpXX39uYbM7IwehXOTO9pRBjaaGECWOdD_7x5j5U4w4iXG4hGxer/d2luZG93c3Bob25lZGVmYXVsdA/EMDhx32Q5BG0DWnZpuVX1g/kRFAu0-jnhMQ-HG94rXzrbb0wQk#{i}"
|
12
|
+
end
|
13
|
+
|
14
|
+
sequence :wns_device_url do |i|
|
15
|
+
"https://hk2.notify.windows.com/?token=AwYAAABe%2bpjShu%2fzcVaaf1NPm%2b2dpiosm7RnmBJGMVkBDiYNXpAEp0mETldEu8axFoamgwb%2fdKCuNSfGGDHZ3RcaO2fcNGfxC6Y4Yp3xTFkDOhv5kNfgSXef7pSP0uwueIpqbWI%3d#{i}"
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :apns_notification, class: 'RubyPushNotifications::APNS::APNSNotification' do
|
3
|
+
tokens { [generate(:apns_token)] }
|
4
|
+
data a: 1
|
5
|
+
|
6
|
+
initialize_with { new tokens, data }
|
7
|
+
end
|
8
|
+
|
9
|
+
factory :gcm_notification, class: 'RubyPushNotifications::GCM::GCMNotification' do
|
10
|
+
registration_ids { [generate(:gcm_registration_id)] }
|
11
|
+
data a: 1
|
12
|
+
|
13
|
+
initialize_with { new registration_ids, data }
|
14
|
+
end
|
15
|
+
|
16
|
+
factory :mpns_notification, class: 'RubyPushNotifications::MPNS::MPNSNotification' do
|
17
|
+
device_urls { [generate(:mpns_device_url)] }
|
18
|
+
data message: { value1: 'hello' }
|
19
|
+
|
20
|
+
initialize_with { new device_urls, data }
|
21
|
+
end
|
22
|
+
|
23
|
+
factory :wns_notification, class: 'RubyPushNotifications::WNS::WNSNotification' do
|
24
|
+
device_urls { [generate(:wns_device_url)] }
|
25
|
+
data message: { value1: 'hello' }
|
26
|
+
|
27
|
+
initialize_with { new device_urls, data }
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
|
2
|
+
module RubyPushNotifications
|
3
|
+
module APNS
|
4
|
+
describe APNSConnection do
|
5
|
+
|
6
|
+
let(:cert) { File.read 'spec/support/dummy.pem' }
|
7
|
+
let(:tcp_socket) { instance_double(Socket).as_null_object }
|
8
|
+
let(:ssl_socket) { instance_double(OpenSSL::SSL::SSLSocket).as_null_object }
|
9
|
+
|
10
|
+
describe '::open' do
|
11
|
+
before do
|
12
|
+
allow(Socket).to receive(:tcp).with('gateway.sandbox.push.apple.com', 2195, nil, nil, { connect_timeout: 30 }).and_return tcp_socket
|
13
|
+
allow(OpenSSL::SSL::SSLSocket).to receive(:new).with(tcp_socket, an_instance_of(OpenSSL::SSL::SSLContext)).and_return ssl_socket
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'creates the connection' do
|
17
|
+
expect(Socket).to receive(:tcp).with('gateway.sandbox.push.apple.com', 2195, nil, nil, { connect_timeout: 30 }).and_return tcp_socket
|
18
|
+
expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(tcp_socket, an_instance_of(OpenSSL::SSL::SSLContext)).and_return ssl_socket
|
19
|
+
APNSConnection.open cert, true
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'returns an instance of APNSConnection' do
|
23
|
+
expect(APNSConnection.open(cert, true)).to be_a APNSConnection
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'sets the password for pem file' do
|
27
|
+
expect(OpenSSL::SSL::SSLSocket).to receive(:new).with(tcp_socket, an_instance_of(OpenSSL::SSL::SSLContext)).and_return ssl_socket
|
28
|
+
expect(OpenSSL::PKey::RSA).to receive(:new).with(cert, 'password')
|
29
|
+
expect(APNSConnection.open(cert, true, 'password')).to be_a APNSConnection
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when :host option is present' do
|
33
|
+
it 'opens a connection with a custom APNS' do
|
34
|
+
expect(Socket).to receive(:tcp).with('gateway.push.example.com', 2195, nil, nil, { connect_timeout: 30 }).and_return tcp_socket
|
35
|
+
APNSConnection.open cert, true, 'password', { host: "gateway.push.example.com" }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe '#close' do
|
41
|
+
let(:connection) { APNSConnection.new tcp_socket, ssl_socket }
|
42
|
+
|
43
|
+
it 'closes the ssl socket' do
|
44
|
+
expect(ssl_socket).to receive(:close)
|
45
|
+
connection.close
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'closes the tcp socket' do
|
49
|
+
expect(tcp_socket).to receive(:close)
|
50
|
+
connection.close
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#write' do
|
55
|
+
let(:connection) { APNSConnection.new tcp_socket, ssl_socket }
|
56
|
+
let(:contents_string) { 'the contents string' }
|
57
|
+
|
58
|
+
it 'writes the ssl socket' do
|
59
|
+
expect(ssl_socket).to receive(:write).with contents_string
|
60
|
+
connection.write contents_string
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#read' do
|
65
|
+
let(:connection) { APNSConnection.new tcp_socket, ssl_socket }
|
66
|
+
|
67
|
+
it 'writes the ssl socket' do
|
68
|
+
expect(ssl_socket).to receive(:read).with 6
|
69
|
+
connection.read 6
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe '#flush' do
|
74
|
+
let(:connection) { APNSConnection.new tcp_socket, ssl_socket }
|
75
|
+
|
76
|
+
it 'flushes the ssl socket' do
|
77
|
+
expect(ssl_socket).to receive :flush
|
78
|
+
connection.flush
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe 'IO behavior' do
|
83
|
+
let(:connection) { APNSConnection.new tcp_socket, ssl_socket }
|
84
|
+
|
85
|
+
it 'can be selected' do
|
86
|
+
allow(ssl_socket).to receive(:to_io).and_return IO.new(IO.sysopen('/dev/null'))
|
87
|
+
IO.select [connection]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
|
2
|
+
module RubyPushNotifications
|
3
|
+
module APNS
|
4
|
+
describe APNSNotification do
|
5
|
+
|
6
|
+
let(:device_tokens) { ['12', '34'] }
|
7
|
+
let(:data) { { a: 1 } }
|
8
|
+
let(:notification) { APNSNotification.new device_tokens, data }
|
9
|
+
let(:notif_id) { 1 }
|
10
|
+
|
11
|
+
it 'successfully creates the apns binary' do
|
12
|
+
json = JSON.dump data
|
13
|
+
expect do |b|
|
14
|
+
notification.each_message notif_id, &b
|
15
|
+
end.to yield_successive_args apns_binary(json, device_tokens[0], notif_id), apns_binary(json, device_tokens[1], notif_id + 1)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'caches the payload' do
|
19
|
+
expect(JSON).to receive(:dump).with(data).once.and_return 'dummy string'
|
20
|
+
allow(data).to receive(:respond_to?).with(:to_json).and_return(false)
|
21
|
+
notification.each_message(notif_id) {}
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'validates the data'
|
25
|
+
|
26
|
+
it 'validates the tokens'
|
27
|
+
|
28
|
+
it_behaves_like 'a proper results manager' do
|
29
|
+
let(:success_count) { 2 }
|
30
|
+
let(:failures_count) { 1 }
|
31
|
+
let(:individual_results) do
|
32
|
+
[
|
33
|
+
NO_ERROR_STATUS_CODE,
|
34
|
+
PROCESSING_ERROR_STATUS_CODE,
|
35
|
+
NO_ERROR_STATUS_CODE
|
36
|
+
]
|
37
|
+
end
|
38
|
+
let(:results) { APNSResults.new individual_results }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,295 @@
|
|
1
|
+
module RubyPushNotifications
|
2
|
+
module APNS
|
3
|
+
describe APNSPusher do
|
4
|
+
|
5
|
+
let(:sandbox) { true }
|
6
|
+
let(:certificate) { 'abc' }
|
7
|
+
let(:pusher) { APNSPusher.new certificate, sandbox }
|
8
|
+
let(:connection) { instance_double(APNSConnection).as_null_object }
|
9
|
+
let(:data) { { a: 1 } }
|
10
|
+
|
11
|
+
before do
|
12
|
+
allow(APNSConnection).to receive(:open).with(certificate, sandbox, nil, {}).and_return connection
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#push' do
|
16
|
+
|
17
|
+
context 'a single notification' do
|
18
|
+
|
19
|
+
context 'containing a single destination' do
|
20
|
+
|
21
|
+
let(:token) { generate :apns_token }
|
22
|
+
let(:notification) { build :apns_notification, data: data, tokens: [token] }
|
23
|
+
|
24
|
+
describe 'success' do
|
25
|
+
|
26
|
+
before { allow(IO).to receive(:select).and_return [] }
|
27
|
+
|
28
|
+
it 'writes the notification to the socket' do
|
29
|
+
expect(connection).to receive(:write).with apns_binary(data, token, 0)
|
30
|
+
pusher.push [notification]
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'flushes the socket contents' do
|
34
|
+
expect(connection).to receive(:flush)
|
35
|
+
pusher.push [notification]
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'results' do
|
39
|
+
before { pusher.push [notification] }
|
40
|
+
|
41
|
+
include_examples 'right results', 1, 0, [NO_ERROR_STATUS_CODE]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'failure' do
|
46
|
+
|
47
|
+
before do
|
48
|
+
allow(IO).to receive(:select).and_return [[connection]]
|
49
|
+
allow(connection).to receive(:read).with(6).and_return [8, PROCESSING_ERROR_STATUS_CODE, 0].pack 'ccN'
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'does not retry' do
|
53
|
+
expect(connection).to receive(:write).with(apns_binary(data, token, 0)).once
|
54
|
+
pusher.push [notification]
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'results' do
|
58
|
+
before { pusher.push [notification] }
|
59
|
+
|
60
|
+
include_examples 'right results', 0, 1, [PROCESSING_ERROR_STATUS_CODE]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'containing several destinations' do
|
66
|
+
let(:tokens) { [generate(:apns_token), generate(:apns_token)] }
|
67
|
+
let(:notification) { build :apns_notification, data: data, tokens: tokens }
|
68
|
+
|
69
|
+
describe 'success' do
|
70
|
+
|
71
|
+
before { allow(IO).to receive(:select).and_return [] }
|
72
|
+
|
73
|
+
it 'writes the messages to the socket' do
|
74
|
+
expect(connection).to receive(:write).with apns_binary(data, tokens[0], 0)
|
75
|
+
expect(connection).to receive(:write).with apns_binary(data, tokens[1], 1)
|
76
|
+
pusher.push [notification]
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'flushes the socket contents' do
|
80
|
+
expect(connection).to receive(:flush).once
|
81
|
+
pusher.push [notification]
|
82
|
+
end
|
83
|
+
|
84
|
+
describe 'results' do
|
85
|
+
before { pusher.push [notification] }
|
86
|
+
|
87
|
+
include_examples 'right results', 2, 0, [NO_ERROR_STATUS_CODE] * 2
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe 'failure' do
|
92
|
+
|
93
|
+
let(:connection2) { instance_double(APNSConnection).as_null_object }
|
94
|
+
|
95
|
+
before do
|
96
|
+
allow(APNSConnection).to receive(:open).with(certificate, sandbox, nil, {}).and_return connection, connection2
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'failing first' do
|
100
|
+
before do
|
101
|
+
allow(IO).to receive(:select).and_return [[connection]], []
|
102
|
+
allow(connection).to receive(:read).with(6).and_return [8, PROCESSING_ERROR_STATUS_CODE, 0].pack 'ccN'
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'sends the each notification once and to the expected connection instance' do
|
106
|
+
expect(connection).to receive(:write).with(apns_binary(data, tokens[0], 0)).once
|
107
|
+
expect(connection2).to receive(:write).with(apns_binary(data, tokens[1], 1)).once
|
108
|
+
pusher.push [notification]
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'results' do
|
112
|
+
before { pusher.push [notification] }
|
113
|
+
|
114
|
+
include_examples 'right results', 1, 1, [PROCESSING_ERROR_STATUS_CODE, NO_ERROR_STATUS_CODE]
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
context 'failing first but delayed error' do
|
119
|
+
before do
|
120
|
+
allow(IO).to receive(:select).and_return [], [[connection]], []
|
121
|
+
allow(connection).to receive(:read).with(6).and_return [8, PROCESSING_ERROR_STATUS_CODE, 0].pack 'ccN'
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'sends the second notification twice' do
|
125
|
+
expect(connection).to receive(:write).with(apns_binary(data, tokens[0], 0)).once
|
126
|
+
expect(connection).to receive(:write).with(apns_binary(data, tokens[1], 1)).once
|
127
|
+
expect(connection2).to receive(:write).with(apns_binary(data, tokens[1], 1)).once
|
128
|
+
pusher.push [notification]
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'results' do
|
132
|
+
before { pusher.push [notification] }
|
133
|
+
|
134
|
+
include_examples 'right results', 1, 1, [PROCESSING_ERROR_STATUS_CODE, NO_ERROR_STATUS_CODE]
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
context 'failing last' do
|
139
|
+
before do
|
140
|
+
allow(IO).to receive(:select).and_return [], [[connection]]
|
141
|
+
allow(connection).to receive(:read).with(6).and_return [8, PROCESSING_ERROR_STATUS_CODE, 1].pack 'ccN'
|
142
|
+
end
|
143
|
+
|
144
|
+
it 'sends the second notification just once' do
|
145
|
+
expect(connection).to receive(:write).with(apns_binary(data, tokens[0], 0)).once
|
146
|
+
expect(connection).to receive(:write).with(apns_binary(data, tokens[1], 1)).once
|
147
|
+
expect(connection2).to_not receive(:write)
|
148
|
+
pusher.push [notification]
|
149
|
+
end
|
150
|
+
|
151
|
+
describe 'results' do
|
152
|
+
before { pusher.push [notification] }
|
153
|
+
|
154
|
+
include_examples 'right results', 1, 1, [NO_ERROR_STATUS_CODE, PROCESSING_ERROR_STATUS_CODE]
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'several notifications' do
|
162
|
+
let(:tokens) { (0...10).map { generate:apns_token } }
|
163
|
+
let(:notifications) { tokens.map { |token| build :apns_notification, data: data, tokens: [token] } }
|
164
|
+
|
165
|
+
describe 'success' do
|
166
|
+
|
167
|
+
before { allow(IO).to receive(:select).and_return [] }
|
168
|
+
|
169
|
+
it 'writes the notifications to the socket' do
|
170
|
+
notifications.each_with_index do |notification, i|
|
171
|
+
expect(connection).to receive(:write).with(apns_binary(data, tokens[i], i)).once
|
172
|
+
end
|
173
|
+
pusher.push notifications
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'flushes the socket contents' do
|
177
|
+
expect(connection).to receive(:flush).once
|
178
|
+
pusher.push notifications
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'saves results' do
|
182
|
+
pusher.push notifications
|
183
|
+
expect(notifications.map(&:individual_results)).to eq [[NO_ERROR_STATUS_CODE]] * 10
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe 'failure' do
|
188
|
+
|
189
|
+
context 'several async failures' do
|
190
|
+
|
191
|
+
let(:connection2) { instance_double(APNSConnection).as_null_object }
|
192
|
+
let(:connection3) { instance_double(APNSConnection).as_null_object }
|
193
|
+
let(:connection4) { instance_double(APNSConnection).as_null_object }
|
194
|
+
|
195
|
+
before do
|
196
|
+
allow(IO).to receive(:select).and_return [], [], [[connection]], [], [], [[connection2]], [], [], [], [], [], [], [[connection3]]
|
197
|
+
allow(connection).to receive(:read).with(6).and_return [8, PROCESSING_ERROR_STATUS_CODE, 0].pack('ccN')
|
198
|
+
allow(connection2).to receive(:read).with(6).and_return [8, MISSING_DEVICE_TOKEN_STATUS_CODE, 2].pack('ccN')
|
199
|
+
allow(connection3).to receive(:read).with(6).and_return [8, INVALID_TOPIC_SIZE_STATUS_CODE, 9].pack('ccN')
|
200
|
+
allow(APNSConnection).to receive(:open).with(certificate, sandbox, nil, {}).and_return connection, connection2, connection3, connection4
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'reopens the connection' do
|
204
|
+
(0..2).each do |i|
|
205
|
+
expect(connection).to receive(:write).with(apns_binary(data, tokens[i], i)).once
|
206
|
+
end
|
207
|
+
expect(connection).to_not receive(:write).with apns_binary(data, tokens[3], 3)
|
208
|
+
|
209
|
+
expect(connection2).to_not receive(:write).with apns_binary(data, tokens[0], 0)
|
210
|
+
(1..3).each do |i|
|
211
|
+
expect(connection2).to receive(:write).with(apns_binary(data, tokens[i], i)).once
|
212
|
+
end
|
213
|
+
expect(connection2).to_not receive(:write).with apns_binary(data, tokens[4], 4)
|
214
|
+
|
215
|
+
expect(connection3).to_not receive(:write).with apns_binary(data, tokens[2], 2)
|
216
|
+
(3..9).each do |i|
|
217
|
+
expect(connection3).to receive(:write).with(apns_binary(data, tokens[i], i)).once
|
218
|
+
end
|
219
|
+
|
220
|
+
expect(connection4).to_not receive :write
|
221
|
+
pusher.push notifications
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'saves the statuses' do
|
225
|
+
pusher.push notifications
|
226
|
+
expect(notifications.map(&:individual_results)).to eq [
|
227
|
+
[PROCESSING_ERROR_STATUS_CODE],
|
228
|
+
[NO_ERROR_STATUS_CODE],
|
229
|
+
[MISSING_DEVICE_TOKEN_STATUS_CODE],
|
230
|
+
[NO_ERROR_STATUS_CODE],
|
231
|
+
[NO_ERROR_STATUS_CODE],
|
232
|
+
[NO_ERROR_STATUS_CODE],
|
233
|
+
[NO_ERROR_STATUS_CODE],
|
234
|
+
[NO_ERROR_STATUS_CODE],
|
235
|
+
[NO_ERROR_STATUS_CODE],
|
236
|
+
[INVALID_TOPIC_SIZE_STATUS_CODE]
|
237
|
+
]
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
context 'several sync failures' do
|
242
|
+
|
243
|
+
let(:connection2) { instance_double(APNSConnection).as_null_object }
|
244
|
+
let(:connection3) { instance_double(APNSConnection).as_null_object }
|
245
|
+
let(:connection4) { instance_double(APNSConnection).as_null_object }
|
246
|
+
|
247
|
+
before do
|
248
|
+
allow(IO).to receive(:select).and_return [[connection]], [], [[connection2]], [], [], [], [], [], [], [[connection3]]
|
249
|
+
allow(connection).to receive(:read).with(6).and_return [8, PROCESSING_ERROR_STATUS_CODE, 0].pack('ccN')
|
250
|
+
allow(connection2).to receive(:read).with(6).and_return [8, MISSING_DEVICE_TOKEN_STATUS_CODE, 2].pack('ccN')
|
251
|
+
allow(connection3).to receive(:read).with(6).and_return [8, INVALID_TOPIC_SIZE_STATUS_CODE, 9].pack('ccN')
|
252
|
+
allow(APNSConnection).to receive(:open).with(certificate, sandbox, nil, {}).and_return connection, connection2, connection3, connection4
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'repones the connection' do
|
256
|
+
expect(connection).to receive(:write).with(apns_binary(data, tokens[0], 0)).once
|
257
|
+
expect(connection).to_not receive(:write).with apns_binary(data, tokens[1], 1)
|
258
|
+
|
259
|
+
expect(connection2).to_not receive(:write).with apns_binary(data, tokens[0], 0)
|
260
|
+
(1..2).each do |i|
|
261
|
+
expect(connection2).to receive(:write).with(apns_binary(data, tokens[i], i)).once
|
262
|
+
end
|
263
|
+
expect(connection2).to_not receive(:write).with apns_binary(data, tokens[3], 3)
|
264
|
+
|
265
|
+
expect(connection3).to_not receive(:write).with apns_binary(data, tokens[2], 2)
|
266
|
+
(3..9).each do |i|
|
267
|
+
expect(connection3).to receive(:write).with(apns_binary(data, tokens[i], i)).once
|
268
|
+
end
|
269
|
+
|
270
|
+
expect(connection4).to_not receive :write
|
271
|
+
pusher.push notifications
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'saves the statuses' do
|
275
|
+
pusher.push notifications
|
276
|
+
expect(notifications.map(&:individual_results)).to eq [
|
277
|
+
[PROCESSING_ERROR_STATUS_CODE],
|
278
|
+
[NO_ERROR_STATUS_CODE],
|
279
|
+
[MISSING_DEVICE_TOKEN_STATUS_CODE],
|
280
|
+
[NO_ERROR_STATUS_CODE],
|
281
|
+
[NO_ERROR_STATUS_CODE],
|
282
|
+
[NO_ERROR_STATUS_CODE],
|
283
|
+
[NO_ERROR_STATUS_CODE],
|
284
|
+
[NO_ERROR_STATUS_CODE],
|
285
|
+
[NO_ERROR_STATUS_CODE],
|
286
|
+
[INVALID_TOPIC_SIZE_STATUS_CODE]
|
287
|
+
]
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|