mercurius 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,20 @@
1
+ describe APNS::Notification do
2
+
3
+ describe '#==' do
4
+ it 'doesnt care about object equality' do
5
+ a = APNS::Notification.new(alert: '1', badge: 1, other: { a: :b }, sound: 'default')
6
+ b = APNS::Notification.new(alert: '1', badge: 1, other: { a: :b }, sound: 'default')
7
+ expect(a == b).to eq true
8
+ end
9
+
10
+ %w(alert badge other sound).each do |attr|
11
+ it "must match #{attr} to be considered equal" do
12
+ attributes = { alert: '1', badge: 1, other: { a: :b }, sound: 'default' }
13
+ a = APNS::Notification.new(attributes)
14
+ b = APNS::Notification.new(attributes.merge(attr => SecureRandom.hex))
15
+ expect(a == b).to eq false
16
+ end
17
+ end
18
+ end
19
+
20
+ end
data/spec/spec_helper.rb CHANGED
@@ -1 +1,5 @@
1
1
  require 'mercurius'
2
+ require 'webmock/rspec'
3
+ require 'support/fake_socket'
4
+
5
+ WebMock.disable_net_connect!
@@ -0,0 +1,61 @@
1
+ Bag Attributes
2
+ friendlyName: Fake APNs Provider Certificate
3
+ localKeyID: C0 9A 0E C0 77 F5 7A A4 71 1B 07 9D 10 0E 2D FB 8C B5 62 BC
4
+ subject=/CN=Fake APNs Provider Certificate/O=Fake Provider/OU=Fake Notification Sending Division/ST=Fake Tennessee/C=US/L=Fake Franklin/emailAddress=support@metova.com
5
+ issuer=/CN=Fake APNs Certificate Authority/O=Fake Apple/OU=Fake Certificate Signing Division/ST=Fake California/C=US/L=Fake Cupertino/emailAddress=support@metova.com
6
+ -----BEGIN CERTIFICATE-----
7
+ MIIENDCCAxygAwIBAgIBAjALBgkqhkiG9w0BAQswgcoxKDAmBgNVBAMMH0Zha2Ug
8
+ QVBOcyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxEzARBgNVBAoMCkZha2UgQXBwbGUx
9
+ KjAoBgNVBAsMIUZha2UgQ2VydGlmaWNhdGUgU2lnbmluZyBEaXZpc2lvbjEYMBYG
10
+ A1UECAwPRmFrZSBDYWxpZm9ybmlhMQswCQYDVQQGEwJVUzEXMBUGA1UEBwwORmFr
11
+ ZSBDdXBlcnRpbm8xHTAbBgkqhkiG9w0BCQEWDmluZm9Ad2F2aWkuY29tMB4XDTEy
12
+ MDQwNDIwNTYzNloXDTEzMDQwNDIwNTYzNlowgcsxJzAlBgNVBAMMHkZha2UgQVBO
13
+ cyBQcm92aWRlciBDZXJ0aWZpY2F0ZTEWMBQGA1UECgwNRmFrZSBQcm92aWRlcjEr
14
+ MCkGA1UECwwiRmFrZSBOb3RpZmljYXRpb24gU2VuZGluZyBEaXZpc2lvbjEYMBYG
15
+ A1UECAwPRmFrZSBXYXNoaW5ndG9uMQswCQYDVQQGEwJVUzEVMBMGA1UEBwwMRmFr
16
+ ZSBTZWF0dGxlMR0wGwYJKoZIhvcNAQkBFg5pbmZvQHdhdmlpLmNvbTCCASIwDQYJ
17
+ KoZIhvcNAQEBBQADggEPADCCAQoCggEBALeeRtyoGCoyTZPLr4mjbK8nQpbwcf6/
18
+ 2GlkqDDaYy17kFjZXA3ZrdPncWnC1gA+93ZAtvy/a1PdSyKMNrTdkqmiId4EzRl5
19
+ oEFVAEXYSy5DmL78KiMYfmhGXtusq+mj0HvsBHRRsTESqmRhwHj8Th4wYBp6w4jr
20
+ UmFDIP2FuTqck1WgtgsVQMgVgrgyUUDCzejMfGxBkvavP9TRmYqlZPqRkadMoads
21
+ T+JTA8JAa7srtQVmdfCg0PvIKZxegIAiGjdoO0ZoWSlS2fWFzDKfsIybXbqinO/s
22
+ Og5C9ITAYR5+A/pBYXv+R3MOvYLxZ4SgHFOqs4J0oF26324jovt1FWkCAwEAAaMk
23
+ MCIwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEB
24
+ CwUAA4IBAQCfsBLbFlCfMFA1t5o4C1QWMA3tfM+MyGUDSJ4qIWFF1/zBQl8bSTc/
25
+ XkUaNZ42R/NZ+anwyPlYNK/N7JBC5nJiIDkn+SF/ifXUMZcJ6ryWwEIuM9oPf+yM
26
+ LABztG23gD6RbFw5n3PhO2IsO8dKa2HS4yxBPWAJuOnn9A+H87G+Vy7f7hc9ZgR+
27
+ BmUNVj9Wm+NBrZrWU431HbLUyi2udD2vDfXk2LopBUN05iOD7BqHEUbdeQ5bPxe5
28
+ 7smdpmEV3QrbpfCfWtoV28OJ/EA0qB0GwihJ3Pkx3V7SaASOwEwhhiwHQDPN/Ksy
29
+ lG47dCmL1Q47TN9Rzv7LnCSuKXuEycxo
30
+ -----END CERTIFICATE-----
31
+ Bag Attributes
32
+ friendlyName: Fake APNs Provider Certificate
33
+ localKeyID: C0 9A 0E C0 77 F5 7A A4 71 1B 07 9D 10 0E 2D FB 8C B5 62 BC
34
+ Key Attributes: <No Attributes>
35
+ -----BEGIN RSA PRIVATE KEY-----
36
+ MIIEowIBAAKCAQEAt55G3KgYKjJNk8uviaNsrydClvBx/r/YaWSoMNpjLXuQWNlc
37
+ Ddmt0+dxacLWAD73dkC2/L9rU91LIow2tN2SqaIh3gTNGXmgQVUARdhLLkOYvvwq
38
+ Ixh+aEZe26yr6aPQe+wEdFGxMRKqZGHAePxOHjBgGnrDiOtSYUMg/YW5OpyTVaC2
39
+ CxVAyBWCuDJRQMLN6Mx8bEGS9q8/1NGZiqVk+pGRp0yhp2xP4lMDwkBruyu1BWZ1
40
+ 8KDQ+8gpnF6AgCIaN2g7RmhZKVLZ9YXMMp+wjJtduqKc7+w6DkL0hMBhHn4D+kFh
41
+ e/5Hcw69gvFnhKAcU6qzgnSgXbrfbiOi+3UVaQIDAQABAoIBAAKv1zudXhUn/Uif
42
+ X2c1M/7wJSJOTGy84+7O4UMtvuvIdhlGvPka6VdDeL5icn04bqiVU9go+OoWP+Y2
43
+ hQpqf53p2HMGQPYReI3cL4/WFWuM46xPxlITJq5h8TtnsHBPzFoz3vDQzTX5nvKv
44
+ F4DtuDrq3E0m5LuZLfBsagwrq8U2xPzIQaRVfl+BGATOFBa30hSwNByqMHW3AuMd
45
+ 5qZQAAXa5C2OhWTEV5sfqQT3hJN/fHgn2gSOi3R3CW8F9yEx0M4ECR+kYb0NdYt/
46
+ FczNtgnrneK60yhQnOkX19Tr5MGvj44GryLndxAkrFTp5ipfBm+Gc26XKNkfoWJ+
47
+ ovzT1n0CgYEA2Q5umhJudO3W13WsKOxoU7ErtewemzDpYb0CrxdI9/i9Fxi1QV7C
48
+ +JSSf0XFKu+nW50D8jMJ60WwU4WX4v8DoG3M0vrXiJ0CZyIClFWgvk+VWi0hGh9b
49
+ e3PcjNMIKQNK2FyOnOwUnL0DerNFMtYD1kLkDS5CsjGY4VYGPVFRx1sCgYEA2JAB
50
+ rdUcmN3bfixXeHedRGzw6YFkEbEXqKt8Oa0dVlsDL20JX/Cj5xAESIXyswsIfuAo
51
+ Rjv4mI/J6lxXhoEiNo/9VsNJ+QH77zv8mVPqs1Z5pxjtp1lNag9jOMZZAX6vgJ1e
52
+ Glx/stLxxkIhX5aI1ppIZXNFCIY7e8qx9OPYNYsCgYBAw/imimdhBnK7mYYEM/4x
53
+ MsVLJChBwEdy/XXmjrkcHKE3Wg0Dc2YTzCkmRsg9NoMmZ+R8iVQlWobxdQRMHDGV
54
+ 1g1uyqAzSD4mTdSdNCuhfZef76VX6RFf9cNSVcmyiyPzCTMYiazg09lM7F7yez9r
55
+ 2Eu5zxrhlsD6Q7Pa6f/PzwKBgQCitPd9+mrk83MQxhHmAcCYA12xorRjknFbGZRY
56
+ 5Rbwpaqr/DkZ6vvKA7+kGXdyS6zTXmkD89TgEtA6k6xy8xyYb/CAOnOecX4ujRxI
57
+ usLQgP0frVwI6tB+ChebNXLz65HCiPmFxs9utIxQT6kxXzFqQzp3dnZ8ZBXW+UBg
58
+ 5Lqx5wKBgFIi2DP5/cF5nUDqOtiQTzl0MeJWW3w3UBS9jQF7Cx00YyLSqIF1batv
59
+ Zk0Yq5w/2oh9C5EDrf8eyCYfK3iU2Ij4Jy6N6zITjRhW/kxxZigjmcTb/Tsme2Xh
60
+ IFo5RoAfOV1dPiXM4oqZFPNmppAxiZH2ohEmo593DHYosQHMjXYG
61
+ -----END RSA PRIVATE KEY-----
@@ -0,0 +1,30 @@
1
+ class FakeSocket < StringIO
2
+ attr_reader :wrote
3
+
4
+ def initialize(*)
5
+ @_open = false
6
+ super
7
+ end
8
+
9
+ def write(data)
10
+ @wrote ||= []
11
+ @wrote << data
12
+ super
13
+ end
14
+
15
+ def read
16
+ end
17
+
18
+ def connect
19
+ @_open = true
20
+ end
21
+
22
+ def close
23
+ @_open = false
24
+ end
25
+
26
+ def closed?
27
+ @_open == false
28
+ end
29
+
30
+ end
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mercurius
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
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-01-28 00:00:00.000000000 Z
11
+ date: 2015-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: httparty
14
+ name: json
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
@@ -25,7 +25,7 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: json
28
+ name: faraday
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - ">="
@@ -38,6 +38,48 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: faraday_middleware
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: activemodel
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 4.0.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 4.0.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 4.1.0
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 4.1.0
41
83
  - !ruby/object:Gem::Dependency
42
84
  name: rake
43
85
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +108,20 @@ dependencies:
66
108
  - - ">="
67
109
  - !ruby/object:Gem::Version
68
110
  version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: webmock
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'
69
125
  description: |2
70
126
  This gem is a wrapper to send push notifications to devices through native push services.
71
127
  email:
@@ -75,6 +131,7 @@ extensions: []
75
131
  extra_rdoc_files: []
76
132
  files:
77
133
  - ".gitignore"
134
+ - ".rspec"
78
135
  - ".ruby-gemset"
79
136
  - ".ruby-version"
80
137
  - ".travis.yml"
@@ -83,16 +140,28 @@ files:
83
140
  - README.md
84
141
  - Rakefile
85
142
  - lib/mercurius.rb
86
- - lib/mercurius/android.rb
87
- - lib/mercurius/apns/core.rb
143
+ - lib/mercurius/apns.rb
144
+ - lib/mercurius/apns/connection.rb
88
145
  - lib/mercurius/apns/notification.rb
89
- - lib/mercurius/apple.rb
90
- - lib/mercurius/gcm/core.rb
146
+ - lib/mercurius/apns/pem.rb
147
+ - lib/mercurius/apns/service.rb
148
+ - lib/mercurius/errors/pem_not_configured_error.rb
149
+ - lib/mercurius/errors/pem_not_found_error.rb
150
+ - lib/mercurius/errors/too_many_retries_error.rb
151
+ - lib/mercurius/gcm.rb
152
+ - lib/mercurius/gcm/connection.rb
91
153
  - lib/mercurius/gcm/notification.rb
154
+ - lib/mercurius/gcm/response.rb
155
+ - lib/mercurius/gcm/result.rb
156
+ - lib/mercurius/gcm/service.rb
92
157
  - lib/mercurius/version.rb
93
158
  - mercurius.gemspec
94
- - spec/lib/mercurius_spec.rb
159
+ - spec/lib/apns_service_spec.rb
160
+ - spec/lib/gcm_service_spec.rb
161
+ - spec/lib/notification_spec.rb
95
162
  - spec/spec_helper.rb
163
+ - spec/support/apns.pem
164
+ - spec/support/fake_socket.rb
96
165
  homepage: https://github.com/jrbeck/mercurius
97
166
  licenses: []
98
167
  metadata: {}
@@ -117,5 +186,9 @@ signing_key:
117
186
  specification_version: 4
118
187
  summary: Send push notifications to mobile devices through native services
119
188
  test_files:
120
- - spec/lib/mercurius_spec.rb
189
+ - spec/lib/apns_service_spec.rb
190
+ - spec/lib/gcm_service_spec.rb
191
+ - spec/lib/notification_spec.rb
121
192
  - spec/spec_helper.rb
193
+ - spec/support/apns.pem
194
+ - spec/support/fake_socket.rb
@@ -1,2 +0,0 @@
1
- require "mercurius/gcm/core"
2
- require "mercurius/gcm/notification"
@@ -1,128 +0,0 @@
1
- require 'socket'
2
- require 'openssl'
3
- require 'json'
4
-
5
- module APNS
6
- class Error < Exception; end
7
- class ConfigurationError < Error; end
8
-
9
- @host = 'gateway.sandbox.push.apple.com'
10
- @port = 2195
11
- @pem_path = nil
12
- @pem_password = nil
13
- @pem_data = nil
14
-
15
- @persistent = false
16
- @mutex = Mutex.new
17
- @retries = 3 # TODO: check if we really need this
18
-
19
- @sock = nil
20
- @ssl = nil
21
-
22
- class << self
23
- attr_accessor :host, :port, :pem_path, :pem_password, :pem_data
24
- end
25
-
26
- def self.start_persistence
27
- @persistent = true
28
- end
29
-
30
- def self.stop_persistence
31
- @persistent = false
32
- self.close_connection
33
- end
34
-
35
- def self.send_notification(device_token, message)
36
- notification = APNS::Notification.new(device_token, message)
37
- send_notifications([notification])
38
- end
39
-
40
- def self.send_notifications(notifications)
41
- @mutex.synchronize do
42
- with_connection do
43
- notifications.each do |n|
44
- @ssl.write(n.packaged_notification)
45
- end
46
- end
47
- end
48
- end
49
-
50
- def self.feedback
51
- sock, ssl = feedback_connection
52
- apns_feedback = []
53
-
54
- # read lines from the socket
55
- while line = ssl.read(38)
56
- line.strip!
57
- f = line.unpack('N1n1H140')
58
- apns_feedback << { timestamp: Time.at(f[0]), token: f[2] }
59
- end
60
-
61
- ssl.close
62
- sock.close
63
-
64
- apns_feedback
65
- end
66
-
67
- protected
68
-
69
- def self.with_connection
70
- attempts = 1
71
-
72
- begin
73
- open_connection if connection_closed?
74
- yield
75
- rescue StandardError, Errno::EPIPE
76
- raise Error.new("Failed after #{@retries} attempts.") unless attempts < @retries
77
- close_connection
78
- attempts += 1
79
- retry
80
- end
81
-
82
- close_connection unless @persistent
83
- end
84
-
85
- def self.open_connection
86
- @sock = TCPSocket.new(self.host, self.port)
87
- @ssl = OpenSSL::SSL::SSLSocket.new(@sock, context)
88
- @ssl.connect
89
- end
90
-
91
- def self.close_connection
92
- @ssl.close
93
- @ssl = nil
94
- @sock.close
95
- @sock = nil
96
- end
97
-
98
- def self.connection_closed?
99
- @ssl.nil? || @sock.nil? || @ssl.closed? || @sock.closed?
100
- end
101
-
102
- def self.feedback_connection
103
- fhost = self.host.gsub('gateway','feedback')
104
- sock = TCPSocket.new(fhost, 2196)
105
- ssl = OpenSSL::SSL::SSLSocket.new(sock, context)
106
- ssl.connect
107
- return sock, ssl
108
- end
109
-
110
- def self.context
111
- context = OpenSSL::SSL::SSLContext.new
112
- context.cert = OpenSSL::X509::Certificate.new(pem_data)
113
- context.key = OpenSSL::PKey::RSA.new(pem_data, pem_password)
114
- context
115
- end
116
-
117
- def self.pem_data
118
- return @pem_data if @pem_data
119
-
120
- if @pem_path
121
- raise ConfigurationError.new('The specified PEM file does not exist.') unless File.exist?(@pem_path)
122
- @pem_data = File.read(@pem_path)
123
- else
124
- raise ConfigurationError.new('PEM not configured properly.')
125
- end
126
- end
127
-
128
- end
@@ -1,2 +0,0 @@
1
- require "mercurius/apns/core"
2
- require "mercurius/apns/notification"
@@ -1,113 +0,0 @@
1
- require 'httparty'
2
- require 'json'
3
-
4
- module GCM
5
- include HTTParty
6
-
7
- @host = 'https://android.googleapis.com/gcm/send'
8
- @format = :json
9
- @key = nil
10
-
11
- class << self
12
- attr_accessor :host, :format, :key
13
-
14
- def key(identity = nil)
15
- if @key.is_a?(Hash)
16
- raise %{If your key is a hash of keys you'll need to pass a identifier to the notification!} if identity.nil?
17
- return @key[identity]
18
- else
19
- return @key
20
- end
21
- end
22
-
23
- def key_identities
24
- if @key.is_a?(Hash)
25
- return @key.keys
26
- else
27
- return nil
28
- end
29
- end
30
- end
31
-
32
- def self.send_notification(device_tokens, data = {}, options = {})
33
- n = GCM::Notification.new(device_tokens, data, options)
34
- self.send_notifications([n])
35
- end
36
-
37
- def self.send_notifications(notifications)
38
- responses = []
39
- notifications.each do |n|
40
- responses << self.prepare_and_send(n)
41
- end
42
- responses
43
- end
44
-
45
- private
46
-
47
- def self.prepare_and_send(n)
48
- if n.device_tokens.count < 1 || n.device_tokens.count > 1000
49
- raise "Number of device tokens must be between 1 and 1000"
50
- end
51
- if !n.collapse_key.nil? && n.time_to_live.nil?
52
- raise %q{If you are defining a "collapse key" you need a "time to live"}
53
- end
54
- if @key.is_a?(Hash) && n.identity.nil?
55
- raise %{If your key is a Hash of keys you'll need to pass a identifier to the notification!}
56
- end
57
-
58
- if self.format == :json
59
- self.send_push_as_json(n)
60
- elsif self.format == :text
61
- self.send_push_as_plain_text(n)
62
- else
63
- raise "Invalid format"
64
- end
65
- end
66
-
67
- def self.send_push_as_json(n)
68
- headers = {
69
- 'Authorization' => "key=#{ self.key(n.identity) }",
70
- 'Content-Type' => 'application/json',
71
- }
72
- body = {
73
- registration_ids: n.device_tokens,
74
- data: n.data,
75
- collapse_key: n.collapse_key,
76
- time_to_live: n.time_to_live,
77
- delay_while_idle: n.delay_while_idle
78
- }
79
- return self.send_to_server(headers, body.to_json)
80
- end
81
-
82
- def self.send_push_as_plain_text(n)
83
- raise "Still has to be done: http://developer.android.com/guide/google/gcm/gcm.html"
84
- headers = {
85
- # TODO: Aceitar key ser um hash
86
- 'Authorization' => "key=#{ self.key(n.identity) }",
87
- 'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8',
88
- }
89
- return self.send_to_server(headers, body)
90
- end
91
-
92
- def self.send_to_server(headers, body)
93
- params = { headers: headers, body: body}
94
- response = self.post(self.host, params)
95
- build_response(response)
96
- end
97
-
98
- def self.build_response(response)
99
- case response.code
100
- when 200
101
- { response: 'success', body: JSON.parse(response.body), headers: response.headers, status_code: response.code }
102
- when 400
103
- { response: 'Only applies for JSON requests. Indicates that the request could not be parsed as JSON, or it contained invalid fields.', status_code: response.code }
104
- when 401
105
- { response: 'There was an error authenticating the sender account.', status_code: response.code }
106
- when 500
107
- { response: 'There was an internal error in the GCM server while trying to process the request.', status_code: response.code }
108
- when 503
109
- { response: 'Server is temporarily unavailable.', status_code: response.code }
110
- end
111
- end
112
-
113
- end
@@ -1,148 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Mercurius do
4
- describe "APNS" do
5
- it "should have an APNS object" do
6
- defined?(APNS).should_not be_false
7
- end
8
-
9
- it "should not forget the APNS default parameters" do
10
- APNS.host.should == "gateway.sandbox.push.apple.com"
11
- APNS.port.should == 2195
12
- APNS.pem_path.should be_equal(nil)
13
- APNS.pem_password.should be_equal(nil)
14
- end
15
-
16
- describe "Notifications" do
17
- describe "#==" do
18
- it "should properly equate objects without caring about object identity" do
19
- a = APNS::Notification.new("123", {:alert => "hi"})
20
- b = APNS::Notification.new("123", {:alert => "hi"})
21
- a.should eq(b)
22
- end
23
- end
24
- end
25
-
26
- describe '.send_notification' do
27
- let(:token) { 'token' }
28
- let(:message) { 'message' }
29
- let(:pem_data) { 'pem_data' }
30
- let(:cert) { double }
31
- let(:key) { double }
32
- let(:sock) { double(close: nil) }
33
- let(:ssl) { double(connect: nil, write: nil, close: nil) }
34
- let(:packaged) { 'packaged' }
35
-
36
- after do
37
- APNS.pem_path = nil
38
- APNS.pem_data = nil
39
- end
40
-
41
- before do
42
- allow(OpenSSL::X509::Certificate).to receive(:new).
43
- with(pem_data).and_return(cert)
44
- allow(OpenSSL::PKey::RSA).to receive(:new).
45
- with(pem_data, anything).and_return(key)
46
- allow(TCPSocket).to receive(:new).and_return(sock)
47
- allow(OpenSSL::SSL::SSLSocket).to receive(:new).and_return(ssl)
48
- end
49
-
50
- shared_examples 'notifications' do
51
- it 'notifications are sent' do
52
- expect(ssl).to have_received(:write).with(/"#{message}"/)
53
- end
54
- end
55
-
56
- context 'with pem setting' do
57
- context 'with an existing pem file' do
58
- let(:path) { '/good/path' }
59
-
60
- before do
61
- allow(File).to receive(:exist?).with(path).and_return(true)
62
- allow(File).to receive(:read).with(path).and_return(pem_data)
63
- end
64
-
65
- before { APNS.pem_path = '/good/path' }
66
- before { APNS.send_notification(token, message) }
67
-
68
- include_examples 'notifications'
69
- end
70
-
71
- context 'when the pem does not exist' do
72
- before { APNS.pem_path = '/bad/path' }
73
-
74
- it 'fails' do
75
- expect do
76
- APNS.send_notification(token, message)
77
- end.to raise_error(APNS::ConfigurationError, /does not exist/)
78
- end
79
- end
80
- end
81
-
82
- context 'with pem_data' do
83
- before { APNS.pem_data = pem_data }
84
- before { APNS.send_notification(token, message) }
85
-
86
- include_examples 'notifications'
87
- end
88
-
89
- context 'without pem or pem_data' do
90
- before { APNS.pem_path = nil }
91
-
92
- it 'fails' do
93
- expect do
94
- APNS.send_notification(token, message)
95
- end.to raise_error(APNS::ConfigurationError, /PEM not configured properly/)
96
- end
97
- end
98
- end
99
-
100
- end
101
-
102
- describe "GCM" do
103
- it "should have a GCM object" do
104
- defined?(GCM).should_not be_false
105
- end
106
-
107
- describe "Notifications" do
108
-
109
- before do
110
- @options = {:data => "dummy data"}
111
- end
112
-
113
- it "should allow only notifications with device_tokens as array" do
114
- n = GCM::Notification.new("id", @options)
115
- n.device_tokens.is_a?(Array).should be_true
116
-
117
- n.device_tokens = ["a" "b", "c"]
118
- n.device_tokens.is_a?(Array).should be_true
119
-
120
- n.device_tokens = "a"
121
- n.device_tokens.is_a?(Array).should be_true
122
- end
123
-
124
- it "should allow only notifications with data as hash with :data root" do
125
- n = GCM::Notification.new("id", { :data => "data" })
126
-
127
- n.data.is_a?(Hash).should be_true
128
- n.data.should == {:data => "data"}
129
-
130
- n.data = {:a => ["a", "b", "c"]}
131
- n.data.is_a?(Hash).should be_true
132
- n.data.should == {:a => ["a", "b", "c"]}
133
-
134
- n.data = {:a => "a"}
135
- n.data.is_a?(Hash).should be_true
136
- n.data.should == {:a => "a"}
137
- end
138
-
139
- describe "#==" do
140
- it "should properly equate objects without caring about object identity" do
141
- a = GCM::Notification.new("id", { :data => "data" })
142
- b = GCM::Notification.new("id", { :data => "data" })
143
- a.should eq(b)
144
- end
145
- end
146
- end
147
- end
148
- end