mercurius 0.1.5 → 0.1.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c9d092e2bac4a62f415675ab2377d5bbef233fda
4
- data.tar.gz: 39e988fb569e75e8053352d00fee748cfa6b9028
3
+ metadata.gz: 2ab94d197c802c11b53e6fc8dc34090237b456af
4
+ data.tar.gz: 4dbcf381ccc7185f1cb27514ac24ff3d80bf8332
5
5
  SHA512:
6
- metadata.gz: fbe5d38205bde19ef187af2287c029a30a2d348e874b10c4da3b24c9dd77a92bfb04edf58ee5854e38e7f8d1aa90bb3b87b4c47cdd89789d769c45103ec68fe2
7
- data.tar.gz: a868cdc0297e17c69e72fbec34c4d615e4570d3d59169de4acb89d59f2230d8c9f7a73ee6ee802e9a83a16cb1b3129a6c7584552a279888ce32d77bed641b297
6
+ metadata.gz: 098bd1d77a6e27e53e52cc873aeee6b8428569d47fbf855af51cd2624ab0470c7cfede9e0dc8b1e092100e779d78c6d0843751bacbba837e332102b2351e77f7
7
+ data.tar.gz: fee9b5c35b361e65a8d4496e9127f5627b2078ab249349477b9827fe24855125c0664bf66fc5946735d2a7fc7539eb87d9856cfd3d8f8904724c5165b08f21a3
data/README.md CHANGED
@@ -28,14 +28,14 @@ Create the service with:
28
28
 
29
29
  Now create the notification that you wish to send:
30
30
 
31
- gcm_notification = GCM::Notification.new(alert: 'Hey')
31
+ gcm_notification = GCM::Notification.new(data: { alert: 'Hey' })
32
32
 
33
33
  You can deliver the gcm_notification in the following manners:
34
34
 
35
- gcm_service.deliver gcm_notification, 'token123' # single recipient
36
- gcm_service.deliver gcm_notification, 'token123', 'token456' # multiple recipients
37
- token_array = ['token123', 'token456']
38
- gcm_service.deliver gcm_notification, token_array # multiple recipients
35
+ gcm_service.deliver gcm_notification, 'token123' # single recipient
36
+ gcm_service.deliver gcm_notification, 'token123', 'token456' # multiple recipients
37
+ gcm_service.deliver gcm_notification, ['token123', 'token456'] # multiple recipients
38
+ gcm_service.deliver gcm_notification, topic: 'topic123' # topic delivery
39
39
 
40
40
  ## APNS
41
41
 
data/bin/rake ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rake' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rake', 'rake')
data/bin/rspec ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+ #
3
+ # This file was generated by Bundler.
4
+ #
5
+ # The application 'rspec' is installed as part of a gem, and
6
+ # this file is here to facilitate running it.
7
+ #
8
+
9
+ require 'pathname'
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile",
11
+ Pathname.new(__FILE__).realpath)
12
+
13
+ require 'rubygems'
14
+ require 'bundler/setup'
15
+
16
+ load Gem.bin_path('rspec-core', 'rspec')
data/lib/mercurius.rb CHANGED
@@ -23,4 +23,6 @@ require 'mercurius/gcm/connection'
23
23
  require 'mercurius/gcm/notification'
24
24
  require 'mercurius/gcm/service'
25
25
  require 'mercurius/gcm/response'
26
+ require 'mercurius/gcm/response_collection'
27
+ require 'mercurius/gcm/result_collection'
26
28
  require 'mercurius/gcm/result'
@@ -34,13 +34,11 @@ module APNS
34
34
  end
35
35
 
36
36
  private
37
-
38
37
  def ssl_context_for_pem(pem)
39
38
  context = OpenSSL::SSL::SSLContext.new
40
39
  context.cert = OpenSSL::X509::Certificate.new(pem.data)
41
40
  context.key = OpenSSL::PKey::RSA.new(pem.data, pem.password)
42
41
  context
43
42
  end
44
-
45
43
  end
46
44
  end
@@ -26,16 +26,6 @@ module APNS
26
26
  [0, 0, 32, package_device_token(device_token), 0, packaged_message.bytesize, packaged_message].pack("ccca*cca*")
27
27
  end
28
28
 
29
- def package_device_token(device_token)
30
- [device_token.gsub(/[\s|<|>]/,'')].pack('H*')
31
- end
32
-
33
- def packaged_message
34
- { aps: payload }.to_json.gsub(/\\u([\da-fA-F]{4})/) do |m|
35
- [$1].pack("H*").unpack("n*").pack("U*")
36
- end
37
- end
38
-
39
29
  def ==(that)
40
30
  attributes == that.attributes
41
31
  end
@@ -44,5 +34,15 @@ module APNS
44
34
  packaged_message.bytesize <= MAX_PAYLOAD_BYTES
45
35
  end
46
36
 
37
+ private
38
+ def package_device_token(device_token)
39
+ [device_token.gsub(/[\s|<|>]/,'')].pack('H*')
40
+ end
41
+
42
+ def packaged_message
43
+ { aps: payload }.to_json.gsub(/\\u([\da-fA-F]{4})/) do |m|
44
+ [$1].pack("H*").unpack("n*").pack("U*")
45
+ end
46
+ end
47
47
  end
48
48
  end
@@ -9,7 +9,6 @@ module APNS
9
9
  end
10
10
 
11
11
  private
12
-
13
12
  def read_file_at_path
14
13
  if File.exist? path
15
14
  File.read path
@@ -17,6 +16,5 @@ module APNS
17
16
  raise PemNotFoundError.new
18
17
  end
19
18
  end
20
-
21
19
  end
22
20
  end
@@ -33,7 +33,6 @@ module APNS
33
33
  end
34
34
 
35
35
  private
36
-
37
36
  def persistent?
38
37
  @_persistent
39
38
  end
@@ -57,6 +56,5 @@ module APNS
57
56
  def too_many_retries?
58
57
  @attempts >= MAX_NUMBER_OF_RETRIES
59
58
  end
60
-
61
59
  end
62
60
  end
@@ -1,7 +1,5 @@
1
1
  class InvalidApnsModeError < StandardError
2
-
3
2
  def initialize
4
3
  super 'Tried to set invalid APNS mode.'
5
4
  end
6
-
7
5
  end
@@ -1,7 +1,5 @@
1
1
  class PemNotConfiguredError < StandardError
2
-
3
2
  def initialize
4
3
  super 'PEM is not configured properly.'
5
4
  end
6
-
7
- end
5
+ end
@@ -1,7 +1,5 @@
1
1
  class PemNotFoundError < StandardError
2
-
3
2
  def initialize
4
3
  super 'The specified PEM file does not exist.'
5
4
  end
6
-
7
- end
5
+ end
@@ -1,7 +1,5 @@
1
1
  class TooManyRetriesError < StandardError
2
-
3
2
  def initialize(e)
4
3
  super "APNS Service has reached it's maximum number of retries. Error: #{e.message}"
5
4
  end
6
-
7
5
  end
@@ -1,36 +1,22 @@
1
1
  module GCM
2
2
  class Notification
3
3
  include ActiveModel::Model
4
-
5
- def self.special_attrs
6
- [:collapse_key, :time_to_live, :delay_while_idle, :dry_run, :notification]
7
- end
8
-
9
- attr_accessor :data
10
- attr_accessor *special_attrs
11
- # validate delay_while_idle is true/false
12
- # validate ttl is integer in seconds
4
+ attr_accessor :attributes
13
5
 
14
6
  def initialize(attributes = {})
15
7
  @attributes = attributes
16
- super @attributes.slice(*self.class.special_attrs).merge(data: @attributes.except(*self.class.special_attrs))
17
8
  end
18
9
 
19
10
  def to_h
20
- hash = {
21
- notification: notification,
22
- data: data,
23
- collapse_key: collapse_key,
24
- time_to_live: time_to_live,
25
- delay_while_idle: delay_while_idle,
26
- dry_run: dry_run
27
- }
28
-
29
- hash.reject { |k, v| v.nil? }
11
+ @attributes
30
12
  end
31
13
 
32
14
  def ==(that)
33
15
  attributes == that.attributes
34
16
  end
17
+
18
+ def method_missing(method, *args, &block)
19
+ @attributes.fetch(method) { super }
20
+ end
35
21
  end
36
22
  end
@@ -1,49 +1,55 @@
1
1
  module GCM
2
2
  class Response
3
- attr_reader :response, :device_tokens
4
-
5
- MESSAGES = {
6
- 200 => 'Success',
7
- 400 => 'The request could not be parsed as JSON or it contained invalid fields',
8
- 401 => 'There was an error authenticating the sender account',
9
- 500 => 'There was an internal error in the GCM server',
10
- 503 => 'GCM server is temporarily unavailable',
11
- default: 'Unknown error'
12
- }
13
-
14
- def initialize(response, device_tokens)
3
+ attr_reader :response, :tokens
4
+
5
+ def initialize(response, tokens = [])
15
6
  @response = response
16
- @device_tokens = device_tokens
7
+ @tokens = tokens
17
8
  end
18
9
 
19
10
  def status
20
- @response.status
21
- end
22
-
23
- def message
24
- MESSAGES.fetch(status, MESSAGES[:default])
11
+ response.status
25
12
  end
26
13
 
27
14
  def success?
28
- @response.success?
15
+ response.success?
29
16
  end
30
17
 
31
- def failed?
18
+ def fail?
32
19
  !success?
33
20
  end
34
21
 
35
- def has_canonical_ids?
36
- (response_body.canonical_ids || 0) > 0
22
+ def results
23
+ @_results ||= begin
24
+ results = to_h.fetch 'results', []
25
+ results.map!.with_index do |attributes, i|
26
+ GCM::Result.new attributes, tokens[i]
27
+ end
28
+ ResultCollection.new(results)
29
+ end
37
30
  end
38
31
 
39
- def canonical_ids
40
- response_body.results.map do |result|
41
- result["registration_id"]
32
+ def error
33
+ case status
34
+ when 401
35
+ 'Authentication error with GCM. Check the server whitelist and the validity of your project key.'
36
+ when 400
37
+ 'Invalid JSON was sent to GCM.'
38
+ when 500..599
39
+ 'GCM Internal server error.'
40
+ else
41
+ nil
42
42
  end
43
43
  end
44
44
 
45
- def response_body
46
- @response_body ||= OpenStruct.new JSON.parse(response.body)
45
+ def retry_after
46
+ response.headers['Retry-After']
47
+ end
48
+
49
+ def to_h
50
+ JSON.parse response.body
51
+ rescue JSON::ParserError
52
+ {}
47
53
  end
48
54
  end
49
55
  end
@@ -0,0 +1,28 @@
1
+ module GCM
2
+ class ResponseCollection
3
+ attr_reader :recommendations
4
+
5
+ def initialize(notification, responses = [])
6
+ @responses = responses
7
+ @notification = notification
8
+ end
9
+
10
+ def [](index)
11
+ @responses[index]
12
+ end
13
+
14
+ def <<(response)
15
+ @responses.concat Array(response).flatten
16
+ end
17
+
18
+ def results
19
+ out = GCM::ResultCollection.new
20
+ @responses.map do |response|
21
+ response.results.each do |result|
22
+ out << result
23
+ end
24
+ end
25
+ out
26
+ end
27
+ end
28
+ end
@@ -1,30 +1,29 @@
1
1
  module GCM
2
2
  class Result
3
- attr_reader :responses
3
+ include ActiveModel::Model
4
4
 
5
- def initialize(notification)
6
- @notification = notification
7
- @responses = []
8
- end
5
+ attr_accessor :message_id, :registration_id, :error
6
+ attr_reader :token
9
7
 
10
- def success?
11
- failed_responses.empty?
8
+ def initialize(attributes, token)
9
+ super attributes
10
+ @token = token
12
11
  end
13
12
 
14
- def process_response(response, device_tokens)
15
- self.responses << GCM::Response.new(response, device_tokens)
13
+ def success?
14
+ message_id.present?
16
15
  end
17
16
 
18
- def failed_responses
19
- @_failed_responses ||= responses.select(&:failed?)
17
+ def fail?
18
+ !success?
20
19
  end
21
20
 
22
- def failed_device_tokens
23
- @_failed_device_tokens ||= failed_responses.flat_map { |response| response.device_tokens }
21
+ def canonical_id
22
+ registration_id
24
23
  end
25
24
 
26
- def has_canonical_ids?
27
- responses.map{ |response| response.has_canonical_ids? }.reduce{ |carry, val| carry || val }
25
+ def has_canonical_id?
26
+ canonical_id.present?
28
27
  end
29
28
  end
30
29
  end
@@ -0,0 +1,33 @@
1
+ module GCM
2
+ class ResultCollection
3
+ include Enumerable
4
+
5
+ def initialize(results = [])
6
+ @results = results
7
+ end
8
+
9
+ def [](index)
10
+ @results[index]
11
+ end
12
+
13
+ def each(&block)
14
+ @results.each &block
15
+ end
16
+
17
+ def succeeded
18
+ @results.select &:success?
19
+ end
20
+
21
+ def failed
22
+ @results.select &:fail?
23
+ end
24
+
25
+ def with_canonical_ids
26
+ @results.select &:has_canonical_id?
27
+ end
28
+
29
+ def <<(result)
30
+ @results << result
31
+ end
32
+ end
33
+ end
@@ -2,8 +2,7 @@ module GCM
2
2
  class Service
3
3
  include ActiveModel::Model
4
4
 
5
- MAX_NUMBER_OF_RETRIES = 3
6
- MAX_DEVICES_AT_ONCE = 999
5
+ BATCH_SIZE = 999
7
6
 
8
7
  attr_accessor :host, :key
9
8
  attr_reader :connection, :attempts
@@ -16,27 +15,27 @@ module GCM
16
15
  @attempts = 0
17
16
  end
18
17
 
19
- def deliver(notification, *device_tokens)
20
- result = GCM::Result.new(notification)
21
- device_tokens = Array(device_tokens).flatten
22
- device_tokens.each_slice(MAX_DEVICES_AT_ONCE) do |tokens|
23
- payload = notification.to_h.merge registration_ids: tokens
24
- result.process_response connection.write(payload), tokens
25
- end
26
- result
27
- end
28
-
29
- def deliver_topic(notification, topic)
30
- GCM::Result.new(notification).tap do |result|
31
- result.process_response connection.write(notification.to_h.merge(to: topic)), [topic]
32
- end
18
+ def deliver(notification, *tokens, topic: nil)
19
+ responses = GCM::ResponseCollection.new(notification)
20
+ responses << deliver_to_tokens(notification, tokens)
21
+ responses << deliver_to_topic(notification, topic) if topic
22
+ responses
33
23
  end
34
24
 
35
25
  private
26
+ def each_batch_of_tokens(tokens, batch_size: BATCH_SIZE, &block)
27
+ Array(tokens).flatten.compact.each_slice(batch_size)
28
+ end
36
29
 
37
- def too_many_retries?
38
- @attempts >= MAX_NUMBER_OF_RETRIES
30
+ def deliver_to_tokens(notification, tokens)
31
+ each_batch_of_tokens(tokens).map do |tokens|
32
+ payload = notification.to_h.merge registration_ids: tokens
33
+ GCM::Response.new(connection.write(payload), tokens)
34
+ end
39
35
  end
40
36
 
37
+ def deliver_to_topic(notification, topic)
38
+ GCM::Response.new connection.write(notification.to_h.merge(to: topic))
39
+ end
41
40
  end
42
41
  end
@@ -1,3 +1,3 @@
1
1
  module Mercurius
2
- VERSION = '0.1.5'
2
+ VERSION = '0.1.6'
3
3
  end
data/mercurius.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |s|
18
18
 
19
19
  s.files = `git ls-files`.split("\n")
20
20
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
21
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
21
+ s.executables = `git ls-files -- exe/*`.split("\n").map{ |f| File.basename(f) }
22
22
 
23
23
  s.require_paths = ["lib"]
24
24
  s.required_ruby_version = '~> 2.0'
@@ -1,17 +1,11 @@
1
1
  describe GCM::Notification do
2
2
  describe 'with attributes' do
3
- it 'should extract special attributes from the hash and assign them' do
3
+ it 'delegates methods to the attributes hash' do
4
4
  notification = GCM::Notification.new({ collapse_key: 'some_key', time_to_live: 123, delay_while_idle: true, dry_run: true })
5
5
  expect(notification.collapse_key).to eq 'some_key'
6
6
  expect(notification.time_to_live).to eq 123
7
7
  expect(notification.delay_while_idle).to eq true
8
8
  expect(notification.dry_run).to eq true
9
9
  end
10
-
11
- it 'should move other attributes to data' do
12
- notification = GCM::Notification.new({ message: 'hello', dry_run: true})
13
- expect(notification.dry_run).to eq true
14
- expect(notification.data).to eq({ message: 'hello' })
15
- end
16
10
  end
17
- end
11
+ end
@@ -1,25 +1,82 @@
1
1
  describe GCM::Response do
2
- subject { GCM::Response.new nil, nil }
3
-
4
- it 'has_canonical_ids? should return true if the response body has canonical ids' do
5
- allow(subject).to receive(:response_body) { OpenStruct.new canonical_ids: 1 }
6
- expect(subject.has_canonical_ids?).to be_truthy
2
+ class FakeResponse < Struct.new(:hash, :success)
3
+ def body; hash.to_json; end
4
+ def success?; success; end
7
5
  end
8
6
 
9
- it 'has_canonical_ids? should return false if the body has no canonical ids' do
10
- allow(subject).to receive(:response_body) { OpenStruct.new success: 1 }
11
- expect(subject.has_canonical_ids?).to be_falsy
7
+ let(:json) { Hash.new }
8
+ let(:success) { true }
9
+ let(:tokens) { ['token123', 'token456'] }
10
+
11
+ let(:response) do
12
+ GCM::Response.new FakeResponse.new(json, success), tokens
12
13
  end
13
14
 
14
- it 'canonical_ids should return an array of registration ids' do
15
- allow(subject).to receive(:response_body) { OpenStruct.new results: [{'registration_id' => '1234'}, {'registration_id' => '5678'}, {}] }
16
- expect(subject.canonical_ids).to eq ['1234', '5678', nil]
15
+ describe '#results' do
16
+ let(:json) do
17
+ {
18
+ multicast_id: 108, success: 2, failure: 1, canonical_ids: 1, results: [
19
+ { message_id: '1' },
20
+ { message_id: '2', registration_id: 'canonicalToken456' },
21
+ { error: 'DeviceMessageRateExceeded' }
22
+ ]
23
+ }
24
+ end
25
+
26
+ it 'returns an array of the results in a response' do
27
+ expect(response.results.count).to eq 3
28
+ expect(response.results[0].message_id).to eq '1'
29
+ expect(response.results[0].token).to eq 'token123'
30
+ expect(response.results[1].message_id).to eq '2'
31
+ expect(response.results[1].token).to eq 'token456'
32
+ expect(response.results[1].canonical_id).to eq 'canonicalToken456'
33
+ end
34
+
35
+ describe 'ResultCollection#succeeded' do
36
+ subject { response.results.succeeded }
37
+
38
+ it 'returns only the successful results' do
39
+ expect(subject.count).to eq 2
40
+ expect(subject[0].message_id).to eq '1'
41
+ expect(subject[1].message_id).to eq '2'
42
+ end
43
+ end
44
+
45
+ describe 'ResultCollection#failed' do
46
+ subject { response.results.failed }
47
+
48
+ it 'returns only the failed results' do
49
+ expect(subject.count).to eq 1
50
+ expect(subject[0].error).to eq 'DeviceMessageRateExceeded'
51
+ end
52
+ end
53
+
54
+ describe 'ResultCollection#with_canonical_ids' do
55
+ subject { response.results.with_canonical_ids }
56
+
57
+ it 'returns only the results with canonical ids' do
58
+ expect(subject.count).to eq 1
59
+ expect(subject[0].token).to eq 'token456'
60
+ expect(subject[0].canonical_id).to eq 'canonicalToken456'
61
+ end
62
+ end
17
63
  end
18
64
 
19
- it 'response_body should return an openstruct of the response.body' do
20
- allow(subject).to receive(:response) { OpenStruct.new body: { one: 'two' }.to_json }
21
- result = subject.response_body
22
- expect(result).to be_a OpenStruct
23
- expect(result.to_h).to eq({one: 'two'})
65
+ describe '#success?' do
66
+ context 'Faraday response is successful' do
67
+ let(:success) { true }
68
+
69
+ it 'returns true' do
70
+ expect(response).to be_success
71
+ end
72
+ end
73
+
74
+ context 'Faraday response is not successful' do
75
+ let(:success) { false }
76
+
77
+ it 'returns false' do
78
+ expect(response).to_not be_success
79
+ end
80
+ end
24
81
  end
25
- end
82
+ end
@@ -0,0 +1,32 @@
1
+ describe GCM::ResultCollection do
2
+ subject do
3
+ GCM::ResultCollection.new [
4
+ GCM::Result.new({ message_id: '1' }, 'token123'),
5
+ GCM::Result.new({ message_id: '2', registration_id: 'canonicalToken456' }, 'token456'),
6
+ GCM::Result.new({ error: 'DeviceMessageRateExceeded' }, nil)
7
+ ]
8
+ end
9
+
10
+ describe '#succeeded' do
11
+ it 'returns only the successful results' do
12
+ expect(subject.succeeded.count).to eq 2
13
+ expect(subject.succeeded[0].message_id).to eq '1'
14
+ expect(subject.succeeded[1].message_id).to eq '2'
15
+ end
16
+ end
17
+
18
+ describe '#failed' do
19
+ it 'returns only the failed results' do
20
+ expect(subject.failed.count).to eq 1
21
+ expect(subject.failed[0].error).to eq 'DeviceMessageRateExceeded'
22
+ end
23
+ end
24
+
25
+ describe '#with_canonical_ids' do
26
+ it 'returns only the results with canonical ids' do
27
+ expect(subject.with_canonical_ids.count).to eq 1
28
+ expect(subject.with_canonical_ids[0].token).to eq 'token456'
29
+ expect(subject.with_canonical_ids[0].canonical_id).to eq 'canonicalToken456'
30
+ end
31
+ end
32
+ end
@@ -1,13 +1,49 @@
1
1
  describe GCM::Result do
2
- subject { GCM::Result.new nil }
2
+ describe '#canonical_id' do
3
+ it 'returns the registration_id from the GCM response JSON' do
4
+ result = GCM::Result.new({ message_id: '1:08', registration_id: 'canonicalToken123' }, nil)
5
+ expect(result.canonical_id).to eq 'canonicalToken123'
6
+ end
3
7
 
4
- it 'has_canonical_ids? should return true if any responses have them' do
5
- allow(subject).to receive(:responses) { [instance_double(GCM::Response, has_canonical_ids?: true), instance_double(GCM::Response, has_canonical_ids?: false)] }
6
- expect(subject.has_canonical_ids?).to be_truthy
8
+ it 'returns nil if no canonical ID is given by GCM' do
9
+ result = GCM::Result.new({ message_id: '1:08' }, nil)
10
+ expect(result.canonical_id).to be_nil
11
+ end
7
12
  end
8
13
 
9
- it 'otherwise, has_canonical_ids should return false' do
10
- allow(subject).to receive(:responses) { [instance_double(GCM::Response, has_canonical_ids?: false), instance_double(GCM::Response, has_canonical_ids?: false)] }
11
- expect(subject.has_canonical_ids?).to be_falsy
14
+ describe '#has_canonical_id?' do
15
+ it 'returns true when canonical_id is given by GCM' do
16
+ result = GCM::Result.new({ message_id: '1:08', registration_id: 'canonicalToken123' }, nil)
17
+ expect(result.has_canonical_id?).to be_truthy
18
+ end
19
+
20
+ it 'returns false when canonical_id is not given by GCM' do
21
+ result = GCM::Result.new({ message_id: '1:08' }, nil)
22
+ expect(result.has_canonical_id?).to be_falsey
23
+ end
24
+ end
25
+
26
+ describe '#success?' do
27
+ it 'returns true when the message is sent and returned with a message id' do
28
+ result = GCM::Result.new({ message_id: '1:08' }, nil)
29
+ expect(result).to be_success
30
+ end
31
+
32
+ it 'returns false otherwise' do
33
+ result = GCM::Result.new({ error: 'DeviceMessageRateExceeded' }, nil)
34
+ expect(result).to_not be_success
35
+ end
36
+ end
37
+
38
+ describe '#error' do
39
+ it 'returns the error from GCM' do
40
+ result = GCM::Result.new({ error: 'DeviceMessageRateExceeded' }, nil)
41
+ expect(result.error).to eq 'DeviceMessageRateExceeded'
42
+ end
43
+
44
+ it 'returns nil when there is no error' do
45
+ result = GCM::Result.new({ message_id: '1:08' }, nil)
46
+ expect(result.error).to be_nil
47
+ end
12
48
  end
13
49
  end
@@ -1,6 +1,6 @@
1
1
  describe GCM::Service do
2
2
  let(:service) { GCM::Service.new }
3
- let(:message) { GCM::Notification.new(alert: 'Hey') }
3
+ let(:message) { GCM::Notification.new(data: { alert: 'Hey' }) }
4
4
 
5
5
  it 'should default to the GCM module configs' do
6
6
  expect(service.host).to eq GCM.host
@@ -34,7 +34,7 @@ describe GCM::Service do
34
34
  expect(WebMock).to have_requested(:post, %r[android.googleapis.com/gcm/send]).
35
35
  with(body: { data: { alert: 'Hey' }, registration_ids: tokens.take(999) })
36
36
  expect(WebMock).to have_requested(:post, %r[android.googleapis.com/gcm/send]).
37
- with(body: { data: { alert: 'Hey' }, registration_ids: [tokens.last] })
37
+ with(body: { data: { alert: 'Hey' }, registration_ids: ['token1000'] })
38
38
  end
39
39
  end
40
40
 
@@ -43,7 +43,7 @@ describe GCM::Service do
43
43
  let(:message) { { notification: { title: 'hello', body: 'world' } } }
44
44
 
45
45
  it 'sends a notification to a topic' do
46
- service.deliver_topic message, '/topics/global'
46
+ service.deliver message, topic: '/topics/global'
47
47
  expect(WebMock).to have_requested(:post, %r[android.googleapis.com/gcm/send]).
48
48
  with(body: message.merge(to: '/topics/global'))
49
49
  end
@@ -54,28 +54,47 @@ describe GCM::Service do
54
54
  before { stub_request :post, %r[android.googleapis.com/gcm/send] }
55
55
 
56
56
  it 'processes a 200 response' do
57
- result = service.deliver message, 'token123'
58
- expect(result.responses[0].status).to eq 200
59
- expect(result.responses[0].message).to eq GCM::Response::MESSAGES[200]
60
- expect(result.failed_device_tokens).to eq []
57
+ responses = service.deliver message, 'token123'
58
+ expect(responses[0].status).to eq 200
59
+ expect(responses[0].success?).to eq true
60
+ expect(responses.results.failed).to eq []
61
61
  end
62
62
  end
63
63
 
64
- context 'failure' do
65
- before { stub_request(:post, %r[android.googleapis.com/gcm/send]).to_return(status: 400) }
64
+ describe 'failure' do
65
+ context 401 do
66
+ before { stub_request(:post, %r[android.googleapis.com/gcm/send]).to_return(status: 401) }
66
67
 
67
- it 'processes a 400 response' do
68
- result = service.deliver message, 'token123'
69
- expect(result.responses[0].status).to eq 400
70
- expect(result.responses[0].message).to eq GCM::Response::MESSAGES[400]
71
- expect(result.failed_device_tokens).to eq ['token123']
68
+ it 'has a meaningful message from #error' do
69
+ responses = service.deliver message, 'token123'
70
+ expect(responses[0].error).to match /Authentication error/
71
+ end
72
72
  end
73
73
 
74
- it 'adds all failed messages to the failed device tokens array' do
75
- tokens = (1..1000).to_a.map { |i| "token#{i}" }
76
- result = service.deliver message, tokens
77
- expect(result.failed_device_tokens).to include 'token1'
78
- expect(result.failed_device_tokens).to include 'token1000'
74
+ context 400 do
75
+ before { stub_request(:post, %r[android.googleapis.com/gcm/send]).to_return(status: 400) }
76
+
77
+ it 'has a meaningful message from #error' do
78
+ responses = service.deliver message, 'token123'
79
+ expect(responses[0].error).to match /Invalid JSON/
80
+ end
81
+ end
82
+
83
+ context 500..599 do
84
+ before do
85
+ stub_request(:post, %r[android.googleapis.com/gcm/send]).
86
+ to_return status: 500, headers: { 'Retry-After' => '120' }
87
+ end
88
+
89
+ it 'has a meaningful message from #error' do
90
+ responses = service.deliver message, 'token123'
91
+ expect(responses[0].error).to match /GCM Internal server error/
92
+ end
93
+
94
+ it 'returns the Retry-After header from GCM' do
95
+ responses = service.deliver message, 'token123'
96
+ expect(responses[0].retry_after).to eq '120'
97
+ end
79
98
  end
80
99
  end
81
100
 
@@ -18,7 +18,7 @@ describe 'Test mode' do
18
18
 
19
19
  context 'GCM' do
20
20
  let(:service) { GCM::MockService.new }
21
- let(:message) { GCM::Notification.new(alert: 'Hey') }
21
+ let(:message) { GCM::Notification.new(data: { alert: 'Hey' }) }
22
22
 
23
23
  it 'returns the deliveries sent to GCM' do
24
24
  result = service.deliver message, 'token123'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mercurius
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Beck
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-09 00:00:00.000000000 Z
11
+ date: 2015-09-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -139,6 +139,8 @@ files:
139
139
  - LICENSE
140
140
  - README.md
141
141
  - Rakefile
142
+ - bin/rake
143
+ - bin/rspec
142
144
  - lib/mercurius.rb
143
145
  - lib/mercurius/apns.rb
144
146
  - lib/mercurius/apns/connection.rb
@@ -153,7 +155,9 @@ files:
153
155
  - lib/mercurius/gcm/connection.rb
154
156
  - lib/mercurius/gcm/notification.rb
155
157
  - lib/mercurius/gcm/response.rb
158
+ - lib/mercurius/gcm/response_collection.rb
156
159
  - lib/mercurius/gcm/result.rb
160
+ - lib/mercurius/gcm/result_collection.rb
157
161
  - lib/mercurius/gcm/service.rb
158
162
  - lib/mercurius/testing.rb
159
163
  - lib/mercurius/testing/base.rb
@@ -167,6 +171,7 @@ files:
167
171
  - spec/lib/apns_spec.rb
168
172
  - spec/lib/gcm_notification_spec.rb
169
173
  - spec/lib/gcm_response_spec.rb
174
+ - spec/lib/gcm_result_collection_spec.rb
170
175
  - spec/lib/gcm_result_spec.rb
171
176
  - spec/lib/gcm_service_spec.rb
172
177
  - spec/lib/testing_spec.rb
@@ -202,6 +207,7 @@ test_files:
202
207
  - spec/lib/apns_spec.rb
203
208
  - spec/lib/gcm_notification_spec.rb
204
209
  - spec/lib/gcm_response_spec.rb
210
+ - spec/lib/gcm_result_collection_spec.rb
205
211
  - spec/lib/gcm_result_spec.rb
206
212
  - spec/lib/gcm_service_spec.rb
207
213
  - spec/lib/testing_spec.rb