apn_on_rails 0.3.1 → 0.4.0
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.
- 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
|