pushr-gcm 1.0.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +7 -0
- data/lib/pushr-gcm/version.rb +3 -0
- data/lib/pushr/configuration_gcm.rb +14 -0
- data/lib/pushr/daemon/gcm.rb +18 -0
- data/lib/pushr/daemon/gcm_support/connection_gcm.rb +136 -0
- data/lib/pushr/daemon/gcm_support/response_handler.rb +44 -0
- data/lib/pushr/feedback_gcm.rb +12 -0
- data/lib/pushr/gcm.rb +12 -0
- data/lib/pushr/message_gcm.rb +48 -0
- data/spec/lib/pushr/configuration_gcm_spec.rb +33 -0
- data/spec/lib/pushr/daemon/gcm_spec.rb +15 -0
- data/spec/lib/pushr/daemon/gcm_support/connection_gcm_spec.rb +71 -0
- data/spec/lib/pushr/daemon/gcm_support/response_handler_spec.rb +82 -0
- data/spec/lib/pushr/feedback_gcm_spec.rb +27 -0
- data/spec/lib/pushr/message_gcm_spec.rb +54 -0
- data/spec/spec_helper.rb +37 -0
- data/spec/support/vcr.rb +4 -0
- data/spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_fails_and_should_retry_after.yml +63 -0
- data/spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_fails_and_should_retry_after_with_date.yml +63 -0
- data/spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_fails_and_should_sleep_after_fail.yml +61 -0
- data/spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_fails_of_a_json_formatting_execption.yml +61 -0
- data/spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_fails_of_a_not_authenticated_execption.yml +61 -0
- data/spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_succesful.yml +52 -0
- metadata +263 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bccec81fa181496f22827181b7cecc90cee2f5e1
|
4
|
+
data.tar.gz: 8088e1f5cb2905f4d7e5860e71136ff141da4840
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0070d30417bdb2cf3b99c9b45ec3e26441eb2c008067681de823e01f4a1fb33d9db4b0028cdd9f33cd74a56d3f600cb56ecaea4af7ad53ff29fd5344280d2232
|
7
|
+
data.tar.gz: 0fb12d6756e0545ccd25b3ae6b07503bcc57e2fba41bba895c5faa6d3ff8715f9b034ba5da31837e406a06c2e6ecc997d97fddb761af0285f9022be17b4f3aa1
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 YOURNAME
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# PushrGCM
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/9to5/pushr-gcm.svg?branch=master)](https://travis-ci.org/9to5/pushr-gcm)
|
4
|
+
[![Code Climate](https://codeclimate.com/github/9to5/pushr-gcm.png)](https://codeclimate.com/github/9to5/pushr-gcm)
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/9to5/pushr-gcm/badge.png)](https://coveralls.io/r/9to5/pushr-gcm)
|
6
|
+
|
7
|
+
Please see [pushr-core](https://github.com/tompesman/pushr-core) for more information.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Pushr
|
2
|
+
class ConfigurationGcm < Pushr::Configuration
|
3
|
+
attr_accessor :id, :type, :app, :enabled, :connections, :api
|
4
|
+
validates :api, presence: true
|
5
|
+
|
6
|
+
def name
|
7
|
+
:gcm
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_json
|
11
|
+
MultiJson.dump(type: self.class.to_s, app: app, enabled: enabled, connections: connections, api: api)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module Pushr
|
2
|
+
module Daemon
|
3
|
+
module GcmSupport
|
4
|
+
class ConnectionError < StandardError; end
|
5
|
+
|
6
|
+
class ConnectionGcm
|
7
|
+
attr_reader :response, :name, :configuration
|
8
|
+
PUSH_URL = 'https://android.googleapis.com/gcm/send'
|
9
|
+
IDLE_PERIOD = 5 * 60
|
10
|
+
|
11
|
+
def initialize(configuration, i)
|
12
|
+
@configuration = configuration
|
13
|
+
@name = "#{@configuration.app}: ConnectionGcm #{i}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def connect
|
17
|
+
@last_use = Time.now
|
18
|
+
uri = URI.parse(PUSH_URL)
|
19
|
+
@connection = open_http(uri.host, uri.port)
|
20
|
+
@connection.start
|
21
|
+
Pushr::Daemon.logger.info("[#{@name}] Connected to #{PUSH_URL}")
|
22
|
+
end
|
23
|
+
|
24
|
+
def write(data)
|
25
|
+
retry_count = 0
|
26
|
+
begin
|
27
|
+
response = notification_request(data.to_message)
|
28
|
+
handle_response(response, data, retry_count)
|
29
|
+
rescue => e
|
30
|
+
retry_count += 1
|
31
|
+
if retry_count < 10
|
32
|
+
retry
|
33
|
+
else
|
34
|
+
raise e
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def handle_response(response, data, retry_count)
|
42
|
+
if response.code.eql? '200'
|
43
|
+
handler = Pushr::Daemon::GcmSupport::ResponseHandler.new(response, data)
|
44
|
+
handler.handle
|
45
|
+
else
|
46
|
+
handle_error_response(response, data, retry_count)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def handle_error_response(response, data, retry_count)
|
51
|
+
case response.code.to_i
|
52
|
+
when 400
|
53
|
+
Pushr::Daemon.logger.error("[#{@name}] JSON formatting exception received.")
|
54
|
+
when 401
|
55
|
+
Pushr::Daemon.logger.error("[#{@name}] Authentication exception received.")
|
56
|
+
when 500..599
|
57
|
+
# internal error GCM server || service unavailable: exponential back-off
|
58
|
+
handle_error_5xx_response(response, retry_count)
|
59
|
+
else
|
60
|
+
Pushr::Daemon.logger.error("[#{@name}] Unknown error: #{response.code} #{response.message}")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# sleep if there is a Retry-After header
|
65
|
+
def handle_error_5xx_response(response, retry_count)
|
66
|
+
if response.header['Retry-After']
|
67
|
+
value = response.header['Retry-After']
|
68
|
+
|
69
|
+
if value.to_i > 0 # Retry-After: 120
|
70
|
+
sleep value.to_i
|
71
|
+
elsif Date.rfc2822(value) # Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
|
72
|
+
sleep Time.now.utc - Date.rfc2822(value).to_time.utc
|
73
|
+
end
|
74
|
+
else
|
75
|
+
sleep 2**retry_count
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def open_http(host, port)
|
80
|
+
http = Net::HTTP.new(host, port)
|
81
|
+
http.use_ssl = true
|
82
|
+
http
|
83
|
+
end
|
84
|
+
|
85
|
+
def notification_request(data)
|
86
|
+
headers = { 'Authorization' => "key=#{@configuration.api}",
|
87
|
+
'Content-type' => 'application/json',
|
88
|
+
'Content-length' => "#{data.length}" }
|
89
|
+
uri = URI.parse(PUSH_URL)
|
90
|
+
post(uri, data, headers)
|
91
|
+
end
|
92
|
+
|
93
|
+
def post(uri, data, headers)
|
94
|
+
reconnect_idle if idle_period_exceeded?
|
95
|
+
|
96
|
+
retry_count = 0
|
97
|
+
|
98
|
+
begin
|
99
|
+
response = @connection.post(uri.path, data, headers)
|
100
|
+
@last_use = Time.now
|
101
|
+
rescue EOFError, Errno::ECONNRESET, Timeout::Error => e
|
102
|
+
retry_count += 1
|
103
|
+
|
104
|
+
Pushr::Daemon.logger.error("[#{@name}] Lost connection to #{PUSH_URL} (#{e.class.name}), reconnecting ##{retry_count}...")
|
105
|
+
|
106
|
+
if retry_count <= 3
|
107
|
+
reconnect
|
108
|
+
sleep 1
|
109
|
+
retry
|
110
|
+
else
|
111
|
+
raise ConnectionError, "#{@name} tried #{retry_count - 1} times to reconnect but failed (#{e.class.name})."
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
response
|
116
|
+
end
|
117
|
+
|
118
|
+
def idle_period_exceeded?
|
119
|
+
# Timeout on the http connection is 5 minutes, reconnect after 5 minutes
|
120
|
+
@last_use + IDLE_PERIOD < Time.now
|
121
|
+
end
|
122
|
+
|
123
|
+
def reconnect_idle
|
124
|
+
Pushr::Daemon.logger.info("[#{@name}] Idle period exceeded, reconnecting...")
|
125
|
+
reconnect
|
126
|
+
end
|
127
|
+
|
128
|
+
def reconnect
|
129
|
+
@connection.finish
|
130
|
+
@last_use = Time.now
|
131
|
+
@connection.start
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Pushr
|
2
|
+
module Daemon
|
3
|
+
module GcmSupport
|
4
|
+
class ResponseHandler
|
5
|
+
attr_accessor :response, :message
|
6
|
+
def initialize(response, message)
|
7
|
+
self.response = response
|
8
|
+
self.message = message
|
9
|
+
end
|
10
|
+
|
11
|
+
def handle
|
12
|
+
hsh = MultiJson.load(response.body)
|
13
|
+
hsh['results'].each_with_index do |result, index|
|
14
|
+
handle_single(result, message.registration_ids[index])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def handle_single(result, registration_id)
|
19
|
+
if result.key?('error')
|
20
|
+
if result['error'] == 'NotRegistered' || result['error'] == 'InvalidRegistration'
|
21
|
+
Pushr::FeedbackGcm.new(app: message.app, failed_at: Time.now, device: registration_id, follow_up: 'delete').save
|
22
|
+
end
|
23
|
+
|
24
|
+
if result['error'] == 'Unavailable'
|
25
|
+
# TODO: If it is Unavailable, you could retry to send it in another request
|
26
|
+
m = message.clone
|
27
|
+
m.registration_ids = [registration_id]
|
28
|
+
m.save
|
29
|
+
end
|
30
|
+
|
31
|
+
# Pushr::Daemon.logger.error("[#{@name}] Error received.")
|
32
|
+
# fail Pushr::Daemon::DeliveryError.new(@response.code, nil, msg, 'GCM', false)
|
33
|
+
|
34
|
+
elsif result.key?('registration_id')
|
35
|
+
# success, but update device token
|
36
|
+
hsh = { app: message.app, failed_at: Time.now, device: registration_id,
|
37
|
+
follow_up: 'update', update_to: result['registration_id'] }
|
38
|
+
Pushr::FeedbackGcm.new(hsh).save
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Pushr
|
2
|
+
class FeedbackGcm < Pushr::Feedback
|
3
|
+
attr_accessor :type, :app, :device, :follow_up, :failed_at, :update_to
|
4
|
+
|
5
|
+
validates :follow_up, inclusion: { in: %w(delete update), message: '%{value} is not a valid follow-up' }
|
6
|
+
|
7
|
+
def to_json
|
8
|
+
hsh = { type: 'Pushr::FeedbackGcm', app: app, device: device, follow_up: follow_up, failed_at: failed_at, update_to: update_to }
|
9
|
+
MultiJson.dump(hsh)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/pushr/gcm.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'net/https'
|
3
|
+
require 'active_model'
|
4
|
+
require 'pushr-gcm/version'
|
5
|
+
require 'pushr/configuration'
|
6
|
+
require 'pushr/configuration_gcm'
|
7
|
+
require 'pushr/message'
|
8
|
+
require 'pushr/message_gcm'
|
9
|
+
require 'pushr/feedback'
|
10
|
+
require 'pushr/feedback_gcm'
|
11
|
+
require 'pushr/daemon/gcm'
|
12
|
+
require 'pushr/daemon/gcm_support/connection_gcm'
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Pushr
|
2
|
+
class MessageGcm < Pushr::Message
|
3
|
+
POSTFIX = 'gcm'
|
4
|
+
|
5
|
+
validates :registration_ids, presence: true
|
6
|
+
validate :registration_ids_array
|
7
|
+
validate :data_size
|
8
|
+
validates :delay_while_idle, :dry_run, inclusion: { in: [true, false] }, allow_blank: true
|
9
|
+
validates :time_to_live, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 2419200 },
|
10
|
+
allow_blank: true
|
11
|
+
|
12
|
+
attr_accessor :type, :app, :registration_ids, :notification_key, :collapse_key, :delay_while_idle, :time_to_live, :data,
|
13
|
+
:restricted_package_name, :dry_run
|
14
|
+
|
15
|
+
def to_message
|
16
|
+
hsh = {}
|
17
|
+
hsh['registration_ids'] = registration_ids
|
18
|
+
%w(notification_key collapse_key delay_while_idle time_to_live data restricted_package_name dry_run).each do |variable|
|
19
|
+
hsh[variable] = send(variable) if send(variable)
|
20
|
+
end
|
21
|
+
MultiJson.dump(hsh)
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_json
|
25
|
+
hsh = { type: self.class.to_s, app: app, registration_ids: registration_ids, notification_key: notification_key,
|
26
|
+
collapse_key: collapse_key, delay_while_idle: delay_while_idle, time_to_live: time_to_live, data: data }
|
27
|
+
MultiJson.dump(hsh)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def registration_ids_array
|
33
|
+
if registration_ids.class == Array
|
34
|
+
if registration_ids.size > 1000
|
35
|
+
errors.add(:registration_ids, 'is too big (max 1000)')
|
36
|
+
elsif registration_ids.size == 0
|
37
|
+
errors.add(:registration_ids, 'is too small (min 1)')
|
38
|
+
end
|
39
|
+
else
|
40
|
+
errors.add(:registration_ids, 'is not an array') unless registration_ids.class == Array
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def data_size
|
45
|
+
errors.add(:data, 'is more thank 4kb') if data && MultiJson.dump(data).bytes.count > 4096
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pushr/configuration_gcm'
|
3
|
+
|
4
|
+
describe Pushr::ConfigurationGcm do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
Pushr::Core.configure do |config|
|
8
|
+
config.redis = ConnectionPool.new(size: 1, timeout: 1) { MockRedis.new }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'all' do
|
13
|
+
it 'returns all configurations' do
|
14
|
+
expect(Pushr::Configuration.all).to eql([])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'create' do
|
19
|
+
it 'should create a configuration' do
|
20
|
+
config = Pushr::ConfigurationGcm.new(app: 'app_name', connections: 2, enabled: true)
|
21
|
+
expect(config.key).to eql('app_name:gcm')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'save' do
|
26
|
+
let(:config) { Pushr::ConfigurationGcm.new(app: 'app_name', connections: 2, enabled: true, api: 'key') }
|
27
|
+
it 'should save a configuration' do
|
28
|
+
config.save
|
29
|
+
expect(Pushr::Configuration.all.count).to eql(1)
|
30
|
+
expect(Pushr::Configuration.all[0].class).to eql(Pushr::ConfigurationGcm)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pushr/daemon/gcm'
|
3
|
+
require 'pushr/daemon/gcm_support/connection_gcm'
|
4
|
+
|
5
|
+
describe Pushr::Daemon::Gcm do
|
6
|
+
let(:gcm) { Pushr::Daemon::Gcm.new(test: 'test') }
|
7
|
+
|
8
|
+
describe 'responds to' do
|
9
|
+
it 'configuration' do
|
10
|
+
expect(gcm.connectiontype).to eql(Pushr::Daemon::GcmSupport::ConnectionGcm)
|
11
|
+
expect(gcm.stop).to eql(true)
|
12
|
+
expect(gcm.configuration).to eql(test: 'test')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pushr/daemon'
|
3
|
+
require 'pushr/daemon/logger'
|
4
|
+
require 'pushr/message_gcm'
|
5
|
+
require 'pushr/configuration_gcm'
|
6
|
+
require 'pushr/daemon/delivery_error'
|
7
|
+
require 'pushr/daemon/gcm_support/response_handler'
|
8
|
+
require 'pushr/daemon/gcm_support/connection_gcm'
|
9
|
+
|
10
|
+
describe Pushr::Daemon::GcmSupport::ConnectionGcm do
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
Pushr::Core.configure do |config|
|
14
|
+
config.redis = ConnectionPool.new(size: 1, timeout: 1) { MockRedis.new }
|
15
|
+
end
|
16
|
+
|
17
|
+
logger = double('logger')
|
18
|
+
allow(logger).to receive(:info)
|
19
|
+
allow(logger).to receive(:error)
|
20
|
+
allow(logger).to receive(:warn)
|
21
|
+
Pushr::Daemon.logger = logger
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'sends a message' do
|
25
|
+
let(:config) do
|
26
|
+
Pushr::ConfigurationGcm.new(app: 'app_name', connections: 2, enabled: true, api: 'apikey')
|
27
|
+
end
|
28
|
+
let(:message) do
|
29
|
+
hsh = { app: 'app_name', registration_ids: ['devicetoken'], collapse_key: 'x', delay_while_idle: false,
|
30
|
+
time_to_live: 24 * 60 * 60, data: { test: 'test' } }
|
31
|
+
Pushr::MessageGcm.new(hsh)
|
32
|
+
end
|
33
|
+
let(:connection) { Pushr::Daemon::GcmSupport::ConnectionGcm.new(config, 1) }
|
34
|
+
|
35
|
+
it 'succesful', :vcr do
|
36
|
+
connection.connect
|
37
|
+
connection.write(message)
|
38
|
+
# TODO: expect(connection.write(message).code).to eql '200'
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'fails and should Retry-After', :vcr do
|
42
|
+
expect_any_instance_of(Pushr::Daemon::GcmSupport::ConnectionGcm).to receive(:sleep)
|
43
|
+
connection.connect
|
44
|
+
connection.write(message)
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'fails and should Retry-After with date', :vcr do
|
48
|
+
expect_any_instance_of(Pushr::Daemon::GcmSupport::ConnectionGcm).to receive(:sleep)
|
49
|
+
connection.connect
|
50
|
+
connection.write(message)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'fails and should sleep after fail', :vcr do
|
54
|
+
expect_any_instance_of(Pushr::Daemon::GcmSupport::ConnectionGcm).to receive(:sleep)
|
55
|
+
connection.connect
|
56
|
+
connection.write(message)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'fails of a json formatting execption', :vcr do
|
60
|
+
connection.connect
|
61
|
+
connection.write(message)
|
62
|
+
# TODO: assert
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'fails of a not authenticated execption', :vcr do
|
66
|
+
connection.connect
|
67
|
+
connection.write(message)
|
68
|
+
# TODO: assert
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pushr/daemon'
|
3
|
+
require 'pushr/feedback_gcm'
|
4
|
+
require 'pushr/message_gcm'
|
5
|
+
require 'pushr/daemon/gcm_support/response_handler'
|
6
|
+
|
7
|
+
describe Pushr::Daemon::GcmSupport::ResponseHandler do
|
8
|
+
it 'should handle no errors' do
|
9
|
+
json = '{"multicast_id":7726000338213371155,"success":1,"failure":0,"canonical_ids":0,' \
|
10
|
+
'"results":[{"message_id":"0:1397767098298993%00525e0300000078"}]}'
|
11
|
+
response = double('response')
|
12
|
+
allow(response).to receive(:body).and_return(json)
|
13
|
+
|
14
|
+
message = double('message')
|
15
|
+
allow(message).to receive('registration_ids').and_return(['device_id'])
|
16
|
+
handler = Pushr::Daemon::GcmSupport::ResponseHandler.new(response, message)
|
17
|
+
handler.handle
|
18
|
+
# TODO: assert
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should handle Unavailable' do
|
22
|
+
json = '{"multicast_id":7726000338213371155,"success":0,"failure":1,"canonical_ids":0,' \
|
23
|
+
'"results":[{"error":"Unavailable"}]}'
|
24
|
+
response = double('response')
|
25
|
+
allow(response).to receive(:body).and_return(json)
|
26
|
+
|
27
|
+
message = double('message')
|
28
|
+
allow(message).to receive('registration_ids').and_return(['device_id'])
|
29
|
+
expect(message).to receive('registration_ids=').with(['device_id'])
|
30
|
+
allow(message).to receive('save')
|
31
|
+
handler = Pushr::Daemon::GcmSupport::ResponseHandler.new(response, message)
|
32
|
+
handler.handle
|
33
|
+
# TODO: assert
|
34
|
+
end
|
35
|
+
it 'should work' do
|
36
|
+
t = double('test')
|
37
|
+
allow(t).to receive(:foobar).and_return(1)
|
38
|
+
expect(t.clone.foobar).to eq(1)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should handle InvalidRegistration' do
|
42
|
+
expect_any_instance_of(Pushr::FeedbackGcm).to receive(:save)
|
43
|
+
json = '{"multicast_id":7726000338213371155,"success":0,"failure":1,"canonical_ids":0,' \
|
44
|
+
'"results":[{"error":"InvalidRegistration"}]}'
|
45
|
+
response = double('response')
|
46
|
+
allow(response).to receive(:body).and_return(json)
|
47
|
+
|
48
|
+
message = double('message')
|
49
|
+
allow(message).to receive('registration_ids').and_return(['device_id'])
|
50
|
+
allow(message).to receive(:app).and_return('app_name')
|
51
|
+
handler = Pushr::Daemon::GcmSupport::ResponseHandler.new(response, message)
|
52
|
+
handler.handle
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should handle registration_id' do
|
56
|
+
expect_any_instance_of(Pushr::FeedbackGcm).to receive(:save)
|
57
|
+
json = '{"multicast_id":7726000338213371155,"success":1,"failure":0,"canonical_ids":1,' \
|
58
|
+
'"results":[{"message_id":"message_id","registration_id":"new_reg_id"}]}'
|
59
|
+
response = double('response')
|
60
|
+
allow(response).to receive(:body).and_return(json)
|
61
|
+
|
62
|
+
message = double('message')
|
63
|
+
allow(message).to receive('registration_ids').and_return(['device_id'])
|
64
|
+
allow(message).to receive(:app).and_return('app_name')
|
65
|
+
handler = Pushr::Daemon::GcmSupport::ResponseHandler.new(response, message)
|
66
|
+
handler.handle
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'should handle NotRegistered' do
|
70
|
+
expect_any_instance_of(Pushr::FeedbackGcm).to receive(:save)
|
71
|
+
json = '{"multicast_id":7726000338213371155,"success":0,"failure":1,"canonical_ids":0,' \
|
72
|
+
'"results":[{"error":"NotRegistered"}]}'
|
73
|
+
response = double('response')
|
74
|
+
allow(response).to receive(:body).and_return(json)
|
75
|
+
|
76
|
+
message = double('message')
|
77
|
+
allow(message).to receive('registration_ids').and_return(['device_id'])
|
78
|
+
allow(message).to receive(:app).and_return('app_name')
|
79
|
+
handler = Pushr::Daemon::GcmSupport::ResponseHandler.new(response, message)
|
80
|
+
handler.handle
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pushr/feedback_gcm'
|
3
|
+
|
4
|
+
describe Pushr::FeedbackGcm do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
Pushr::Core.configure do |config|
|
8
|
+
config.redis = ConnectionPool.new(size: 1, timeout: 1) { MockRedis.new }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'create' do
|
13
|
+
it 'should create a feedback' do
|
14
|
+
feedback = Pushr::FeedbackGcm.new(app: 'app_name', device: 'ab' * 20, follow_up: 'delete', failed_at: Time.now, update_to: nil)
|
15
|
+
expect(feedback.app).to eql('app_name')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'save' do
|
20
|
+
let(:feedback) { Pushr::FeedbackGcm.new(app: 'app_name', device: 'ab' * 20, follow_up: 'delete', failed_at: Time.now, update_to: nil) }
|
21
|
+
it 'should save a feedback' do
|
22
|
+
feedback.save
|
23
|
+
feedback2 = Pushr::Feedback.next
|
24
|
+
expect(feedback2.class).to eql(Pushr::FeedbackGcm)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pushr/message_gcm'
|
3
|
+
|
4
|
+
describe Pushr::MessageGcm do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
Pushr::Core.configure do |config|
|
8
|
+
config.redis = ConnectionPool.new(size: 1, timeout: 1) { MockRedis.new }
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'next' do
|
13
|
+
it 'returns next message' do
|
14
|
+
expect(Pushr::Message.next('pushr:app_name:gcm')).to eql(nil)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'save' do
|
19
|
+
let(:message) do
|
20
|
+
hsh = { app: 'app_name', registration_ids: ['test'], collapse_key: 'x',
|
21
|
+
delay_while_idle: false, time_to_live: 24 * 60 * 60, data: {} }
|
22
|
+
Pushr::MessageGcm.new(hsh)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should return true' do
|
26
|
+
expect(message.save).to eql true
|
27
|
+
end
|
28
|
+
it 'should save a message' do
|
29
|
+
message.save
|
30
|
+
expect(Pushr::Message.next('pushr:app_name:gcm')).to be_kind_of(Pushr::MessageGcm)
|
31
|
+
end
|
32
|
+
it 'should respond to to_message' do
|
33
|
+
expect(message.to_message).to be_kind_of(String)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should contain not more than 1000 registration_ids' do
|
37
|
+
hsh = { app: 'app_name', registration_ids: ('a' * 1001).split(//) }
|
38
|
+
message = Pushr::MessageGcm.new(hsh)
|
39
|
+
expect(message.save).to eql false
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should contain more than 0 registration_ids' do
|
43
|
+
hsh = { app: 'app_name', registration_ids: [] }
|
44
|
+
message = Pushr::MessageGcm.new(hsh)
|
45
|
+
expect(message.save).to eql false
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should contain an array in registration_ids' do
|
49
|
+
hsh = { app: 'app_name', registration_ids: nil }
|
50
|
+
message = Pushr::MessageGcm.new(hsh)
|
51
|
+
expect(message.save).to eql false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
|
6
|
+
require 'simplecov'
|
7
|
+
require 'coveralls'
|
8
|
+
|
9
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
10
|
+
SimpleCov::Formatter::HTMLFormatter,
|
11
|
+
Coveralls::SimpleCov::Formatter
|
12
|
+
]
|
13
|
+
SimpleCov.start
|
14
|
+
|
15
|
+
require 'vcr'
|
16
|
+
require 'pushr/core'
|
17
|
+
require 'mock_redis'
|
18
|
+
|
19
|
+
Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
|
20
|
+
|
21
|
+
RSpec.configure do |config|
|
22
|
+
config.raise_errors_for_deprecations!
|
23
|
+
config.run_all_when_everything_filtered = true
|
24
|
+
# config.filter_run :focus
|
25
|
+
|
26
|
+
# Run specs in random order to surface order dependencies. If you find an
|
27
|
+
# order dependency and want to debug it, you can fix the order by providing
|
28
|
+
# the seed, which is printed after each run.
|
29
|
+
# --seed 1234
|
30
|
+
config.order = 'random'
|
31
|
+
|
32
|
+
config.around(:each, :vcr) do |example|
|
33
|
+
name = example.metadata[:full_description].split(/\s+/, 2).join('/').underscore.gsub(/[^\w\/]+/, '_')
|
34
|
+
options = example.metadata.slice(:record, :match_requests_on).except(:example_group)
|
35
|
+
VCR.use_cassette(name, options) { example.call }
|
36
|
+
end
|
37
|
+
end
|
data/spec/support/vcr.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://android.googleapis.com/gcm/send
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"registration_ids":["devicetoken"],"collapse_key":"x","time_to_live":86400,"data":{"test":"test"}}'
|
9
|
+
headers:
|
10
|
+
Authorization:
|
11
|
+
- key=apikey
|
12
|
+
Content-Type:
|
13
|
+
- application/json
|
14
|
+
Content-Length:
|
15
|
+
- '99'
|
16
|
+
Accept-Encoding:
|
17
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
18
|
+
Accept:
|
19
|
+
- "*/*"
|
20
|
+
User-Agent:
|
21
|
+
- Ruby
|
22
|
+
response:
|
23
|
+
status:
|
24
|
+
code: 500
|
25
|
+
message: Unauthorized
|
26
|
+
headers:
|
27
|
+
Retry-After:
|
28
|
+
- 120
|
29
|
+
Content-Type:
|
30
|
+
- text/html; charset=UTF-8
|
31
|
+
Date:
|
32
|
+
- Sat, 19 Apr 2014 10:00:22 GMT
|
33
|
+
Expires:
|
34
|
+
- Sat, 19 Apr 2014 10:00:22 GMT
|
35
|
+
Cache-Control:
|
36
|
+
- private, max-age=0
|
37
|
+
X-Content-Type-Options:
|
38
|
+
- nosniff
|
39
|
+
X-Frame-Options:
|
40
|
+
- SAMEORIGIN
|
41
|
+
X-Xss-Protection:
|
42
|
+
- 1; mode=block
|
43
|
+
Server:
|
44
|
+
- GSE
|
45
|
+
Alternate-Protocol:
|
46
|
+
- 443:quic
|
47
|
+
Transfer-Encoding:
|
48
|
+
- chunked
|
49
|
+
body:
|
50
|
+
encoding: UTF-8
|
51
|
+
string: |
|
52
|
+
<HTML>
|
53
|
+
<HEAD>
|
54
|
+
<TITLE>Unauthorized</TITLE>
|
55
|
+
</HEAD>
|
56
|
+
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
|
57
|
+
<H1>Unauthorized</H1>
|
58
|
+
<H2>Error 401</H2>
|
59
|
+
</BODY>
|
60
|
+
</HTML>
|
61
|
+
http_version:
|
62
|
+
recorded_at: Sat, 19 Apr 2014 10:00:22 GMT
|
63
|
+
recorded_with: VCR 2.9.0
|
@@ -0,0 +1,63 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://android.googleapis.com/gcm/send
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"registration_ids":["devicetoken"],"collapse_key":"x","time_to_live":86400,"data":{"test":"test"}}'
|
9
|
+
headers:
|
10
|
+
Authorization:
|
11
|
+
- key=apikey
|
12
|
+
Content-Type:
|
13
|
+
- application/json
|
14
|
+
Content-Length:
|
15
|
+
- '99'
|
16
|
+
Accept-Encoding:
|
17
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
18
|
+
Accept:
|
19
|
+
- "*/*"
|
20
|
+
User-Agent:
|
21
|
+
- Ruby
|
22
|
+
response:
|
23
|
+
status:
|
24
|
+
code: 500
|
25
|
+
message: Unauthorized
|
26
|
+
headers:
|
27
|
+
Retry-After:
|
28
|
+
- Fri, 31 Dec 1999 23:59:59 GMT
|
29
|
+
Content-Type:
|
30
|
+
- text/html; charset=UTF-8
|
31
|
+
Date:
|
32
|
+
- Sun, 20 Apr 2014 17:07:29 GMT
|
33
|
+
Expires:
|
34
|
+
- Sun, 20 Apr 2014 17:07:29 GMT
|
35
|
+
Cache-Control:
|
36
|
+
- private, max-age=0
|
37
|
+
X-Content-Type-Options:
|
38
|
+
- nosniff
|
39
|
+
X-Frame-Options:
|
40
|
+
- SAMEORIGIN
|
41
|
+
X-Xss-Protection:
|
42
|
+
- 1; mode=block
|
43
|
+
Server:
|
44
|
+
- GSE
|
45
|
+
Alternate-Protocol:
|
46
|
+
- 443:quic
|
47
|
+
Transfer-Encoding:
|
48
|
+
- chunked
|
49
|
+
body:
|
50
|
+
encoding: UTF-8
|
51
|
+
string: |
|
52
|
+
<HTML>
|
53
|
+
<HEAD>
|
54
|
+
<TITLE>Unauthorized</TITLE>
|
55
|
+
</HEAD>
|
56
|
+
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
|
57
|
+
<H1>Unauthorized</H1>
|
58
|
+
<H2>Error 401</H2>
|
59
|
+
</BODY>
|
60
|
+
</HTML>
|
61
|
+
http_version:
|
62
|
+
recorded_at: Sun, 20 Apr 2014 17:07:29 GMT
|
63
|
+
recorded_with: VCR 2.9.0
|
@@ -0,0 +1,61 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://android.googleapis.com/gcm/send
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"registration_ids":["devicetoken"],"collapse_key":"x","time_to_live":86400,"data":{"test":"test"}}'
|
9
|
+
headers:
|
10
|
+
Authorization:
|
11
|
+
- key=apikey
|
12
|
+
Content-Type:
|
13
|
+
- application/json
|
14
|
+
Content-Length:
|
15
|
+
- '99'
|
16
|
+
Accept-Encoding:
|
17
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
18
|
+
Accept:
|
19
|
+
- "*/*"
|
20
|
+
User-Agent:
|
21
|
+
- Ruby
|
22
|
+
response:
|
23
|
+
status:
|
24
|
+
code: 500
|
25
|
+
message: Unauthorized
|
26
|
+
headers:
|
27
|
+
Content-Type:
|
28
|
+
- text/html; charset=UTF-8
|
29
|
+
Date:
|
30
|
+
- Sun, 20 Apr 2014 17:51:10 GMT
|
31
|
+
Expires:
|
32
|
+
- Sun, 20 Apr 2014 17:51:10 GMT
|
33
|
+
Cache-Control:
|
34
|
+
- private, max-age=0
|
35
|
+
X-Content-Type-Options:
|
36
|
+
- nosniff
|
37
|
+
X-Frame-Options:
|
38
|
+
- SAMEORIGIN
|
39
|
+
X-Xss-Protection:
|
40
|
+
- 1; mode=block
|
41
|
+
Server:
|
42
|
+
- GSE
|
43
|
+
Alternate-Protocol:
|
44
|
+
- 443:quic
|
45
|
+
Transfer-Encoding:
|
46
|
+
- chunked
|
47
|
+
body:
|
48
|
+
encoding: UTF-8
|
49
|
+
string: |
|
50
|
+
<HTML>
|
51
|
+
<HEAD>
|
52
|
+
<TITLE>Unauthorized</TITLE>
|
53
|
+
</HEAD>
|
54
|
+
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
|
55
|
+
<H1>Unauthorized</H1>
|
56
|
+
<H2>Error 401</H2>
|
57
|
+
</BODY>
|
58
|
+
</HTML>
|
59
|
+
http_version:
|
60
|
+
recorded_at: Sun, 20 Apr 2014 17:51:10 GMT
|
61
|
+
recorded_with: VCR 2.9.0
|
@@ -0,0 +1,61 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://android.googleapis.com/gcm/send
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"registration_ids":["devicetoken"],"collapse_key":"x","time_to_live":86400,"data":{"test":"test"}}'
|
9
|
+
headers:
|
10
|
+
Authorization:
|
11
|
+
- key=apikey
|
12
|
+
Content-Type:
|
13
|
+
- application/json
|
14
|
+
Content-Length:
|
15
|
+
- '99'
|
16
|
+
Accept-Encoding:
|
17
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
18
|
+
Accept:
|
19
|
+
- "*/*"
|
20
|
+
User-Agent:
|
21
|
+
- Ruby
|
22
|
+
response:
|
23
|
+
status:
|
24
|
+
code: 400
|
25
|
+
message: Unauthorized
|
26
|
+
headers:
|
27
|
+
Content-Type:
|
28
|
+
- text/html; charset=UTF-8
|
29
|
+
Date:
|
30
|
+
- Sun, 20 Apr 2014 18:26:50 GMT
|
31
|
+
Expires:
|
32
|
+
- Sun, 20 Apr 2014 18:26:50 GMT
|
33
|
+
Cache-Control:
|
34
|
+
- private, max-age=0
|
35
|
+
X-Content-Type-Options:
|
36
|
+
- nosniff
|
37
|
+
X-Frame-Options:
|
38
|
+
- SAMEORIGIN
|
39
|
+
X-Xss-Protection:
|
40
|
+
- 1; mode=block
|
41
|
+
Server:
|
42
|
+
- GSE
|
43
|
+
Alternate-Protocol:
|
44
|
+
- 443:quic
|
45
|
+
Transfer-Encoding:
|
46
|
+
- chunked
|
47
|
+
body:
|
48
|
+
encoding: UTF-8
|
49
|
+
string: |
|
50
|
+
<HTML>
|
51
|
+
<HEAD>
|
52
|
+
<TITLE>Unauthorized</TITLE>
|
53
|
+
</HEAD>
|
54
|
+
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
|
55
|
+
<H1>Unauthorized</H1>
|
56
|
+
<H2>Error 401</H2>
|
57
|
+
</BODY>
|
58
|
+
</HTML>
|
59
|
+
http_version:
|
60
|
+
recorded_at: Sun, 20 Apr 2014 18:26:50 GMT
|
61
|
+
recorded_with: VCR 2.9.0
|
@@ -0,0 +1,61 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://android.googleapis.com/gcm/send
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"registration_ids":["devicetoken"],"collapse_key":"x","time_to_live":86400,"data":{"test":"test"}}'
|
9
|
+
headers:
|
10
|
+
Authorization:
|
11
|
+
- key=apikey
|
12
|
+
Content-Type:
|
13
|
+
- application/json
|
14
|
+
Content-Length:
|
15
|
+
- '99'
|
16
|
+
Accept-Encoding:
|
17
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
18
|
+
Accept:
|
19
|
+
- "*/*"
|
20
|
+
User-Agent:
|
21
|
+
- Ruby
|
22
|
+
response:
|
23
|
+
status:
|
24
|
+
code: 401
|
25
|
+
message: Unauthorized
|
26
|
+
headers:
|
27
|
+
Content-Type:
|
28
|
+
- text/html; charset=UTF-8
|
29
|
+
Date:
|
30
|
+
- Sun, 20 Apr 2014 18:31:58 GMT
|
31
|
+
Expires:
|
32
|
+
- Sun, 20 Apr 2014 18:31:58 GMT
|
33
|
+
Cache-Control:
|
34
|
+
- private, max-age=0
|
35
|
+
X-Content-Type-Options:
|
36
|
+
- nosniff
|
37
|
+
X-Frame-Options:
|
38
|
+
- SAMEORIGIN
|
39
|
+
X-Xss-Protection:
|
40
|
+
- 1; mode=block
|
41
|
+
Server:
|
42
|
+
- GSE
|
43
|
+
Alternate-Protocol:
|
44
|
+
- 443:quic
|
45
|
+
Transfer-Encoding:
|
46
|
+
- chunked
|
47
|
+
body:
|
48
|
+
encoding: UTF-8
|
49
|
+
string: |
|
50
|
+
<HTML>
|
51
|
+
<HEAD>
|
52
|
+
<TITLE>Unauthorized</TITLE>
|
53
|
+
</HEAD>
|
54
|
+
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
|
55
|
+
<H1>Unauthorized</H1>
|
56
|
+
<H2>Error 401</H2>
|
57
|
+
</BODY>
|
58
|
+
</HTML>
|
59
|
+
http_version:
|
60
|
+
recorded_at: Sun, 20 Apr 2014 18:31:58 GMT
|
61
|
+
recorded_with: VCR 2.9.0
|
@@ -0,0 +1,52 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: post
|
5
|
+
uri: https://android.googleapis.com/gcm/send
|
6
|
+
body:
|
7
|
+
encoding: UTF-8
|
8
|
+
string: '{"registration_ids":["devicetoken"],"collapse_key":"x","time_to_live":86400,"data":{"test":"test"}}'
|
9
|
+
headers:
|
10
|
+
Authorization:
|
11
|
+
- key=apikey
|
12
|
+
Content-Type:
|
13
|
+
- application/json
|
14
|
+
Content-Length:
|
15
|
+
- '99'
|
16
|
+
Accept-Encoding:
|
17
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
18
|
+
Accept:
|
19
|
+
- "*/*"
|
20
|
+
User-Agent:
|
21
|
+
- Ruby
|
22
|
+
response:
|
23
|
+
status:
|
24
|
+
code: 200
|
25
|
+
message: OK
|
26
|
+
headers:
|
27
|
+
Content-Type:
|
28
|
+
- application/json; charset=UTF-8
|
29
|
+
Date:
|
30
|
+
- Thu, 17 Apr 2014 20:38:18 GMT
|
31
|
+
Expires:
|
32
|
+
- Thu, 17 Apr 2014 20:38:18 GMT
|
33
|
+
Cache-Control:
|
34
|
+
- private, max-age=0
|
35
|
+
X-Content-Type-Options:
|
36
|
+
- nosniff
|
37
|
+
X-Frame-Options:
|
38
|
+
- SAMEORIGIN
|
39
|
+
X-Xss-Protection:
|
40
|
+
- 1; mode=block
|
41
|
+
Server:
|
42
|
+
- GSE
|
43
|
+
Alternate-Protocol:
|
44
|
+
- 443:quic
|
45
|
+
Transfer-Encoding:
|
46
|
+
- chunked
|
47
|
+
body:
|
48
|
+
encoding: UTF-8
|
49
|
+
string: '{"multicast_id":7726000338213371155,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1397767098298993%00525e0300000078"}]}'
|
50
|
+
http_version:
|
51
|
+
recorded_at: Thu, 17 Apr 2014 20:38:17 GMT
|
52
|
+
recorded_with: VCR 2.9.0
|
metadata
ADDED
@@ -0,0 +1,263 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pushr-gcm
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0.pre.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Tom Pesman
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: multi_json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pushr-core
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activemodel
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.0.0.beta2
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.0.0.beta2
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: guard
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: guard-rspec
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: mock_redis
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: simplecov
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: webmock
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "<"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '1.16'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "<"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '1.16'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: vcr
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: rake
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: coveralls
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :development
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: rubocop
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
description: GCM support for the modular push daemon.
|
196
|
+
email:
|
197
|
+
- tom@tnux.net
|
198
|
+
executables: []
|
199
|
+
extensions: []
|
200
|
+
extra_rdoc_files: []
|
201
|
+
files:
|
202
|
+
- lib/pushr-gcm/version.rb
|
203
|
+
- lib/pushr/configuration_gcm.rb
|
204
|
+
- lib/pushr/daemon/gcm.rb
|
205
|
+
- lib/pushr/daemon/gcm_support/connection_gcm.rb
|
206
|
+
- lib/pushr/daemon/gcm_support/response_handler.rb
|
207
|
+
- lib/pushr/feedback_gcm.rb
|
208
|
+
- lib/pushr/gcm.rb
|
209
|
+
- lib/pushr/message_gcm.rb
|
210
|
+
- README.md
|
211
|
+
- MIT-LICENSE
|
212
|
+
- spec/lib/pushr/configuration_gcm_spec.rb
|
213
|
+
- spec/lib/pushr/daemon/gcm_spec.rb
|
214
|
+
- spec/lib/pushr/daemon/gcm_support/connection_gcm_spec.rb
|
215
|
+
- spec/lib/pushr/daemon/gcm_support/response_handler_spec.rb
|
216
|
+
- spec/lib/pushr/feedback_gcm_spec.rb
|
217
|
+
- spec/lib/pushr/message_gcm_spec.rb
|
218
|
+
- spec/spec_helper.rb
|
219
|
+
- spec/support/vcr.rb
|
220
|
+
- spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_fails_and_should_retry_after.yml
|
221
|
+
- spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_fails_and_should_retry_after_with_date.yml
|
222
|
+
- spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_fails_and_should_sleep_after_fail.yml
|
223
|
+
- spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_fails_of_a_json_formatting_execption.yml
|
224
|
+
- spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_fails_of_a_not_authenticated_execption.yml
|
225
|
+
- spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_succesful.yml
|
226
|
+
homepage: https://github.com/9to5/pushr-gcm
|
227
|
+
licenses: []
|
228
|
+
metadata: {}
|
229
|
+
post_install_message:
|
230
|
+
rdoc_options: []
|
231
|
+
require_paths:
|
232
|
+
- lib
|
233
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
234
|
+
requirements:
|
235
|
+
- - ">="
|
236
|
+
- !ruby/object:Gem::Version
|
237
|
+
version: '0'
|
238
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
239
|
+
requirements:
|
240
|
+
- - ">"
|
241
|
+
- !ruby/object:Gem::Version
|
242
|
+
version: 1.3.1
|
243
|
+
requirements: []
|
244
|
+
rubyforge_project:
|
245
|
+
rubygems_version: 2.1.11
|
246
|
+
signing_key:
|
247
|
+
specification_version: 4
|
248
|
+
summary: GCM (Android) part of the modular push daemon.
|
249
|
+
test_files:
|
250
|
+
- spec/lib/pushr/configuration_gcm_spec.rb
|
251
|
+
- spec/lib/pushr/daemon/gcm_spec.rb
|
252
|
+
- spec/lib/pushr/daemon/gcm_support/connection_gcm_spec.rb
|
253
|
+
- spec/lib/pushr/daemon/gcm_support/response_handler_spec.rb
|
254
|
+
- spec/lib/pushr/feedback_gcm_spec.rb
|
255
|
+
- spec/lib/pushr/message_gcm_spec.rb
|
256
|
+
- spec/spec_helper.rb
|
257
|
+
- spec/support/vcr.rb
|
258
|
+
- spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_fails_and_should_retry_after.yml
|
259
|
+
- spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_fails_and_should_retry_after_with_date.yml
|
260
|
+
- spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_fails_and_should_sleep_after_fail.yml
|
261
|
+
- spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_fails_of_a_json_formatting_execption.yml
|
262
|
+
- spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_fails_of_a_not_authenticated_execption.yml
|
263
|
+
- spec/vcr/pushr/daemon/gcm_support/connection_gcm/sends_a_message_succesful.yml
|