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
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
module RubyPushNotifications
|
3
|
+
module GCM
|
4
|
+
describe GCMConnection do
|
5
|
+
|
6
|
+
describe '::post' do
|
7
|
+
|
8
|
+
let(:body) { 'abc' }
|
9
|
+
let(:key) { 'def' }
|
10
|
+
let(:response) { JSON.dump a: 1 }
|
11
|
+
|
12
|
+
before do
|
13
|
+
stub_request(:post, 'https://android.googleapis.com/gcm/send').
|
14
|
+
to_return status: [200, 'OK'], body: response
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'runs the right request' do
|
18
|
+
GCMConnection.post body, key
|
19
|
+
|
20
|
+
expect(WebMock).
|
21
|
+
to have_requested(:post, 'https://android.googleapis.com/gcm/send').
|
22
|
+
with(body: body, headers: { 'Content-Type' => 'application/json', 'Authorization' => "key=#{key}" }).
|
23
|
+
once
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when :url option is present' do
|
27
|
+
it 'posts data to a custom GCM endpoint' do
|
28
|
+
stub_request(:post, 'https://example.com/gcm/send').
|
29
|
+
to_return status: [200, 'OK'], body: response
|
30
|
+
|
31
|
+
GCMConnection.post body, key, url: 'https://example.com/gcm/send'
|
32
|
+
|
33
|
+
expect(WebMock).
|
34
|
+
to have_requested(:post, 'https://example.com/gcm/send').
|
35
|
+
with(body: body, headers: { 'Content-Type' => 'application/json', 'Authorization' => "key=#{key}" }).
|
36
|
+
once
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'returns the response encapsulated in a GCMResponse object' do
|
41
|
+
expect(GCMConnection.post body, key).to eq GCMResponse.new(200, response)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
module RubyPushNotifications
|
3
|
+
module GCM
|
4
|
+
describe GCMNotification do
|
5
|
+
|
6
|
+
let(:registration_ids) { %w(a b c) }
|
7
|
+
let(:data) { { a: 1 } }
|
8
|
+
let(:notification) { build :gcm_notification, registration_ids: registration_ids, data: data }
|
9
|
+
|
10
|
+
it 'builds the right gcm json' do
|
11
|
+
expect(notification.as_gcm_json).to eq JSON.dump(
|
12
|
+
registration_ids: registration_ids,
|
13
|
+
data: data
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'validates the registration_ids format'
|
18
|
+
|
19
|
+
# According to https://developer.android.com/google/gcm/server-ref.html#table1
|
20
|
+
it 'validates the data'
|
21
|
+
|
22
|
+
it_behaves_like 'a proper results manager' do
|
23
|
+
let(:success_count) { 2 }
|
24
|
+
let(:failures_count) { 1 }
|
25
|
+
let(:canonical_id) { 'abcd' }
|
26
|
+
let(:individual_results) { [GCMCanonicalIDResult.new(canonical_id)] }
|
27
|
+
let(:results) do
|
28
|
+
GCMResponse.new 200, JSON.dump(
|
29
|
+
success: success_count, failure: failures_count, results: [
|
30
|
+
registration_id: canonical_id
|
31
|
+
]
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
|
2
|
+
module RubyPushNotifications
|
3
|
+
module GCM
|
4
|
+
describe GCMPusher do
|
5
|
+
|
6
|
+
let(:gcm_key) { 'gcm key' }
|
7
|
+
let(:pusher) { GCMPusher.new gcm_key }
|
8
|
+
|
9
|
+
describe '#push' do
|
10
|
+
|
11
|
+
let(:notif1) { build :gcm_notification }
|
12
|
+
let(:notif2) { build :gcm_notification }
|
13
|
+
let(:response) { JSON.dump a: 1 }
|
14
|
+
|
15
|
+
before do
|
16
|
+
stub_request(:post, 'https://android.googleapis.com/gcm/send').
|
17
|
+
to_return status: [200, 'OK'], body: response
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'submits every notification' do
|
21
|
+
pusher.push [notif1, notif2]
|
22
|
+
|
23
|
+
expect(WebMock).
|
24
|
+
to have_requested(:post, 'https://android.googleapis.com/gcm/send').
|
25
|
+
with(body: notif1.as_gcm_json, headers: { 'Content-Type' => 'application/json', 'Authorization' => "key=#{gcm_key}" }).
|
26
|
+
once
|
27
|
+
|
28
|
+
expect(WebMock).
|
29
|
+
to have_requested(:post, 'https://android.googleapis.com/gcm/send').
|
30
|
+
with(body: notif2.as_gcm_json, headers: { 'Content-Type' => 'application/json', 'Authorization' => "key=#{gcm_key}" }).
|
31
|
+
once
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'sets results to notifications' do
|
35
|
+
expect do
|
36
|
+
pusher.push [notif1, notif2]
|
37
|
+
end.to change { [notif1, notif2].map &:results }.from([nil, nil]).to [GCMResponse.new(200, response)]*2
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'splits notifications with more than 1000 destinations in parts'
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
|
2
|
+
module RubyPushNotifications
|
3
|
+
module GCM
|
4
|
+
describe GCMResponse do
|
5
|
+
|
6
|
+
describe 'success' do
|
7
|
+
|
8
|
+
let(:successful_messages) { 3 }
|
9
|
+
let(:failed_messages) { 1 }
|
10
|
+
let(:canonical_ids) { 2 }
|
11
|
+
let(:body) { JSON.dump(
|
12
|
+
multicast_id: 123456789,
|
13
|
+
success: successful_messages,
|
14
|
+
failure: failed_messages,
|
15
|
+
canonical_ids: canonical_ids,
|
16
|
+
results: [
|
17
|
+
{ message_id: 1,
|
18
|
+
registration_id: 'new_reg_id' },
|
19
|
+
{ message_id: 2,
|
20
|
+
registration_id: 'new_reg_id_2' },
|
21
|
+
{ message_id: 3 },
|
22
|
+
{ message_id: 4,
|
23
|
+
error: 'NotRegistered' }
|
24
|
+
]
|
25
|
+
) }
|
26
|
+
|
27
|
+
let(:response) { GCMResponse.new 200, body }
|
28
|
+
|
29
|
+
it 'parses the number of successfully processed notifications' do
|
30
|
+
expect(response.success).to eq successful_messages
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'parses the number of failed messages' do
|
34
|
+
expect(response.failed).to eq failed_messages
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'parses the number of canonical ids received' do
|
38
|
+
expect(response.canonical_ids).to eq canonical_ids
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'parses the results' do
|
42
|
+
expect(response.results).to eq [GCMCanonicalIDResult.new('new_reg_id'), GCMCanonicalIDResult.new('new_reg_id_2'), GCMResultOK.new, GCMResultError.new('NotRegistered')]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'errors' do
|
47
|
+
let(:dummy_response_body) { 'dummy response body' }
|
48
|
+
describe '400 Bad Request error code' do
|
49
|
+
it 'raises a MalformedGCMJSONError' do
|
50
|
+
expect do
|
51
|
+
GCMResponse.new 400, dummy_response_body
|
52
|
+
end.to raise_error MalformedGCMJSONError, dummy_response_body
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '401 Unauthorized error code' do
|
57
|
+
it 'raises a GCMAuthError' do
|
58
|
+
expect do
|
59
|
+
GCMResponse.new 401, dummy_response_body
|
60
|
+
end.to raise_error GCMAuthError, dummy_response_body
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '500 Internal Server Error error code' do
|
65
|
+
it 'raises a GCMInternalError' do
|
66
|
+
expect do
|
67
|
+
GCMResponse.new 500, dummy_response_body
|
68
|
+
end.to raise_error GCMInternalError, dummy_response_body
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '302 Found error code' do
|
73
|
+
it 'raises a UnexpectedGCMResponseError' do
|
74
|
+
expect do
|
75
|
+
GCMResponse.new 302, dummy_response_body
|
76
|
+
end.to raise_error UnexpectedGCMResponseError, '302'
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
|
2
|
+
module RubyPushNotifications
|
3
|
+
module MPNS
|
4
|
+
describe MPNSConnection do
|
5
|
+
|
6
|
+
describe '::post' do
|
7
|
+
|
8
|
+
let(:body) { 'abc' }
|
9
|
+
let(:headers) {
|
10
|
+
{
|
11
|
+
'x-notificationstatus' => 'Received',
|
12
|
+
'x-deviceconnectionstatus' => 'Connected',
|
13
|
+
'x-subscriptionstatus' => 'Active'
|
14
|
+
}
|
15
|
+
}
|
16
|
+
let(:device_urls) { [generate(:mpns_device_url)] }
|
17
|
+
let(:toast_data) { { title: 'Title', message: 'Hello MPNS World!', type: :toast } }
|
18
|
+
let(:toast_notification) { build :mpns_notification, device_urls: device_urls, data: toast_data }
|
19
|
+
|
20
|
+
before do
|
21
|
+
stub_request(:post, %r{s.notify.live.net}).
|
22
|
+
to_return status: [200, 'OK'], body: body, headers: headers
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'runs the right request' do
|
26
|
+
MPNSConnection.post toast_notification
|
27
|
+
|
28
|
+
expect(WebMock).
|
29
|
+
to have_requested(:post, toast_notification.device_urls[0]).
|
30
|
+
with(body: toast_notification.as_mpns_xml, headers: { 'Content-Type' => 'text/xml', 'X-NotificationClass' => '2', 'X-WindowsPhone-Target' => :toast}).
|
31
|
+
once
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'returns the response encapsulated in a Hash object' do
|
35
|
+
responses = [
|
36
|
+
{ device_url: toast_notification.device_urls[0],
|
37
|
+
headers: headers,
|
38
|
+
code: 200
|
39
|
+
}
|
40
|
+
]
|
41
|
+
expect(MPNSConnection.post toast_notification).to eq MPNSResponse.new(responses)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
|
2
|
+
module RubyPushNotifications
|
3
|
+
module MPNS
|
4
|
+
describe MPNSNotification do
|
5
|
+
|
6
|
+
let(:device_urls) { %w(a b c) }
|
7
|
+
let(:raw_notification) { build :mpns_notification }
|
8
|
+
let(:toast_data) { { title: 'Title', message: 'Hello MPNS World!', type: :toast } }
|
9
|
+
let(:toast_notification) { build :mpns_notification, device_urls: device_urls, data: toast_data }
|
10
|
+
let(:tile_data) { { count: 1, title: 'Hello MPNS World!', type: :tile } }
|
11
|
+
let(:tile_notification) { build :mpns_notification, device_urls: device_urls, data: tile_data }
|
12
|
+
|
13
|
+
it 'builds the right mpns raw xml' do
|
14
|
+
xml = '<?xml version="1.0" encoding="UTF-8"?>'
|
15
|
+
xml << '<root><value1>hello</value1></root>'
|
16
|
+
expect(raw_notification.as_mpns_xml).to eq xml
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'builds the right mpns toast xml' do
|
20
|
+
xml = '<?xml version="1.0" encoding="UTF-8"?>'
|
21
|
+
xml << '<wp:Notification xmlns:wp="WPNotification"><wp:Toast>'
|
22
|
+
xml << '<wp:Text1>Title</wp:Text1>'
|
23
|
+
xml << '<wp:Text2>Hello MPNS World!</wp:Text2>'
|
24
|
+
xml << '</wp:Toast></wp:Notification>'
|
25
|
+
expect(toast_notification.as_mpns_xml).to eq xml
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'builds the right mpns tile xml' do
|
29
|
+
xml = '<?xml version="1.0" encoding="UTF-8"?>'
|
30
|
+
xml << '<wp:Notification xmlns:wp="WPNotification"><wp:Tile>'
|
31
|
+
xml << '<wp:Count>1</wp:Count>'
|
32
|
+
xml << '<wp:Title>Hello MPNS World!</wp:Title>'
|
33
|
+
xml << '</wp:Tile></wp:Notification>'
|
34
|
+
expect(tile_notification.as_mpns_xml).to eq xml
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'validates the mpns format'
|
38
|
+
|
39
|
+
it 'validates the data'
|
40
|
+
|
41
|
+
it_behaves_like 'a proper results manager' do
|
42
|
+
let(:notification) { build :mpns_notification }
|
43
|
+
let(:success_count) { 1 }
|
44
|
+
let(:failures_count) { 0 }
|
45
|
+
let(:device_url) { generate :mpns_device_url }
|
46
|
+
let(:individual_results) { [MPNSResultOK.new(device_url, {})] }
|
47
|
+
let(:results) do
|
48
|
+
MPNSResponse.new [{ code: 200, device_url: device_url, headers: {} }]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
|
2
|
+
module RubyPushNotifications
|
3
|
+
module MPNS
|
4
|
+
describe MPNSPusher do
|
5
|
+
|
6
|
+
let(:pusher) { MPNSPusher.new }
|
7
|
+
|
8
|
+
describe '#push' do
|
9
|
+
|
10
|
+
let(:device_urls) { [generate(:mpns_device_url)] }
|
11
|
+
let(:notif1) { build :mpns_notification, device_urls: ['http://s.notify.live.net/1'], data: { message: { value1: 'hello' } } }
|
12
|
+
let(:notif2) { build :mpns_notification, device_urls: ['http://s.notify.live.net/1'], data: { message: { value1: 'hello' } } }
|
13
|
+
let(:raw_notification) { build :mpns_notification }
|
14
|
+
let(:toast_data) { { title: 'Title', message: 'Hello MPNS World!', type: :toast } }
|
15
|
+
let(:toast_notification) { build :mpns_notification, device_urls: device_urls, data: toast_data }
|
16
|
+
let(:tile_data) { { count: 1, title: 'Hello MPNS World!', type: :tile } }
|
17
|
+
let(:tile_notification) { build :mpns_notification, device_urls: device_urls, data: tile_data }
|
18
|
+
let(:headers) {
|
19
|
+
{
|
20
|
+
'x-notificationstatus' => 'Received',
|
21
|
+
'x-deviceconnectionstatus' => 'Connected',
|
22
|
+
'x-subscriptionstatus' => 'Active'
|
23
|
+
}
|
24
|
+
}
|
25
|
+
let(:response) { [ { device_url: 'http://s.notify.live.net/1', headers: headers, code: 200 } ]}
|
26
|
+
|
27
|
+
before do
|
28
|
+
stub_request(:post, %r{s.notify.live.net}).
|
29
|
+
to_return status: [200, 'OK'], headers: headers
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'submits every notification' do
|
33
|
+
pusher.push [raw_notification, toast_notification, tile_notification]
|
34
|
+
expect(WebMock).
|
35
|
+
to have_requested(:post, raw_notification.device_urls[0]).
|
36
|
+
with(body: raw_notification.as_mpns_xml, headers: { 'Content-Type' => 'text/xml', 'X-NotificationClass' => '3'}).
|
37
|
+
once
|
38
|
+
|
39
|
+
expect(WebMock).
|
40
|
+
to have_requested(:post, toast_notification.device_urls[0]).
|
41
|
+
with(body: toast_notification.as_mpns_xml, headers: { 'Content-Type' => 'text/xml', 'X-NotificationClass' => '2', 'X-WindowsPhone-Target' => :toast}).
|
42
|
+
once
|
43
|
+
|
44
|
+
expect(WebMock).
|
45
|
+
to have_requested(:post, tile_notification.device_urls[0]).
|
46
|
+
with(body: tile_notification.as_mpns_xml, headers: { 'Content-Type' => 'text/xml', 'X-NotificationClass' => '1', 'X-WindowsPhone-Target' => 'token'}).
|
47
|
+
once
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'sets results to notifications' do
|
51
|
+
expect do
|
52
|
+
pusher.push [notif1, notif2]
|
53
|
+
end.to change { [notif1, notif2].map &:results }.from([nil, nil]).to [MPNSResponse.new(response)]*2
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
|
2
|
+
module RubyPushNotifications
|
3
|
+
module MPNS
|
4
|
+
describe MPNSResponse do
|
5
|
+
|
6
|
+
describe 'success' do
|
7
|
+
|
8
|
+
let(:successful_messages) { 2 }
|
9
|
+
let(:failed_messages) { 6 }
|
10
|
+
let(:headers) {
|
11
|
+
{
|
12
|
+
'x-notificationstatus' => 'Received',
|
13
|
+
'x-deviceconnectionstatus' => 'Connected',
|
14
|
+
'x-subscriptionstatus' => 'Active'
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
let(:responses) {
|
19
|
+
[
|
20
|
+
{ device_url: '1', headers: headers, code: 200 },
|
21
|
+
{ device_url: '2', headers: headers, code: 200 },
|
22
|
+
{ device_url: '3', code: 400 },
|
23
|
+
{ device_url: '4', code: 401 },
|
24
|
+
{ device_url: '5', headers: headers, code: 404 },
|
25
|
+
{ device_url: '6', headers: headers, code: 406 },
|
26
|
+
{ device_url: '7', headers: headers, code: 412 },
|
27
|
+
{ device_url: '8', code: 503 }
|
28
|
+
]
|
29
|
+
}
|
30
|
+
|
31
|
+
let(:response) { MPNSResponse.new responses }
|
32
|
+
let(:result) { MPNSResultOK.new '1', headers }
|
33
|
+
|
34
|
+
it 'parses the number of successfully processed notifications' do
|
35
|
+
expect(response.success).to eq successful_messages
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'parses the number of failed messages' do
|
39
|
+
expect(response.failed).to eq failed_messages
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'parses the results' do
|
43
|
+
expect(response.results).to eq [
|
44
|
+
MPNSResultOK.new('1', headers),
|
45
|
+
MPNSResultOK.new('2', headers),
|
46
|
+
MalformedMPNSResultError.new('3'),
|
47
|
+
MPNSAuthError.new('4'),
|
48
|
+
MPNSInvalidError.new('5', headers),
|
49
|
+
MPNSLimitError.new('6', headers),
|
50
|
+
MPNSPreConditionError.new('7', headers),
|
51
|
+
MPNSInternalError.new('8')
|
52
|
+
]
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'parses headers to result attributes' do
|
56
|
+
expect(result.notification_status).to eq 'Received'
|
57
|
+
expect(result.device_connection_status).to eq 'Connected'
|
58
|
+
expect(result.subscription_status).to eq 'Active'
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module RubyPushNotifications
|
2
|
+
module WNS
|
3
|
+
describe WNSAccess do
|
4
|
+
describe '::access_token' do
|
5
|
+
let(:sid) { 'sid' }
|
6
|
+
let(:secret) { 'secret' }
|
7
|
+
|
8
|
+
context 'when service return status OK' do
|
9
|
+
let(:body) {
|
10
|
+
"{\"token_type\":\"bearer\",\"access_token\":\"real_access_token\",\"expires_in\":86400}"
|
11
|
+
}
|
12
|
+
before do
|
13
|
+
stub_request(:post, "https://login.live.com/accesstoken.srf").
|
14
|
+
to_return status: [200, 'OK'], body: body
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'returns correct response' do
|
18
|
+
response = OpenStruct.new(
|
19
|
+
status_code: 200,
|
20
|
+
status: 'OK',
|
21
|
+
error: nil,
|
22
|
+
error_description: nil,
|
23
|
+
access_token: 'real_access_token',
|
24
|
+
token_ttl: 86400
|
25
|
+
)
|
26
|
+
expect(WNSAccess.new(sid, secret).get_token.response).to eq(response)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when service return an error' do
|
31
|
+
context 'when bad credentials' do
|
32
|
+
let(:body) {
|
33
|
+
"{\"error\":\"invalid_client\",\"error_description\":\"Invalid client id\"}"
|
34
|
+
}
|
35
|
+
before do
|
36
|
+
stub_request(:post, "https://login.live.com/accesstoken.srf").
|
37
|
+
to_return status: [400, 'Bad Request'], body: body
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'returns correct response' do
|
41
|
+
response = OpenStruct.new(
|
42
|
+
status_code: 400,
|
43
|
+
status: 'Bad Request',
|
44
|
+
error: 'invalid_client',
|
45
|
+
error_description: 'Invalid client id',
|
46
|
+
access_token: nil,
|
47
|
+
token_ttl: nil
|
48
|
+
)
|
49
|
+
expect(WNSAccess.new(sid, secret).get_token.response).to eq(response)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'when bad request' do
|
54
|
+
let(:body) { '' }
|
55
|
+
before do
|
56
|
+
stub_request(:post, "https://login.live.com/accesstoken.srf").
|
57
|
+
to_return status: [500, 'Internal Server Error'], body: body
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'returns correct response' do
|
61
|
+
response = OpenStruct.new(
|
62
|
+
status_code: 500,
|
63
|
+
status: 'Internal Server Error',
|
64
|
+
error: nil,
|
65
|
+
error_description: nil,
|
66
|
+
access_token: nil,
|
67
|
+
token_ttl: nil
|
68
|
+
)
|
69
|
+
expect(WNSAccess.new(sid, secret).get_token.response).to eq(response)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|