rapns 2.0.5 → 3.0.0.beta.1
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/lib/generators/rapns_generator.rb +1 -0
- data/lib/generators/templates/add_gcm.rb +86 -0
- data/lib/generators/templates/create_rapns_notifications.rb +1 -1
- data/lib/rapns/apns/app.rb +8 -0
- data/lib/rapns/apns/binary_notification_validator.rb +12 -0
- data/lib/rapns/apns/device_token_format_validator.rb +12 -0
- data/lib/rapns/apns/feedback.rb +14 -0
- data/lib/rapns/apns/notification.rb +84 -0
- data/lib/rapns/app.rb +5 -6
- data/lib/rapns/{config.rb → configuration.rb} +5 -5
- data/lib/rapns/daemon/apns/app_runner.rb +36 -0
- data/lib/rapns/daemon/apns/connection.rb +113 -0
- data/lib/rapns/daemon/apns/delivery.rb +63 -0
- data/lib/rapns/daemon/apns/delivery_handler.rb +21 -0
- data/lib/rapns/daemon/apns/disconnection_error.rb +20 -0
- data/lib/rapns/daemon/apns/feedback_receiver.rb +74 -0
- data/lib/rapns/daemon/app_runner.rb +76 -77
- data/lib/rapns/daemon/database_reconnectable.rb +3 -3
- data/lib/rapns/daemon/delivery.rb +43 -0
- data/lib/rapns/daemon/delivery_error.rb +6 -2
- data/lib/rapns/daemon/delivery_handler.rb +13 -79
- data/lib/rapns/daemon/delivery_queue_18.rb +2 -2
- data/lib/rapns/daemon/delivery_queue_19.rb +3 -3
- data/lib/rapns/daemon/feeder.rb +5 -5
- data/lib/rapns/daemon/gcm/app_runner.rb +13 -0
- data/lib/rapns/daemon/gcm/delivery.rb +206 -0
- data/lib/rapns/daemon/gcm/delivery_handler.rb +20 -0
- data/lib/rapns/daemon.rb +31 -20
- data/lib/rapns/gcm/app.rb +7 -0
- data/lib/rapns/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +11 -0
- data/lib/rapns/gcm/notification.rb +31 -0
- data/lib/rapns/gcm/payload_size_validator.rb +13 -0
- data/lib/rapns/multi_json_helper.rb +16 -0
- data/lib/rapns/notification.rb +28 -95
- data/lib/rapns/version.rb +1 -1
- data/lib/rapns.rb +14 -4
- data/lib/tasks/cane.rake +19 -0
- data/lib/tasks/test.rake +34 -0
- data/spec/acceptance/gcm_upgrade_spec.rb +34 -0
- data/spec/acceptance_spec_helper.rb +85 -0
- data/spec/support/simplecov_helper.rb +13 -0
- data/spec/support/simplecov_quality_formatter.rb +8 -0
- data/spec/unit/apns/app_spec.rb +15 -0
- data/spec/unit/apns/feedback_spec.rb +12 -0
- data/spec/{rapns → unit/apns}/notification_spec.rb +44 -72
- data/spec/unit/app_spec.rb +18 -0
- data/spec/unit/daemon/apns/app_runner_spec.rb +37 -0
- data/spec/{rapns/daemon → unit/daemon/apns}/connection_spec.rb +9 -9
- data/spec/unit/daemon/apns/delivery_handler_spec.rb +48 -0
- data/spec/unit/daemon/apns/delivery_spec.rb +154 -0
- data/spec/{rapns/daemon → unit/daemon/apns}/feedback_receiver_spec.rb +14 -14
- data/spec/unit/daemon/app_runner_shared.rb +66 -0
- data/spec/unit/daemon/app_runner_spec.rb +78 -0
- data/spec/{rapns → unit}/daemon/database_reconnectable_spec.rb +4 -5
- data/spec/{rapns → unit}/daemon/delivery_error_spec.rb +2 -2
- data/spec/unit/daemon/delivery_handler_shared.rb +19 -0
- data/spec/{rapns → unit}/daemon/delivery_queue_spec.rb +1 -1
- data/spec/{rapns → unit}/daemon/feeder_spec.rb +33 -33
- data/spec/unit/daemon/gcm/app_runner_spec.rb +15 -0
- data/spec/unit/daemon/gcm/delivery_handler_spec.rb +36 -0
- data/spec/unit/daemon/gcm/delivery_spec.rb +236 -0
- data/spec/{rapns → unit}/daemon/interruptible_sleep_spec.rb +1 -1
- data/spec/{rapns → unit}/daemon/logger_spec.rb +1 -1
- data/spec/{rapns → unit}/daemon_spec.rb +1 -1
- data/spec/unit/gcm/app_spec.rb +5 -0
- data/spec/unit/gcm/notification_spec.rb +55 -0
- data/spec/unit/notification_shared.rb +38 -0
- data/spec/unit/notification_spec.rb +6 -0
- data/spec/{rapns/app_spec.rb → unit_spec_helper.rb} +76 -16
- metadata +107 -45
- data/lib/rapns/binary_notification_validator.rb +0 -10
- data/lib/rapns/daemon/connection.rb +0 -114
- data/lib/rapns/daemon/delivery_handler_pool.rb +0 -18
- data/lib/rapns/daemon/disconnection_error.rb +0 -14
- data/lib/rapns/daemon/feedback_receiver.rb +0 -82
- data/lib/rapns/device_token_format_validator.rb +0 -10
- data/lib/rapns/feedback.rb +0 -12
- data/spec/rapns/daemon/app_runner_spec.rb +0 -193
- data/spec/rapns/daemon/delivery_handler_pool_spec.rb +0 -17
- data/spec/rapns/daemon/delivery_handler_spec.rb +0 -206
- data/spec/rapns/feedback_spec.rb +0 -12
- data/spec/spec_helper.rb +0 -78
@@ -0,0 +1,154 @@
|
|
1
|
+
require 'unit_spec_helper'
|
2
|
+
|
3
|
+
describe Rapns::Daemon::Apns::Delivery do
|
4
|
+
let(:app) { stub(:name => 'MyApp') }
|
5
|
+
let(:notification) { stub.as_null_object }
|
6
|
+
let(:logger) { stub(:error => nil, :info => nil) }
|
7
|
+
let(:config) { stub(:check_for_errors => true) }
|
8
|
+
let(:connection) { stub(:select => false, :write => nil, :reconnect => nil, :close => nil, :connect => nil) }
|
9
|
+
let(:delivery) { Rapns::Daemon::Apns::Delivery.new(app, connection, notification) }
|
10
|
+
|
11
|
+
def perform
|
12
|
+
begin
|
13
|
+
delivery.perform
|
14
|
+
rescue Rapns::DeliveryError, Rapns::Apns::DisconnectionError
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
before do
|
19
|
+
Rapns::Daemon.stub(:logger => logger, :config => config)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "sends the binary version of the notification" do
|
23
|
+
notification.stub(:to_binary => "hi mom")
|
24
|
+
connection.should_receive(:write).with("hi mom")
|
25
|
+
perform
|
26
|
+
end
|
27
|
+
|
28
|
+
it "logs the notification delivery" do
|
29
|
+
notification.stub(:id => 666, :device_token => 'abc123')
|
30
|
+
logger.should_receive(:info).with("[MyApp] 666 sent to abc123")
|
31
|
+
perform
|
32
|
+
end
|
33
|
+
|
34
|
+
it "marks the notification as delivered" do
|
35
|
+
notification.should_receive(:delivered=).with(true)
|
36
|
+
perform
|
37
|
+
end
|
38
|
+
|
39
|
+
it "sets the time the notification was delivered" do
|
40
|
+
now = Time.now
|
41
|
+
Time.stub(:now).and_return(now)
|
42
|
+
notification.should_receive(:delivered_at=).with(now)
|
43
|
+
perform
|
44
|
+
end
|
45
|
+
|
46
|
+
it "does not trigger validations when saving the notification" do
|
47
|
+
notification.should_receive(:save!).with(:validate => false)
|
48
|
+
perform
|
49
|
+
end
|
50
|
+
|
51
|
+
it "updates notification with the ability to reconnect the database" do
|
52
|
+
delivery.should_receive(:with_database_reconnect_and_retry)
|
53
|
+
perform
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'does not check for errors if check_for_errors config option is false' do
|
57
|
+
config.stub(:check_for_errors => false)
|
58
|
+
delivery.should_not_receive(:check_for_error)
|
59
|
+
perform
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "when delivery fails" do
|
63
|
+
before { connection.stub(:select => true, :read => [8, 4, 69].pack("ccN")) }
|
64
|
+
|
65
|
+
it "updates notification with the ability to reconnect the database" do
|
66
|
+
delivery.should_receive(:with_database_reconnect_and_retry)
|
67
|
+
perform
|
68
|
+
end
|
69
|
+
|
70
|
+
it "sets the notification as not delivered" do
|
71
|
+
notification.should_receive(:delivered=).with(false)
|
72
|
+
perform
|
73
|
+
end
|
74
|
+
|
75
|
+
it "sets the notification delivered_at timestamp to nil" do
|
76
|
+
notification.should_receive(:delivered_at=).with(nil)
|
77
|
+
perform
|
78
|
+
end
|
79
|
+
|
80
|
+
it "sets the notification as failed" do
|
81
|
+
notification.should_receive(:failed=).with(true)
|
82
|
+
perform
|
83
|
+
end
|
84
|
+
|
85
|
+
it "sets the notification failed_at timestamp" do
|
86
|
+
now = Time.now
|
87
|
+
Time.stub(:now).and_return(now)
|
88
|
+
notification.should_receive(:failed_at=).with(now)
|
89
|
+
perform
|
90
|
+
end
|
91
|
+
|
92
|
+
it "sets the notification error code" do
|
93
|
+
notification.should_receive(:error_code=).with(4)
|
94
|
+
perform
|
95
|
+
end
|
96
|
+
|
97
|
+
it "logs the delivery error" do
|
98
|
+
error = Rapns::DeliveryError.new(4, 12, "Missing payload")
|
99
|
+
Rapns::DeliveryError.stub(:new => error)
|
100
|
+
expect { delivery.perform }.to raise_error(error)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "sets the notification error description" do
|
104
|
+
notification.should_receive(:error_description=).with("Missing payload")
|
105
|
+
perform
|
106
|
+
end
|
107
|
+
|
108
|
+
it "skips validation when saving the notification" do
|
109
|
+
notification.should_receive(:save!).with(:validate => false)
|
110
|
+
perform
|
111
|
+
end
|
112
|
+
|
113
|
+
it "reads 6 bytes from the socket" do
|
114
|
+
connection.should_receive(:read).with(6).and_return(nil)
|
115
|
+
perform
|
116
|
+
end
|
117
|
+
|
118
|
+
it "does not attempt to read from the socket if the socket was not selected for reading after the timeout" do
|
119
|
+
connection.stub(:select => nil)
|
120
|
+
connection.should_not_receive(:read)
|
121
|
+
perform
|
122
|
+
end
|
123
|
+
|
124
|
+
it "reconnects the socket" do
|
125
|
+
connection.should_receive(:reconnect)
|
126
|
+
perform
|
127
|
+
end
|
128
|
+
|
129
|
+
it "logs that the connection is being reconnected" do
|
130
|
+
Rapns::Daemon.logger.should_receive(:error).with("[MyApp] Error received, reconnecting...")
|
131
|
+
perform
|
132
|
+
end
|
133
|
+
|
134
|
+
context "when the APNs disconnects without returning an error" do
|
135
|
+
before do
|
136
|
+
connection.stub(:read => nil)
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'raises a DisconnectError error if the connection is closed without an error being returned' do
|
140
|
+
expect { delivery.perform }.to raise_error(Rapns::Apns::DisconnectionError)
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'does not set the error code on the notification' do
|
144
|
+
notification.should_receive(:error_code=).with(nil)
|
145
|
+
perform
|
146
|
+
end
|
147
|
+
|
148
|
+
it 'sets the error description on the notification' do
|
149
|
+
notification.should_receive(:error_description=).with("APNs disconnected without returning an error.")
|
150
|
+
perform
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -1,21 +1,21 @@
|
|
1
|
-
require "
|
1
|
+
require "unit_spec_helper"
|
2
2
|
|
3
|
-
describe Rapns::Daemon::FeedbackReceiver, 'check_for_feedback' do
|
3
|
+
describe Rapns::Daemon::Apns::FeedbackReceiver, 'check_for_feedback' do
|
4
4
|
let(:host) { 'feedback.push.apple.com' }
|
5
5
|
let(:port) { 2196 }
|
6
6
|
let(:poll) { 60 }
|
7
7
|
let(:certificate) { stub }
|
8
8
|
let(:password) { stub }
|
9
|
-
let(:app) { 'my_app' }
|
9
|
+
let(:app) { stub(:name => 'my_app', :password => password, :certificate => certificate) }
|
10
10
|
let(:connection) { stub(:connect => nil, :read => nil, :close => nil) }
|
11
11
|
let(:logger) { stub(:error => nil, :info => nil) }
|
12
|
-
let(:receiver) { Rapns::Daemon::FeedbackReceiver.new(app, host, port, poll
|
12
|
+
let(:receiver) { Rapns::Daemon::Apns::FeedbackReceiver.new(app, host, port, poll) }
|
13
13
|
|
14
14
|
before do
|
15
15
|
receiver.stub(:interruptible_sleep)
|
16
16
|
Rapns::Daemon.logger = logger
|
17
|
-
Rapns::Daemon::Connection.stub(:new => connection)
|
18
|
-
Rapns::Feedback.stub(:create!)
|
17
|
+
Rapns::Daemon::Apns::Connection.stub(:new => connection)
|
18
|
+
Rapns::Apns::Feedback.stub(:create!)
|
19
19
|
receiver.instance_variable_set("@stop", false)
|
20
20
|
end
|
21
21
|
|
@@ -30,8 +30,8 @@ describe Rapns::Daemon::FeedbackReceiver, 'check_for_feedback' do
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
it 'instantiates a new connection' do
|
34
|
-
Rapns::Daemon::Connection.should_receive(:new).with("FeedbackReceiver:#{app}", host, port, certificate, password)
|
33
|
+
it 'instantiates a new connection' do
|
34
|
+
Rapns::Daemon::Apns::Connection.should_receive(:new).with("FeedbackReceiver:#{app.name}", host, port, certificate, password)
|
35
35
|
receiver.check_for_feedback
|
36
36
|
end
|
37
37
|
|
@@ -58,7 +58,7 @@ describe Rapns::Daemon::FeedbackReceiver, 'check_for_feedback' do
|
|
58
58
|
|
59
59
|
it 'creates the feedback' do
|
60
60
|
stub_connection_read_with_tuple
|
61
|
-
Rapns::Feedback.should_receive(:create!).with(:failed_at => Time.at(1323533325), :device_token => '834f786655eb9f84614a05ad7d00af31e5cfe93ac3ea078f1da44d2a4eb0ce17', :app =>
|
61
|
+
Rapns::Apns::Feedback.should_receive(:create!).with(:failed_at => Time.at(1323533325), :device_token => '834f786655eb9f84614a05ad7d00af31e5cfe93ac3ea078f1da44d2a4eb0ce17', :app => app)
|
62
62
|
receiver.check_for_feedback
|
63
63
|
end
|
64
64
|
|
@@ -66,7 +66,7 @@ describe Rapns::Daemon::FeedbackReceiver, 'check_for_feedback' do
|
|
66
66
|
error = StandardError.new('bork!')
|
67
67
|
connection.stub(:read).and_raise(error)
|
68
68
|
Rapns::Daemon.logger.should_receive(:error).with(error)
|
69
|
-
|
69
|
+
receiver.check_for_feedback
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'sleeps for the feedback poll period' do
|
@@ -92,10 +92,10 @@ describe Rapns::Daemon::FeedbackReceiver, 'check_for_feedback' do
|
|
92
92
|
|
93
93
|
it 'calls the configuration feedback_callback when feedback is received and the callback is set' do
|
94
94
|
stub_connection_read_with_tuple
|
95
|
-
Rapns
|
95
|
+
Rapns.configuration.feedback_callback = Proc.new {}
|
96
96
|
feedback = Object.new
|
97
|
-
Rapns::Feedback.stub(:create! => feedback)
|
98
|
-
Rapns
|
97
|
+
Rapns::Apns::Feedback.stub(:create! => feedback)
|
98
|
+
Rapns.configuration.feedback_callback.should_receive(:call).with(feedback)
|
99
99
|
receiver.check_for_feedback
|
100
100
|
end
|
101
101
|
|
@@ -115,4 +115,4 @@ describe Rapns::Daemon::FeedbackReceiver, 'check_for_feedback' do
|
|
115
115
|
Rapns::configuration.feedback_callback = callback
|
116
116
|
receiver.check_for_feedback
|
117
117
|
end
|
118
|
-
end
|
118
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
shared_examples_for "an AppRunner subclass" do
|
2
|
+
let(:queue) { stub(:notifications_processed? => true, :push => nil) }
|
3
|
+
|
4
|
+
before { Rapns::Daemon::DeliveryQueue.stub(:new => queue) }
|
5
|
+
after { Rapns::Daemon::AppRunner.runners.clear }
|
6
|
+
|
7
|
+
describe 'start' do
|
8
|
+
it 'starts a delivery handler for each connection' do
|
9
|
+
handler.should_receive(:start)
|
10
|
+
runner.start
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'assigns the queue to the handler' do
|
14
|
+
handler.should_receive(:queue=).with(queue)
|
15
|
+
runner.start
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'enqueue' do
|
20
|
+
let(:notification) { stub }
|
21
|
+
|
22
|
+
it 'enqueues the notification' do
|
23
|
+
queue.should_receive(:push).with(notification)
|
24
|
+
runner.enqueue(notification)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe 'stop' do
|
29
|
+
before { runner.start }
|
30
|
+
|
31
|
+
it 'stops the delivery handlers' do
|
32
|
+
handler.should_receive(:stop)
|
33
|
+
runner.stop
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'idle?' do
|
38
|
+
it 'is idle if all notifications have been processed' do
|
39
|
+
queue.stub(:notifications_processed? => true)
|
40
|
+
runner.idle?.should be_true
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'is not idle if not all notifications have been processed' do
|
44
|
+
queue.stub(:notifications_processed? => false)
|
45
|
+
runner.idle?.should be_false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'sync' do
|
50
|
+
before { runner.start }
|
51
|
+
|
52
|
+
it 'reduces the number of handlers if needed' do
|
53
|
+
handler.should_receive(:stop)
|
54
|
+
new_app = app_class.new
|
55
|
+
new_app.stub(:connections => app.connections - 1)
|
56
|
+
runner.sync(new_app)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'increases the number of handlers if needed' do
|
60
|
+
runner.should_receive(:start_handler).and_return(handler)
|
61
|
+
new_app = app_class.new
|
62
|
+
new_app.stub(:connections => app.connections + 1)
|
63
|
+
runner.sync(new_app)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'unit_spec_helper'
|
2
|
+
|
3
|
+
describe Rapns::Daemon::AppRunner, 'stop' do
|
4
|
+
let(:runner) { stub }
|
5
|
+
before { Rapns::Daemon::AppRunner.runners['app'] = runner }
|
6
|
+
after { Rapns::Daemon::AppRunner.runners.clear }
|
7
|
+
|
8
|
+
it 'stops all runners' do
|
9
|
+
runner.should_receive(:stop)
|
10
|
+
Rapns::Daemon::AppRunner.stop
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe Rapns::Daemon::AppRunner, 'deliver' do
|
15
|
+
let(:runner) { stub }
|
16
|
+
let(:notification) { stub(:app_id => 1) }
|
17
|
+
let(:logger) { stub(:error => nil) }
|
18
|
+
|
19
|
+
before do
|
20
|
+
Rapns::Daemon.stub(:logger => logger)
|
21
|
+
Rapns::Daemon::AppRunner.runners[1] = runner
|
22
|
+
end
|
23
|
+
|
24
|
+
after { Rapns::Daemon::AppRunner.runners.clear }
|
25
|
+
|
26
|
+
it 'enqueues the notification' do
|
27
|
+
runner.should_receive(:enqueue).with(notification)
|
28
|
+
Rapns::Daemon::AppRunner.enqueue(notification)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'logs an error if there is no runner to deliver the notification' do
|
32
|
+
notification.stub(:app_id => 2, :id => 123)
|
33
|
+
logger.should_receive(:error).with("No such app '#{notification.app_id}' for notification #{notification.id}.")
|
34
|
+
Rapns::Daemon::AppRunner.enqueue(notification)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe Rapns::Daemon::AppRunner, 'sync' do
|
39
|
+
let(:app) { Rapns::Apns::App.new }
|
40
|
+
let(:new_app) { Rapns::Apns::App.new }
|
41
|
+
let(:runner) { stub(:sync => nil, :stop => nil, :start => nil) }
|
42
|
+
let(:logger) { stub(:error => nil) }
|
43
|
+
let(:queue) { Rapns::Daemon::DeliveryQueue.new }
|
44
|
+
|
45
|
+
before do
|
46
|
+
app.stub(:id => 1)
|
47
|
+
new_app.stub(:id => 2)
|
48
|
+
Rapns::Daemon::DeliveryQueue.stub(:new => queue)
|
49
|
+
Rapns::Daemon::AppRunner.runners[app.id] = runner
|
50
|
+
Rapns::App.stub(:all => [app])
|
51
|
+
end
|
52
|
+
|
53
|
+
after { Rapns::Daemon::AppRunner.runners.clear }
|
54
|
+
|
55
|
+
it 'loads all apps' do
|
56
|
+
Rapns::App.should_receive(:all)
|
57
|
+
Rapns::Daemon::AppRunner.sync
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'instructs existing runners to sync' do
|
61
|
+
runner.should_receive(:sync).with(app)
|
62
|
+
Rapns::Daemon::AppRunner.sync
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'starts a runner for a new app' do
|
66
|
+
Rapns::App.stub(:all => [app, new_app])
|
67
|
+
new_runner = stub
|
68
|
+
Rapns::Daemon::Apns::AppRunner.should_receive(:new).with(new_app).and_return(new_runner)
|
69
|
+
new_runner.should_receive(:start)
|
70
|
+
Rapns::Daemon::AppRunner.sync
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'deletes old apps' do
|
74
|
+
Rapns::App.stub(:all => [])
|
75
|
+
runner.should_receive(:stop)
|
76
|
+
Rapns::Daemon::AppRunner.sync
|
77
|
+
end
|
78
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require "
|
1
|
+
require "unit_spec_helper"
|
2
2
|
|
3
3
|
describe Rapns::Daemon::DatabaseReconnectable do
|
4
4
|
class TestDouble
|
@@ -7,7 +7,6 @@ describe Rapns::Daemon::DatabaseReconnectable do
|
|
7
7
|
attr_reader :name
|
8
8
|
|
9
9
|
def initialize(error, max_calls)
|
10
|
-
@name = 'TestDouble'
|
11
10
|
@error = error
|
12
11
|
@max_calls = max_calls
|
13
12
|
@calls = 0
|
@@ -53,12 +52,12 @@ describe Rapns::Daemon::DatabaseReconnectable do
|
|
53
52
|
end
|
54
53
|
|
55
54
|
it "should log that the database is being reconnected" do
|
56
|
-
Rapns::Daemon.logger.should_receive(:warn).with("
|
55
|
+
Rapns::Daemon.logger.should_receive(:warn).with("Lost connection to database, reconnecting...")
|
57
56
|
test_double.perform
|
58
57
|
end
|
59
58
|
|
60
59
|
it "should log the reconnection attempt" do
|
61
|
-
Rapns::Daemon.logger.should_receive(:warn).with("
|
60
|
+
Rapns::Daemon.logger.should_receive(:warn).with("Attempt 1")
|
62
61
|
test_double.perform
|
63
62
|
end
|
64
63
|
|
@@ -91,7 +90,7 @@ describe Rapns::Daemon::DatabaseReconnectable do
|
|
91
90
|
end
|
92
91
|
|
93
92
|
it "should log the 2nd attempt" do
|
94
|
-
Rapns::Daemon.logger.should_receive(:warn).with("
|
93
|
+
Rapns::Daemon.logger.should_receive(:warn).with("Attempt 2")
|
95
94
|
test_double.perform
|
96
95
|
end
|
97
96
|
|
@@ -1,10 +1,10 @@
|
|
1
|
-
require "
|
1
|
+
require "unit_spec_helper"
|
2
2
|
|
3
3
|
describe Rapns::DeliveryError do
|
4
4
|
let(:error) { Rapns::DeliveryError.new(4, 12, "Missing payload") }
|
5
5
|
|
6
6
|
it "returns an informative message" do
|
7
|
-
error.message.should == "Unable to deliver notification 12, received
|
7
|
+
error.message.should == "Unable to deliver notification 12, received error 4 (Missing payload)"
|
8
8
|
end
|
9
9
|
|
10
10
|
it "returns the error code" do
|
@@ -0,0 +1,19 @@
|
|
1
|
+
shared_examples_for 'an DeliveryHandler subclass' do
|
2
|
+
it "instructs the queue to wakeup the thread when told to stop" do
|
3
|
+
thread = stub(:join => nil)
|
4
|
+
Thread.stub(:new => thread)
|
5
|
+
queue.should_receive(:wakeup).with(thread)
|
6
|
+
delivery_handler.start
|
7
|
+
delivery_handler.stop
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "when being stopped" do
|
11
|
+
before { queue.pop }
|
12
|
+
|
13
|
+
it "does not attempt to deliver a notification when a DeliveryQueue::::WakeupError is raised" do
|
14
|
+
queue.stub(:pop).and_raise(Rapns::Daemon::DeliveryQueue::WakeupError)
|
15
|
+
delivery_handler.should_not_receive(:deliver)
|
16
|
+
delivery_handler.send(:handle_next_notification)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,79 +1,79 @@
|
|
1
|
-
require "
|
1
|
+
require "unit_spec_helper"
|
2
2
|
|
3
3
|
describe Rapns::Daemon::Feeder do
|
4
|
-
let(:poll) { 2 }
|
5
4
|
let(:config) { stub(:batch_size => 5000) }
|
6
|
-
let(:
|
5
|
+
let!(:app) { Rapns::Apns::App.create!(:name => 'my_app', :environment => 'development', :certificate => TEST_CERT) }
|
6
|
+
let(:notification) { Rapns::Apns::Notification.create!(:device_token => "a" * 64, :app => app) }
|
7
7
|
let(:logger) { stub }
|
8
8
|
|
9
9
|
before do
|
10
|
-
Rapns::Daemon::Feeder.stub(:sleep)
|
11
|
-
Rapns::Daemon::Feeder.stub(:interruptible_sleep)
|
12
10
|
Rapns::Daemon.stub(:logger => logger, :config => config)
|
13
|
-
Rapns::Daemon::Feeder.instance_variable_set("@stop",
|
14
|
-
Rapns::Daemon::AppRunner.stub(:
|
15
|
-
|
11
|
+
Rapns::Daemon::Feeder.instance_variable_set("@stop", true)
|
12
|
+
Rapns::Daemon::AppRunner.stub(:idle => [stub(:app => app)])
|
13
|
+
end
|
14
|
+
|
15
|
+
def start
|
16
|
+
Rapns::Daemon::Feeder.start(0)
|
16
17
|
end
|
17
18
|
|
18
19
|
it "checks for new notifications with the ability to reconnect the database" do
|
19
20
|
Rapns::Daemon::Feeder.should_receive(:with_database_reconnect_and_retry)
|
20
|
-
|
21
|
+
start
|
21
22
|
end
|
22
23
|
|
23
24
|
it 'loads notifications in batches' do
|
24
|
-
relation = stub
|
25
|
-
relation.should_receive(:
|
25
|
+
relation = stub.as_null_object
|
26
|
+
relation.should_receive(:limit).with(5000)
|
26
27
|
Rapns::Notification.stub(:ready_for_delivery => relation)
|
27
|
-
|
28
|
+
start
|
28
29
|
end
|
29
30
|
|
30
|
-
it "
|
31
|
+
it "enqueue the notification" do
|
31
32
|
notification.update_attributes!(:delivered => false)
|
32
|
-
Rapns::Daemon::AppRunner.should_receive(:
|
33
|
-
|
33
|
+
Rapns::Daemon::AppRunner.should_receive(:enqueue).with(notification)
|
34
|
+
start
|
34
35
|
end
|
35
36
|
|
36
37
|
it 'does not enqueue the notification if the app runner is still processing the previous batch' do
|
37
|
-
Rapns::Daemon::AppRunner.
|
38
|
-
|
39
|
-
Rapns::Daemon::Feeder.enqueue_notifications
|
38
|
+
Rapns::Daemon::AppRunner.should_not_receive(:enqueue)
|
39
|
+
start
|
40
40
|
end
|
41
41
|
|
42
42
|
it "enqueues an undelivered notification without deliver_after set" do
|
43
43
|
notification.update_attributes!(:delivered => false, :deliver_after => nil)
|
44
|
-
Rapns::Daemon::AppRunner.should_receive(:
|
45
|
-
|
44
|
+
Rapns::Daemon::AppRunner.should_receive(:enqueue).with(notification)
|
45
|
+
start
|
46
46
|
end
|
47
47
|
|
48
48
|
it "enqueues a notification with a deliver_after time in the past" do
|
49
49
|
notification.update_attributes!(:delivered => false, :deliver_after => 1.hour.ago)
|
50
|
-
Rapns::Daemon::AppRunner.should_receive(:
|
51
|
-
|
50
|
+
Rapns::Daemon::AppRunner.should_receive(:enqueue).with(notification)
|
51
|
+
start
|
52
52
|
end
|
53
53
|
|
54
54
|
it "does not enqueue a notification with a deliver_after time in the future" do
|
55
55
|
notification.update_attributes!(:delivered => false, :deliver_after => 1.hour.from_now)
|
56
|
-
Rapns::Daemon::AppRunner.should_not_receive(:
|
57
|
-
|
56
|
+
Rapns::Daemon::AppRunner.should_not_receive(:enqueue)
|
57
|
+
start
|
58
58
|
end
|
59
59
|
|
60
60
|
it "does not enqueue a previously delivered notification" do
|
61
61
|
notification.update_attributes!(:delivered => true, :delivered_at => Time.now)
|
62
|
-
Rapns::Daemon::AppRunner.should_not_receive(:
|
63
|
-
|
62
|
+
Rapns::Daemon::AppRunner.should_not_receive(:enqueue)
|
63
|
+
start
|
64
64
|
end
|
65
65
|
|
66
66
|
it "does not enqueue a notification that has previously failed delivery" do
|
67
67
|
notification.update_attributes!(:delivered => false, :failed => true)
|
68
|
-
Rapns::Daemon::AppRunner.should_not_receive(:
|
69
|
-
|
68
|
+
Rapns::Daemon::AppRunner.should_not_receive(:enqueue)
|
69
|
+
start
|
70
70
|
end
|
71
71
|
|
72
72
|
it "logs errors" do
|
73
73
|
e = StandardError.new("bork")
|
74
74
|
Rapns::Notification.stub(:ready_for_delivery).and_raise(e)
|
75
75
|
Rapns::Daemon.logger.should_receive(:error).with(e)
|
76
|
-
|
76
|
+
start
|
77
77
|
end
|
78
78
|
|
79
79
|
it "interrupts sleep when stopped" do
|
@@ -84,12 +84,12 @@ describe Rapns::Daemon::Feeder do
|
|
84
84
|
it "enqueues notifications when started" do
|
85
85
|
Rapns::Daemon::Feeder.should_receive(:enqueue_notifications).at_least(:once)
|
86
86
|
Rapns::Daemon::Feeder.stub(:loop).and_yield
|
87
|
-
|
87
|
+
start
|
88
88
|
end
|
89
89
|
|
90
90
|
it "sleeps for the given period" do
|
91
|
-
Rapns::Daemon::Feeder.should_receive(:interruptible_sleep).with(
|
91
|
+
Rapns::Daemon::Feeder.should_receive(:interruptible_sleep).with(2)
|
92
92
|
Rapns::Daemon::Feeder.stub(:loop).and_yield
|
93
|
-
Rapns::Daemon::Feeder.start(
|
93
|
+
Rapns::Daemon::Feeder.start(2)
|
94
94
|
end
|
95
|
-
end
|
95
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'unit_spec_helper'
|
2
|
+
require File.dirname(__FILE__) + '/../app_runner_shared.rb'
|
3
|
+
|
4
|
+
describe Rapns::Daemon::Gcm::AppRunner do
|
5
|
+
it_behaves_like 'an AppRunner subclass'
|
6
|
+
|
7
|
+
let(:app_class) { Rapns::Gcm::App }
|
8
|
+
let(:app) { app_class.new }
|
9
|
+
let(:runner) { Rapns::Daemon::Gcm::AppRunner.new(app) }
|
10
|
+
let(:handler) { stub(:start => nil, :stop => nil, :queue= => nil) }
|
11
|
+
|
12
|
+
before do
|
13
|
+
Rapns::Daemon::Gcm::DeliveryHandler.stub(:new => handler)
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "unit_spec_helper"
|
2
|
+
require File.dirname(__FILE__) + '/../delivery_handler_shared.rb'
|
3
|
+
|
4
|
+
describe Rapns::Daemon::Gcm::DeliveryHandler do
|
5
|
+
it_should_behave_like 'an DeliveryHandler subclass'
|
6
|
+
|
7
|
+
let(:app) { stub }
|
8
|
+
let(:delivery_handler) { Rapns::Daemon::Gcm::DeliveryHandler.new(app) }
|
9
|
+
let(:notification) { stub }
|
10
|
+
let(:http) { stub(:shutdown => nil)}
|
11
|
+
let(:queue) { Rapns::Daemon::DeliveryQueue.new }
|
12
|
+
|
13
|
+
before do
|
14
|
+
Net::HTTP::Persistent.stub(:new => http)
|
15
|
+
Rapns::Daemon::Gcm::Delivery.stub(:perform)
|
16
|
+
delivery_handler.queue = queue
|
17
|
+
queue.push(notification)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'performs delivery of an notification' do
|
21
|
+
Rapns::Daemon::Gcm::Delivery.should_receive(:perform).with(app, http, notification)
|
22
|
+
delivery_handler.start
|
23
|
+
delivery_handler.stop
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'initiates a persistent connection object' do
|
27
|
+
Net::HTTP::Persistent.should_receive(:new).with('rapns')
|
28
|
+
Rapns::Daemon::Gcm::DeliveryHandler.new(app)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'shuts down the http connection stopped' do
|
32
|
+
http.should_receive(:shutdown)
|
33
|
+
delivery_handler.start
|
34
|
+
delivery_handler.stop
|
35
|
+
end
|
36
|
+
end
|