apn_on_rails 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +16 -0
- data/.rspec +2 -0
- data/.specification +80 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +45 -0
- data/README +51 -9
- data/README.textile +198 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/apn_on_rails.gemspec +110 -0
- data/generators/templates/apn_migrations/004_create_apn_apps.rb +18 -0
- data/generators/templates/apn_migrations/005_create_groups.rb +23 -0
- data/generators/templates/apn_migrations/006_alter_apn_groups.rb +11 -0
- data/generators/templates/apn_migrations/007_create_device_groups.rb +27 -0
- data/generators/templates/apn_migrations/008_create_apn_group_notifications.rb +23 -0
- data/generators/templates/apn_migrations/009_create_pull_notifications.rb +16 -0
- data/lib/apn_on_rails/apn_on_rails.rb +22 -3
- data/lib/apn_on_rails/app/models/apn/app.rb +115 -0
- data/lib/apn_on_rails/app/models/apn/device.rb +3 -1
- data/lib/apn_on_rails/app/models/apn/device_grouping.rb +16 -0
- data/lib/apn_on_rails/app/models/apn/group.rb +12 -0
- data/lib/apn_on_rails/app/models/apn/group_notification.rb +79 -0
- data/lib/apn_on_rails/app/models/apn/notification.rb +6 -30
- data/lib/apn_on_rails/app/models/apn/pull_notification.rb +15 -0
- data/lib/apn_on_rails/libs/connection.rb +2 -1
- data/lib/apn_on_rails/libs/feedback.rb +6 -18
- data/lib/apn_on_rails/tasks/apn.rake +13 -4
- data/spec/active_record/setup_ar.rb +19 -0
- data/spec/apn_on_rails/app/models/apn/app_spec.rb +178 -0
- data/spec/apn_on_rails/app/models/apn/device_spec.rb +60 -0
- data/spec/apn_on_rails/app/models/apn/group_notification_spec.rb +66 -0
- data/spec/apn_on_rails/app/models/apn/notification_spec.rb +71 -0
- data/spec/apn_on_rails/app/models/apn/pull_notification_spec.rb +37 -0
- data/spec/apn_on_rails/libs/connection_spec.rb +40 -0
- data/spec/apn_on_rails/libs/feedback_spec.rb +45 -0
- data/spec/extensions/string.rb +10 -0
- data/spec/factories/app_factory.rb +27 -0
- data/spec/factories/device_factory.rb +29 -0
- data/spec/factories/device_grouping_factory.rb +22 -0
- data/spec/factories/group_factory.rb +27 -0
- data/spec/factories/group_notification_factory.rb +22 -0
- data/spec/factories/notification_factory.rb +22 -0
- data/spec/factories/pull_notification_factory.rb +22 -0
- data/spec/fixtures/hexa.bin +1 -0
- data/spec/fixtures/message_for_sending.bin +0 -0
- data/spec/rails_root/config/apple_push_notification_development.pem +19 -0
- data/spec/spec_helper.rb +55 -0
- metadata +214 -24
@@ -10,9 +10,11 @@
|
|
10
10
|
# Device.create(:token => '5gxadhy6 6zmtxfl6 5zpbcxmw ez3w7ksf qscpr55t trknkzap 7yyt45sc g6jrw7qz')
|
11
11
|
class APN::Device < APN::Base
|
12
12
|
|
13
|
+
belongs_to :app, :class_name => 'APN::App'
|
13
14
|
has_many :notifications, :class_name => 'APN::Notification'
|
15
|
+
has_many :unsent_notifications, :class_name => 'APN::Notification', :conditions => 'sent_at is null'
|
14
16
|
|
15
|
-
validates_uniqueness_of :token
|
17
|
+
validates_uniqueness_of :token, :scope => :app_id
|
16
18
|
validates_format_of :token, :with => /^[a-z0-9]{8}\s[a-z0-9]{8}\s[a-z0-9]{8}\s[a-z0-9]{8}\s[a-z0-9]{8}\s[a-z0-9]{8}\s[a-z0-9]{8}\s[a-z0-9]{8}$/
|
17
19
|
|
18
20
|
before_save :set_last_registered_at
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class APN::DeviceGrouping < APN::Base
|
2
|
+
|
3
|
+
belongs_to :group, :class_name => 'APN::Group'
|
4
|
+
belongs_to :device, :class_name => 'APN::Device'
|
5
|
+
|
6
|
+
validates_presence_of :device_id, :group_id
|
7
|
+
validate :same_app_id
|
8
|
+
validates_uniqueness_of :device_id, :scope => :group_id
|
9
|
+
|
10
|
+
def same_app_id
|
11
|
+
unless self.group and self.device and self.group.app_id == self.device.app_id
|
12
|
+
errors.add_to_base("device and group must belong to the same app")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class APN::Group < APN::Base
|
2
|
+
|
3
|
+
belongs_to :app, :class_name => 'APN::App'
|
4
|
+
has_many :device_groupings, :class_name => "APN::DeviceGrouping", :dependent => :destroy
|
5
|
+
has_many :devices, :class_name => 'APN::Device', :through => :device_groupings
|
6
|
+
has_many :group_notifications, :class_name => 'APN::GroupNotification'
|
7
|
+
has_many :unsent_group_notifications, :class_name => 'APN::GroupNotification', :conditions => 'sent_at is null'
|
8
|
+
|
9
|
+
validates_presence_of :app_id
|
10
|
+
validates_uniqueness_of :name, :scope => :app_id
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class APN::GroupNotification < APN::Base
|
2
|
+
include ::ActionView::Helpers::TextHelper
|
3
|
+
extend ::ActionView::Helpers::TextHelper
|
4
|
+
serialize :custom_properties
|
5
|
+
|
6
|
+
belongs_to :group, :class_name => 'APN::Group'
|
7
|
+
has_one :app, :class_name => 'APN::App', :through => :group
|
8
|
+
has_many :device_groupings, :through => :group
|
9
|
+
|
10
|
+
validates_presence_of :group_id
|
11
|
+
|
12
|
+
def devices
|
13
|
+
self.group.devices
|
14
|
+
end
|
15
|
+
|
16
|
+
# Stores the text alert message you want to send to the device.
|
17
|
+
#
|
18
|
+
# If the message is over 150 characters long it will get truncated
|
19
|
+
# to 150 characters with a <tt>...</tt>
|
20
|
+
def alert=(message)
|
21
|
+
if !message.blank? && message.size > 150
|
22
|
+
message = truncate(message, :length => 150)
|
23
|
+
end
|
24
|
+
write_attribute('alert', message)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Creates a Hash that will be the payload of an APN.
|
28
|
+
#
|
29
|
+
# Example:
|
30
|
+
# apn = APN::GroupNotification.new
|
31
|
+
# apn.badge = 5
|
32
|
+
# apn.sound = 'my_sound.aiff'
|
33
|
+
# apn.alert = 'Hello!'
|
34
|
+
# apn.apple_hash # => {"aps" => {"badge" => 5, "sound" => "my_sound.aiff", "alert" => "Hello!"}}
|
35
|
+
#
|
36
|
+
# Example 2:
|
37
|
+
# apn = APN::GroupNotification.new
|
38
|
+
# apn.badge = 0
|
39
|
+
# apn.sound = true
|
40
|
+
# apn.custom_properties = {"typ" => 1}
|
41
|
+
# apn.apple_hash # => {"aps" => {"badge" => 0, "sound" => 1.aiff},"typ" => "1"}
|
42
|
+
def apple_hash
|
43
|
+
result = {}
|
44
|
+
result['aps'] = {}
|
45
|
+
result['aps']['alert'] = self.alert if self.alert
|
46
|
+
result['aps']['badge'] = self.badge.to_i if self.badge
|
47
|
+
if self.sound
|
48
|
+
result['aps']['sound'] = self.sound if self.sound.is_a? String
|
49
|
+
result['aps']['sound'] = "1.aiff" if self.sound.is_a?(TrueClass)
|
50
|
+
end
|
51
|
+
if self.custom_properties
|
52
|
+
self.custom_properties.each do |key,value|
|
53
|
+
result["#{key}"] = "#{value}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
result
|
57
|
+
end
|
58
|
+
|
59
|
+
# Creates the JSON string required for an APN message.
|
60
|
+
#
|
61
|
+
# Example:
|
62
|
+
# apn = APN::Notification.new
|
63
|
+
# apn.badge = 5
|
64
|
+
# apn.sound = 'my_sound.aiff'
|
65
|
+
# apn.alert = 'Hello!'
|
66
|
+
# apn.to_apple_json # => '{"aps":{"badge":5,"sound":"my_sound.aiff","alert":"Hello!"}}'
|
67
|
+
def to_apple_json
|
68
|
+
self.apple_hash.to_json
|
69
|
+
end
|
70
|
+
|
71
|
+
# Creates the binary message needed to send to Apple.
|
72
|
+
def message_for_sending(device)
|
73
|
+
json = self.to_apple_json
|
74
|
+
message = "\0\0 #{device.to_hexa}\0#{json.length.chr}#{json}"
|
75
|
+
raise APN::Errors::ExceededMessageSizeError.new(message) if message.size.to_i > 256
|
76
|
+
message
|
77
|
+
end
|
78
|
+
|
79
|
+
end # APN::Notification
|
@@ -20,6 +20,7 @@ class APN::Notification < APN::Base
|
|
20
20
|
serialize :custom_properties
|
21
21
|
|
22
22
|
belongs_to :device, :class_name => 'APN::Device'
|
23
|
+
has_one :app, :class_name => 'APN::App', :through => :device
|
23
24
|
|
24
25
|
# Stores the text alert message you want to send to the device.
|
25
26
|
#
|
@@ -46,7 +47,7 @@ class APN::Notification < APN::Base
|
|
46
47
|
# apn.badge = 0
|
47
48
|
# apn.sound = true
|
48
49
|
# apn.custom_properties = {"typ" => 1}
|
49
|
-
# apn.
|
50
|
+
# apn.apple_hash # => {"aps" => {"badge" => 0, "sound" => "1.aiff"}, "typ" => "1"}
|
50
51
|
def apple_hash
|
51
52
|
result = {}
|
52
53
|
result['aps'] = {}
|
@@ -84,34 +85,9 @@ class APN::Notification < APN::Base
|
|
84
85
|
message
|
85
86
|
end
|
86
87
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
#
|
92
|
-
# This method expects an Array of APN::Notifications. If no parameter is passed
|
93
|
-
# in then it will use the following:
|
94
|
-
# APN::Notification.all(:conditions => {:sent_at => nil})
|
95
|
-
#
|
96
|
-
# As each APN::Notification is sent the <tt>sent_at</tt> column will be timestamped,
|
97
|
-
# so as to not be sent again.
|
98
|
-
#
|
99
|
-
# This can be run from the following Rake task:
|
100
|
-
# $ rake apn:notifications:deliver
|
101
|
-
def send_notifications(notifications = APN::Notification.all(:conditions => {:sent_at => nil}))
|
102
|
-
unless notifications.nil? || notifications.empty?
|
103
|
-
|
104
|
-
APN::Connection.open_for_delivery do |conn, sock|
|
105
|
-
notifications.each do |noty|
|
106
|
-
conn.write(noty.message_for_sending)
|
107
|
-
noty.sent_at = Time.now
|
108
|
-
noty.save
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
end # class << self
|
88
|
+
def self.send_notifications
|
89
|
+
ActiveSupport::Deprecation.warn("The method APN::Notification.send_notifications is deprecated. Use APN::App.send_notifications instead.")
|
90
|
+
APN::App.send_notifications
|
91
|
+
end
|
116
92
|
|
117
93
|
end # APN::Notification
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class APN::PullNotification < APN::Base
|
2
|
+
belongs_to :app, :class_name => 'APN::App'
|
3
|
+
|
4
|
+
validates_presence_of :app_id
|
5
|
+
|
6
|
+
def self.latest_since(app_id, since_date=nil)
|
7
|
+
conditions = if since_date
|
8
|
+
["app_id = ? AND created_at > ?", app_id, since_date]
|
9
|
+
else
|
10
|
+
["app_id = ?", app_id]
|
11
|
+
end
|
12
|
+
|
13
|
+
first(:order => "created_at DESC", :conditions => conditions)
|
14
|
+
end
|
15
|
+
end
|
@@ -47,7 +47,8 @@ module APN
|
|
47
47
|
:passphrase => configatron.apn.passphrase,
|
48
48
|
:host => configatron.apn.host,
|
49
49
|
:port => configatron.apn.port}.merge(options)
|
50
|
-
cert = File.read(options[:cert])
|
50
|
+
#cert = File.read(options[:cert])
|
51
|
+
cert = options[:cert]
|
51
52
|
ctx = OpenSSL::SSL::SSLContext.new
|
52
53
|
ctx.key = OpenSSL::PKey::RSA.new(cert, options[:passphrase])
|
53
54
|
ctx.cert = OpenSSL::X509::Certificate.new(cert)
|
@@ -10,9 +10,10 @@ module APN
|
|
10
10
|
# has received feedback from Apple. Each APN::Device will
|
11
11
|
# have it's <tt>feedback_at</tt> accessor marked with the time
|
12
12
|
# that Apple believes the device de-registered itself.
|
13
|
-
def devices(&block)
|
13
|
+
def devices(cert, &block)
|
14
14
|
devices = []
|
15
|
-
|
15
|
+
return if cert.nil?
|
16
|
+
APN::Connection.open_for_feedback({:cert => cert}) do |conn, sock|
|
16
17
|
while line = sock.gets # Read lines from the socket
|
17
18
|
line.strip!
|
18
19
|
feedback = line.unpack('N1n1H140')
|
@@ -28,23 +29,10 @@ module APN
|
|
28
29
|
return devices
|
29
30
|
end # devices
|
30
31
|
|
31
|
-
# Retrieves a list of APN::Device instnces from Apple using
|
32
|
-
# the <tt>devices</tt> method. It then checks to see if the
|
33
|
-
# <tt>last_registered_at</tt> date of each APN::Device is
|
34
|
-
# before the date that Apple says the device is no longer
|
35
|
-
# accepting notifications then the device is deleted. Otherwise
|
36
|
-
# it is assumed that the application has been re-installed
|
37
|
-
# and is available for notifications.
|
38
|
-
#
|
39
|
-
# This can be run from the following Rake task:
|
40
|
-
# $ rake apn:feedback:process
|
41
32
|
def process_devices
|
42
|
-
APN::Feedback.
|
43
|
-
|
44
|
-
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end # process_devices
|
33
|
+
ActiveSupport::Deprecation.warn("The method APN::Feedback.process_devices is deprecated. Use APN::App.process_devices instead.")
|
34
|
+
APN::App.process_devices
|
35
|
+
end
|
48
36
|
|
49
37
|
end # class << self
|
50
38
|
|
@@ -4,18 +4,27 @@ namespace :apn do
|
|
4
4
|
|
5
5
|
desc "Deliver all unsent APN notifications."
|
6
6
|
task :deliver => [:environment] do
|
7
|
-
APN::
|
7
|
+
APN::App.send_notifications
|
8
8
|
end
|
9
|
-
|
9
|
+
|
10
10
|
end # notifications
|
11
|
+
|
12
|
+
namespace :group_notifications do
|
13
|
+
|
14
|
+
desc "Deliver all unsent APN Group notifications."
|
15
|
+
task :deliver => [:environment] do
|
16
|
+
APN::App.send_group_notifications
|
17
|
+
end
|
18
|
+
|
19
|
+
end # group_notifications
|
11
20
|
|
12
21
|
namespace :feedback do
|
13
22
|
|
14
23
|
desc "Process all devices that have feedback from APN."
|
15
24
|
task :process => [:environment] do
|
16
|
-
APN::
|
25
|
+
APN::App.process_devices
|
17
26
|
end
|
18
27
|
|
19
28
|
end
|
20
29
|
|
21
|
-
end # apn
|
30
|
+
end # apn
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_record'
|
3
|
+
|
4
|
+
logger = Logger.new(STDOUT)
|
5
|
+
logger.level = Logger::INFO
|
6
|
+
ActiveRecord::Base.logger = logger
|
7
|
+
|
8
|
+
db_file = File.join(File.dirname(__FILE__), 'test.db')
|
9
|
+
FileUtils.rm(db_file) if File.exists?(db_file)
|
10
|
+
# File.open(db_file, 'w')
|
11
|
+
|
12
|
+
ActiveRecord::Base.establish_connection({
|
13
|
+
:adapter => 'sqlite3',
|
14
|
+
:database => db_file
|
15
|
+
})
|
16
|
+
|
17
|
+
ActiveRecord::Migrator.up(File.join(File.dirname(__FILE__), '..', '..', 'generators', 'templates', 'apn_migrations'))
|
18
|
+
|
19
|
+
# raise hell
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'spec_helper.rb')
|
2
|
+
|
3
|
+
describe APN::App do
|
4
|
+
|
5
|
+
describe 'send_notifications' do
|
6
|
+
|
7
|
+
it 'should send the unsent notifications' do
|
8
|
+
|
9
|
+
app = AppFactory.create
|
10
|
+
device = DeviceFactory.create({:app_id => app.id})
|
11
|
+
notifications = [NotificationFactory.create({:device_id => device.id}),
|
12
|
+
NotificationFactory.create({:device_id => device.id})]
|
13
|
+
notifications.each_with_index do |notify, i|
|
14
|
+
notify.stub(:message_for_sending).and_return("message-#{i}")
|
15
|
+
notify.should_receive(:sent_at=).with(instance_of(Time))
|
16
|
+
notify.should_receive(:save)
|
17
|
+
end
|
18
|
+
|
19
|
+
APN::App.should_receive(:all).and_return([app])
|
20
|
+
app.should_receive(:unsent_notifications).at_least(:once).and_return(notifications)
|
21
|
+
app.should_receive(:cert).twice.and_return(app.apn_dev_cert)
|
22
|
+
|
23
|
+
ssl_mock = mock('ssl_mock')
|
24
|
+
ssl_mock.should_receive(:write).with('message-0')
|
25
|
+
ssl_mock.should_receive(:write).with('message-1')
|
26
|
+
APN::Connection.should_receive(:open_for_delivery).and_yield(ssl_mock, nil)
|
27
|
+
|
28
|
+
APN::App.send_notifications
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'send_group_notifications' do
|
35
|
+
|
36
|
+
it 'should send the unsent group notifications' do
|
37
|
+
|
38
|
+
app = AppFactory.create
|
39
|
+
device = DeviceFactory.create({:app_id => app.id})
|
40
|
+
group = GroupFactory.create({:app_id => app.id})
|
41
|
+
device_grouping = DeviceGroupingFactory.create({:group_id => group.id,:device_id => device.id})
|
42
|
+
gnotys = [GroupNotificationFactory.create({:group_id => group.id}),
|
43
|
+
GroupNotificationFactory.create({:group_id => group.id})]
|
44
|
+
gnotys.each_with_index do |gnoty, i|
|
45
|
+
gnoty.stub!(:message_for_sending).and_return("message-#{i}")
|
46
|
+
gnoty.should_receive(:sent_at=).with(instance_of(Time))
|
47
|
+
gnoty.should_receive(:save)
|
48
|
+
end
|
49
|
+
|
50
|
+
APN::App.should_receive(:all).and_return([app])
|
51
|
+
app.should_receive(:unsent_group_notifications).at_least(:once).and_return(gnotys)
|
52
|
+
app.should_receive(:cert).twice.and_return(app.apn_dev_cert)
|
53
|
+
|
54
|
+
ssl_mock = mock('ssl_mock')
|
55
|
+
ssl_mock.should_receive(:write).with('message-0')
|
56
|
+
ssl_mock.should_receive(:write).with('message-1')
|
57
|
+
APN::Connection.should_receive(:open_for_delivery).and_yield(ssl_mock, nil)
|
58
|
+
|
59
|
+
APN::App.send_group_notifications
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'send single group notification' do
|
66
|
+
|
67
|
+
it 'should send the argument group notification' do
|
68
|
+
app = AppFactory.create
|
69
|
+
device = DeviceFactory.create({:app_id => app.id})
|
70
|
+
group = GroupFactory.create({:app_id => app.id})
|
71
|
+
device_grouping = DeviceGroupingFactory.create({:group_id => group.id,:device_id => device.id})
|
72
|
+
gnoty = GroupNotificationFactory.create({:group_id => group.id})
|
73
|
+
gnoty.stub!(:message_for_sending).and_return("message-0")
|
74
|
+
gnoty.should_receive(:sent_at=).with(instance_of(Time))
|
75
|
+
gnoty.should_receive(:save)
|
76
|
+
|
77
|
+
app.should_receive(:cert).at_least(:once).and_return(app.apn_dev_cert)
|
78
|
+
|
79
|
+
ssl_mock = mock('ssl_mock')
|
80
|
+
ssl_mock.should_receive(:write).with('message-0')
|
81
|
+
APN::Connection.should_receive(:open_for_delivery).and_yield(ssl_mock, nil)
|
82
|
+
|
83
|
+
app.send_group_notification(gnoty)
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
describe 'nil cert when sending notifications' do
|
89
|
+
|
90
|
+
it 'should raise an exception for sending notifications for an app with no cert' do
|
91
|
+
app = AppFactory.create
|
92
|
+
APN::App.should_receive(:all).and_return([app])
|
93
|
+
app.should_receive(:cert).and_return(nil)
|
94
|
+
lambda {
|
95
|
+
APN::App.send_notifications
|
96
|
+
}.should raise_error(APN::Errors::MissingCertificateError)
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
describe 'nil cert when sending group notifications' do
|
102
|
+
|
103
|
+
it 'should raise an exception for sending group notifications for an app with no cert' do
|
104
|
+
app = AppFactory.create
|
105
|
+
APN::App.should_receive(:all).and_return([app])
|
106
|
+
app.should_receive(:cert).and_return(nil)
|
107
|
+
lambda {
|
108
|
+
APN::App.send_group_notifications
|
109
|
+
}.should raise_error(APN::Errors::MissingCertificateError)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
describe 'nil cert when sending single group notification' do
|
115
|
+
|
116
|
+
it 'should raise an exception for sending group notifications for an app with no cert' do
|
117
|
+
app = AppFactory.create
|
118
|
+
device = DeviceFactory.create({:app_id => app.id})
|
119
|
+
group = GroupFactory.create({:app_id => app.id})
|
120
|
+
device_grouping = DeviceGroupingFactory.create({:group_id => group.id,:device_id => device.id})
|
121
|
+
gnoty = GroupNotificationFactory.create({:group_id => group.id})
|
122
|
+
app.should_receive(:cert).and_return(nil)
|
123
|
+
lambda {
|
124
|
+
app.send_group_notification(gnoty)
|
125
|
+
}.should raise_error(APN::Errors::MissingCertificateError)
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
describe 'process_devices' do
|
131
|
+
|
132
|
+
it 'should destroy devices that have a last_registered_at date that is before the feedback_at date' do
|
133
|
+
app = AppFactory.create
|
134
|
+
devices = [DeviceFactory.create(:app_id => app.id, :last_registered_at => 1.week.ago, :feedback_at => Time.now),
|
135
|
+
DeviceFactory.create(:app_id => app.id, :last_registered_at => 1.week.from_now, :feedback_at => Time.now)]
|
136
|
+
APN::Feedback.should_receive(:devices).and_return(devices)
|
137
|
+
APN::App.should_receive(:all).and_return([app])
|
138
|
+
app.should_receive(:cert).twice.and_return(app.apn_dev_cert)
|
139
|
+
lambda {
|
140
|
+
APN::App.process_devices
|
141
|
+
}.should change(APN::Device, :count).by(-1)
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
describe 'nil cert when processing devices' do
|
147
|
+
|
148
|
+
it 'should raise an exception for processing devices for an app with no cert' do
|
149
|
+
app = AppFactory.create
|
150
|
+
APN::App.should_receive(:all).and_return([app])
|
151
|
+
app.should_receive(:cert).and_return(nil)
|
152
|
+
lambda {
|
153
|
+
APN::App.process_devices
|
154
|
+
}.should raise_error(APN::Errors::MissingCertificateError)
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
describe 'cert for production environment' do
|
160
|
+
|
161
|
+
it 'should return the production cert for the app' do
|
162
|
+
app = AppFactory.create
|
163
|
+
RAILS_ENV = 'production'
|
164
|
+
app.cert.should == app.apn_prod_cert
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
describe 'cert for development and staging environment' do
|
170
|
+
|
171
|
+
it 'should return the development cert for the app' do
|
172
|
+
app = AppFactory.create
|
173
|
+
RAILS_ENV = 'staging'
|
174
|
+
app.cert.should == app.apn_dev_cert
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|