fcm-ruby-push-notifications 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|