rapns 1.0.7 → 2.0.0rc1

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.
Files changed (39) hide show
  1. data/CHANGELOG.md +7 -0
  2. data/LICENSE +7 -0
  3. data/README.md +58 -41
  4. data/bin/rapns +23 -5
  5. data/lib/generators/rapns_generator.rb +2 -4
  6. data/lib/generators/templates/add_app_to_rapns.rb +11 -0
  7. data/lib/generators/templates/create_rapns_apps.rb +15 -0
  8. data/lib/rapns/app.rb +9 -0
  9. data/lib/rapns/daemon/app_runner.rb +131 -0
  10. data/lib/rapns/daemon/connection.rb +5 -3
  11. data/lib/rapns/daemon/delivery_handler.rb +13 -15
  12. data/lib/rapns/daemon/delivery_handler_pool.rb +8 -10
  13. data/lib/rapns/daemon/delivery_queue.rb +36 -4
  14. data/lib/rapns/daemon/feedback_receiver.rb +19 -12
  15. data/lib/rapns/daemon/feeder.rb +8 -10
  16. data/lib/rapns/daemon/logger.rb +5 -3
  17. data/lib/rapns/daemon.rb +52 -38
  18. data/lib/rapns/notification.rb +16 -5
  19. data/lib/rapns/patches.rb +2 -2
  20. data/lib/rapns/version.rb +1 -1
  21. data/lib/rapns.rb +2 -1
  22. data/spec/rapns/daemon/app_runner_spec.rb +207 -0
  23. data/spec/rapns/daemon/connection_spec.rb +177 -236
  24. data/spec/rapns/daemon/delivery_handler_pool_spec.rb +10 -14
  25. data/spec/rapns/daemon/delivery_handler_spec.rb +92 -79
  26. data/spec/rapns/daemon/feedback_receiver_spec.rb +29 -23
  27. data/spec/rapns/daemon/feeder_spec.rb +40 -44
  28. data/spec/rapns/daemon/logger_spec.rb +21 -3
  29. data/spec/rapns/daemon_spec.rb +65 -125
  30. data/spec/rapns/notification_spec.rb +16 -0
  31. data/spec/spec_helper.rb +4 -1
  32. metadata +14 -15
  33. data/History.md +0 -5
  34. data/lib/generators/templates/rapns.yml +0 -31
  35. data/lib/rapns/daemon/certificate.rb +0 -27
  36. data/lib/rapns/daemon/configuration.rb +0 -98
  37. data/lib/rapns/daemon/pool.rb +0 -36
  38. data/spec/rapns/daemon/certificate_spec.rb +0 -22
  39. data/spec/rapns/daemon/configuration_spec.rb +0 -231
@@ -1,178 +1,191 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Rapns::Daemon::DeliveryHandler do
4
- let(:delivery_handler) { Rapns::Daemon::DeliveryHandler.new(0) }
4
+ let(:queue) { Rapns::Daemon::DeliveryQueue.new }
5
+ let(:name) { 'my_app:0' }
6
+ let(:host) { 'localhost' }
7
+ let(:port) { 2195 }
8
+ let(:certificate) { stub }
9
+ let(:password) { stub }
10
+ let(:delivery_handler) { Rapns::Daemon::DeliveryHandler.new(queue, name, host, port, certificate, password) }
11
+ let(:connection) { stub(:select => false, :write => nil, :reconnect => nil, :close => nil, :connect => nil) }
12
+ let(:logger) { stub(:error => nil, :info => nil) }
13
+ let(:notification) { stub.as_null_object }
14
+ let(:config) { stub(:check_for_errors => true) }
15
+ let(:delivery_queues) { [] }
5
16
 
6
17
  before do
7
- @notification = Rapns::Notification.create!(:device_token => "a" * 64)
8
- Rapns::Daemon.stub(:delivery_queue).and_return(Rapns::Daemon::DeliveryQueue.new)
9
- Rapns::Daemon.delivery_queue.push(@notification)
10
- @connection = mock("Connection", :connect => nil, :write => nil, :close => nil, :select => nil, :read => nil)
11
- Rapns::Daemon::Connection.stub(:new).and_return(@connection)
12
- configuration = mock("Configuration", :push => stub(:host => "gateway.push.apple.com", :port => 2195))
13
- Rapns::Daemon.stub(:configuration).and_return(configuration)
14
- @logger = mock("Logger", :error => nil, :info => nil)
15
- Rapns::Daemon.stub(:logger).and_return(@logger)
18
+ Rapns::Daemon::Connection.stub(:new => connection)
19
+ Rapns::Daemon.stub(:delivery_queues => delivery_queues, :logger => logger, :config => config)
20
+ queue.push(notification)
16
21
  end
17
22
 
18
23
  it "instantiates a new connection" do
19
- Rapns::Daemon::Connection.should_receive(:new).with('DeliveryHandler 0', 'gateway.push.apple.com', 2195)
24
+ Rapns::Daemon::Connection.should_receive(:new).with("DeliveryHandler:#{name}", host, port, certificate, password)
20
25
  delivery_handler
21
26
  end
22
27
 
23
28
  it "connects the socket when started" do
24
- @connection.should_receive(:connect)
29
+ connection.should_receive(:connect)
25
30
  delivery_handler.start
26
31
  delivery_handler.stop
27
32
  end
28
33
 
29
- it "pushes a STOP instruction into the queue when told to stop" do
30
- Rapns::Daemon.delivery_queue.should_receive(:push).with(Rapns::Daemon::DeliveryHandler::STOP)
34
+ it "instructs the queue to wakeup the thread when told to stop" do
35
+ thread = stub
36
+ Thread.stub(:new => thread)
37
+ queue.should_receive(:wakeup).with(thread)
38
+ delivery_handler.start
31
39
  delivery_handler.stop
32
40
  end
33
41
 
34
- it "closes the connection when a STOP instruction is received" do
35
- Rapns::Daemon.delivery_queue.push(Rapns::Daemon::DeliveryHandler::STOP)
42
+ it "sends the binary version of the notification" do
43
+ notification.stub(:to_binary => "hi mom")
44
+ connection.should_receive(:write).with("hi mom")
36
45
  delivery_handler.send(:handle_next_notification)
37
46
  end
38
47
 
39
- it "should pop a new notification from the delivery queue" do
40
- Rapns::Daemon.delivery_queue.should_receive(:pop)
48
+ it "logs the notification delivery" do
49
+ notification.stub(:id => 666, :device_token => 'abc123')
50
+ logger.should_receive(:info).with("[DeliveryHandler:my_app:0] 666 sent to abc123")
41
51
  delivery_handler.send(:handle_next_notification)
42
52
  end
43
53
 
44
- it "does not attempt to deliver a notification when a STOP instruction is received" do
45
- Rapns::Daemon.delivery_queue.pop # empty the queue
46
- delivery_handler.should_not_receive(:deliver)
47
- Rapns::Daemon.delivery_queue.push(Rapns::Daemon::DeliveryHandler::STOP)
54
+ it "marks the notification as delivered" do
55
+ notification.should_receive(:delivered=).with(true)
48
56
  delivery_handler.send(:handle_next_notification)
49
57
  end
50
58
 
51
- it "should send the binary version of the notification" do
52
- @notification.stub((:to_binary)).and_return("hi mom")
53
- @connection.should_receive(:write).with("hi mom")
59
+ it "sets the time the notification was delivered" do
60
+ now = Time.now
61
+ Time.stub(:now).and_return(now)
62
+ notification.should_receive(:delivered_at=).with(now)
54
63
  delivery_handler.send(:handle_next_notification)
55
64
  end
56
65
 
57
- it "should log the notification delivery" do
58
- Rapns::Daemon.logger.should_receive(:info).with("Notification #{@notification.id} delivered to #{@notification.device_token}")
66
+ it "does not trigger validations when saving the notification" do
67
+ notification.should_receive(:save!).with(:validate => false)
59
68
  delivery_handler.send(:handle_next_notification)
60
69
  end
61
70
 
62
- it "should mark the notification as delivered" do
63
- expect { delivery_handler.send(:handle_next_notification); @notification.reload }.to change(@notification, :delivered).to(true)
64
- end
65
-
66
- it "should set the time the notification was delivered" do
67
- @notification.delivered_at.should be_nil
71
+ it "updates notification with the ability to reconnect the database" do
72
+ delivery_handler.should_receive(:with_database_reconnect_and_retry)
68
73
  delivery_handler.send(:handle_next_notification)
69
- @notification.reload
70
- @notification.delivered_at.should be_kind_of(Time)
71
74
  end
72
75
 
73
- it "should not trigger validations when saving the notification" do
74
- @notification.should_receive(:save!).with(:validate => false)
76
+ it "logs if an error is raised when updating the notification" do
77
+ e = StandardError.new("bork!")
78
+ notification.stub(:save!).and_raise(e)
79
+ Rapns::Daemon.logger.should_receive(:error).with(e)
75
80
  delivery_handler.send(:handle_next_notification)
76
81
  end
77
82
 
78
- it "should update notification with the ability to reconnect the database" do
79
- delivery_handler.should_receive(:with_database_reconnect_and_retry)
83
+ it "notifies the delivery queue the notification has been processed" do
84
+ queue.should_receive(:notification_processed)
80
85
  delivery_handler.send(:handle_next_notification)
81
86
  end
82
87
 
83
- it "should log if an error is raised when updating the notification" do
84
- e = StandardError.new("bork!")
85
- @notification.stub(:save!).and_raise(e)
86
- Rapns::Daemon.logger.should_receive(:error).with(e)
88
+ it 'does not check for errors if check_for_errors config option is false' do
89
+ config.stub(:check_for_errors => false)
90
+ delivery_handler.should_not_receive(:check_for_error)
87
91
  delivery_handler.send(:handle_next_notification)
88
92
  end
89
93
 
90
- it "should notify the delivery queue the notification has been processed" do
91
- Rapns::Daemon.delivery_queue.should_receive(:notification_processed)
92
- delivery_handler.send(:handle_next_notification)
94
+ describe "when being stopped" do
95
+ before { queue.pop }
96
+
97
+ it "closes the connection when a DeliveryQueue::WakeupError is raised" do
98
+ connection.should_receive(:close)
99
+ queue.stub(:pop).and_raise(Rapns::Daemon::DeliveryQueue::WakeupError)
100
+ delivery_handler.send(:handle_next_notification)
101
+ end
102
+
103
+ it "does not attempt to deliver a notification when a DeliveryQueue::::WakeupError is raised" do
104
+ queue.stub(:pop).and_raise(Rapns::Daemon::DeliveryQueue::WakeupError)
105
+ delivery_handler.should_not_receive(:deliver)
106
+ delivery_handler.send(:handle_next_notification)
107
+ end
93
108
  end
94
109
 
95
110
  describe "when delivery fails" do
96
- before do
97
- @connection.stub(:select => true, :read => [8, 4, 69].pack("ccN"), :reconnect => nil)
98
- end
111
+ before { connection.stub(:select => true, :read => [8, 4, 69].pack("ccN")) }
99
112
 
100
- it "should update notification with the ability to reconnect the database" do
113
+ it "updates notification with the ability to reconnect the database" do
101
114
  delivery_handler.should_receive(:with_database_reconnect_and_retry)
102
115
  delivery_handler.send(:handle_next_notification)
103
116
  end
104
117
 
105
- it "should set the notification as not delivered" do
106
- @notification.should_receive(:delivered=).with(false)
118
+ it "sets the notification as not delivered" do
119
+ notification.should_receive(:delivered=).with(false)
107
120
  delivery_handler.send(:handle_next_notification)
108
121
  end
109
122
 
110
- it "should set the notification delivered_at timestamp to nil" do
111
- @notification.should_receive(:delivered_at=).with(nil)
123
+ it "sets the notification delivered_at timestamp to nil" do
124
+ notification.should_receive(:delivered_at=).with(nil)
112
125
  delivery_handler.send(:handle_next_notification)
113
126
  end
114
127
 
115
- it "should set the notification as failed" do
116
- @notification.should_receive(:failed=).with(true)
128
+ it "sets the notification as failed" do
129
+ notification.should_receive(:failed=).with(true)
117
130
  delivery_handler.send(:handle_next_notification)
118
131
  end
119
132
 
120
- it "should set the notification failed_at timestamp" do
133
+ it "sets the notification failed_at timestamp" do
121
134
  now = Time.now
122
135
  Time.stub(:now).and_return(now)
123
- @notification.should_receive(:failed_at=).with(now)
136
+ notification.should_receive(:failed_at=).with(now)
124
137
  delivery_handler.send(:handle_next_notification)
125
138
  end
126
139
 
127
- it "should set the notification error code" do
128
- @notification.should_receive(:error_code=).with(4)
140
+ it "sets the notification error code" do
141
+ notification.should_receive(:error_code=).with(4)
129
142
  delivery_handler.send(:handle_next_notification)
130
143
  end
131
144
 
132
- it "should log the delivery error" do
145
+ it "logs the delivery error" do
133
146
  error = Rapns::DeliveryError.new(4, 12, "Missing payload")
134
147
  Rapns::DeliveryError.stub(:new => error)
135
- Rapns::Daemon.logger.should_receive(:error).with(error)
148
+ logger.should_receive(:error).with(error)
136
149
  delivery_handler.send(:handle_next_notification)
137
150
  end
138
151
 
139
- it "should set the notification error description" do
140
- @notification.should_receive(:error_description=).with("Missing payload")
152
+ it "sets the notification error description" do
153
+ notification.should_receive(:error_description=).with("Missing payload")
141
154
  delivery_handler.send(:handle_next_notification)
142
155
  end
143
156
 
144
- it "should skip validation when saving the notification" do
145
- @notification.should_receive(:save!).with(:validate => false)
157
+ it "skips validation when saving the notification" do
158
+ notification.should_receive(:save!).with(:validate => false)
146
159
  delivery_handler.send(:handle_next_notification)
147
160
  end
148
161
 
149
- it "should read 6 bytes from the socket" do
150
- @connection.should_receive(:read).with(6).and_return(nil)
162
+ it "reads 6 bytes from the socket" do
163
+ connection.should_receive(:read).with(6).and_return(nil)
151
164
  delivery_handler.send(:handle_next_notification)
152
165
  end
153
166
 
154
- it "should not attempt to read from the socket if the socket was not selected for reading after the timeout" do
155
- @connection.stub(:select => nil)
156
- @connection.should_not_receive(:read)
167
+ it "does not attempt to read from the socket if the socket was not selected for reading after the timeout" do
168
+ connection.stub(:select => nil)
169
+ connection.should_not_receive(:read)
157
170
  delivery_handler.send(:handle_next_notification)
158
171
  end
159
172
 
160
- it "should reconnect the socket" do
161
- @connection.should_receive(:reconnect)
173
+ it "reconnects the socket" do
174
+ connection.should_receive(:reconnect)
162
175
  delivery_handler.send(:handle_next_notification)
163
176
  end
164
177
 
165
- it "should log that the connection is being reconnected" do
166
- Rapns::Daemon.logger.should_receive(:error).with("[DeliveryHandler 0] Error received, reconnecting...")
178
+ it "logs that the connection is being reconnected" do
179
+ Rapns::Daemon.logger.should_receive(:error).with("[DeliveryHandler:my_app:0] Error received, reconnecting...")
167
180
  delivery_handler.send(:handle_next_notification)
168
181
  end
169
182
 
170
183
  context "when the APNs disconnects without returning an error" do
171
184
  before do
172
- @connection.stub(:read => nil)
185
+ connection.stub(:read => nil)
173
186
  end
174
187
 
175
- it 'should raise a DisconnectError error if the connection is closed without an error being returned' do
188
+ it 'raises a DisconnectError error if the connection is closed without an error being returned' do
176
189
  error = Rapns::DisconnectionError.new
177
190
  Rapns::DisconnectionError.should_receive(:new).and_return(error)
178
191
  Rapns::Daemon.logger.should_receive(:error).with(error)
@@ -180,12 +193,12 @@ describe Rapns::Daemon::DeliveryHandler do
180
193
  end
181
194
 
182
195
  it 'does not set the error code on the notification' do
183
- @notification.should_receive(:error_code=).with(nil)
196
+ notification.should_receive(:error_code=).with(nil)
184
197
  delivery_handler.send(:handle_next_notification)
185
198
  end
186
199
 
187
200
  it 'sets the error descriptipon on the notification' do
188
- @notification.should_receive(:error_description=).with("APNs disconnected without returning an error.")
201
+ notification.should_receive(:error_description=).with("APNs disconnected without returning an error.")
189
202
  delivery_handler.send(:handle_next_notification)
190
203
  end
191
204
  end
@@ -1,16 +1,22 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Rapns::Daemon::FeedbackReceiver, 'check_for_feedback' do
4
+ let(:host) { 'feedback.push.apple.com' }
5
+ let(:port) { 2196 }
6
+ let(:poll) { 60 }
7
+ let(:certificate) { stub }
8
+ let(:password) { stub }
9
+ let(:app) { 'my_app' }
4
10
  let(:connection) { stub(:connect => nil, :read => nil, :close => nil) }
5
11
  let(:logger) { stub(:error => nil, :info => nil) }
12
+ let(:receiever) { Rapns::Daemon::FeedbackReceiver.new(app, host, port, poll, certificate, password) }
6
13
 
7
14
  before do
8
- Rapns::Daemon::FeedbackReceiver.stub(:interruptible_sleep)
15
+ receiever.stub(:interruptible_sleep)
9
16
  Rapns::Daemon.logger = logger
10
17
  Rapns::Daemon::Connection.stub(:new => connection)
11
18
  Rapns::Feedback.stub(:create!)
12
- Rapns::Daemon.configuration = stub(:feedback => stub(:host => 'feedback.push.apple.com', :port => 2196, :poll => 60))
13
- Rapns::Daemon::FeedbackReceiver.instance_variable_set("@stop", false)
19
+ receiever.instance_variable_set("@stop", false)
14
20
  end
15
21
 
16
22
  def stub_connection_read_with_tuple
@@ -25,62 +31,62 @@ describe Rapns::Daemon::FeedbackReceiver, 'check_for_feedback' do
25
31
  end
26
32
 
27
33
  it 'instantiates a new connection' do
28
- Rapns::Daemon::Connection.should_receive(:new).with("FeedbackReceiver", 'feedback.push.apple.com', 2196)
29
- Rapns::Daemon::FeedbackReceiver.check_for_feedback
34
+ Rapns::Daemon::Connection.should_receive(:new).with("FeedbackReceiver:#{app}", host, port, certificate, password)
35
+ receiever.check_for_feedback
30
36
  end
31
37
 
32
38
  it 'connects to the feeback service' do
33
39
  connection.should_receive(:connect)
34
- Rapns::Daemon::FeedbackReceiver.check_for_feedback
40
+ receiever.check_for_feedback
35
41
  end
36
42
 
37
43
  it 'closes the connection' do
38
44
  connection.should_receive(:close)
39
- Rapns::Daemon::FeedbackReceiver.check_for_feedback
45
+ receiever.check_for_feedback
40
46
  end
41
47
 
42
48
  it 'reads from the connection' do
43
49
  connection.should_receive(:read).with(38)
44
- Rapns::Daemon::FeedbackReceiver.check_for_feedback
50
+ receiever.check_for_feedback
45
51
  end
46
52
 
47
53
  it 'logs the feedback' do
48
54
  stub_connection_read_with_tuple
49
- Rapns::Daemon.logger.should_receive(:info).with("[FeedbackReceiver] Delivery failed at 2011-12-10 16:08:45 UTC for 834f786655eb9f84614a05ad7d00af31e5cfe93ac3ea078f1da44d2a4eb0ce17")
50
- Rapns::Daemon::FeedbackReceiver.check_for_feedback
55
+ Rapns::Daemon.logger.should_receive(:info).with("[FeedbackReceiver:my_app] Delivery failed at 2011-12-10 16:08:45 UTC for 834f786655eb9f84614a05ad7d00af31e5cfe93ac3ea078f1da44d2a4eb0ce17")
56
+ receiever.check_for_feedback
51
57
  end
52
58
 
53
59
  it 'creates the feedback' do
54
60
  stub_connection_read_with_tuple
55
- Rapns::Feedback.should_receive(:create!).with(:failed_at => Time.at(1323533325), :device_token => '834f786655eb9f84614a05ad7d00af31e5cfe93ac3ea078f1da44d2a4eb0ce17')
56
- Rapns::Daemon::FeedbackReceiver.check_for_feedback
61
+ Rapns::Feedback.should_receive(:create!).with(:failed_at => Time.at(1323533325), :device_token => '834f786655eb9f84614a05ad7d00af31e5cfe93ac3ea078f1da44d2a4eb0ce17', :app => 'my_app')
62
+ receiever.check_for_feedback
57
63
  end
58
64
 
59
65
  it 'logs errors' do
60
66
  error = StandardError.new('bork!')
61
67
  connection.stub(:read).and_raise(error)
62
68
  Rapns::Daemon.logger.should_receive(:error).with(error)
63
- Rapns::Daemon::FeedbackReceiver.check_for_feedback
69
+ receiever.check_for_feedback
64
70
  end
65
71
 
66
72
  it 'sleeps for the feedback poll period' do
67
- Rapns::Daemon::FeedbackReceiver.stub(:check_for_feedback)
68
- Rapns::Daemon::FeedbackReceiver.should_receive(:interruptible_sleep).with(60).at_least(:once)
73
+ receiever.stub(:check_for_feedback)
74
+ receiever.should_receive(:interruptible_sleep).with(60).at_least(:once)
69
75
  Thread.stub(:new).and_yield
70
- Rapns::Daemon::FeedbackReceiver.stub(:loop).and_yield
71
- Rapns::Daemon::FeedbackReceiver.start
76
+ receiever.stub(:loop).and_yield
77
+ receiever.start
72
78
  end
73
79
 
74
80
  it 'checks for feedback when started' do
75
- Rapns::Daemon::FeedbackReceiver.should_receive(:check_for_feedback).at_least(:once)
81
+ receiever.should_receive(:check_for_feedback).at_least(:once)
76
82
  Thread.stub(:new).and_yield
77
- Rapns::Daemon::FeedbackReceiver.stub(:loop).and_yield
78
- Rapns::Daemon::FeedbackReceiver.start
83
+ receiever.stub(:loop).and_yield
84
+ receiever.start
79
85
  end
80
86
 
81
87
  it 'interrupts sleep when stopped' do
82
- Rapns::Daemon::FeedbackReceiver.stub(:check_for_feedback)
83
- Rapns::Daemon::FeedbackReceiver.should_receive(:interrupt_sleep)
84
- Rapns::Daemon::FeedbackReceiver.stop
88
+ receiever.stub(:check_for_feedback)
89
+ receiever.should_receive(:interrupt_sleep)
90
+ receiever.stop
85
91
  end
86
92
  end
@@ -1,79 +1,75 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Rapns::Daemon::Feeder do
4
+ let(:poll) { 2 }
5
+ let(:config) { stub(:batch_size => 5000) }
6
+ let(:notification) { Rapns::Notification.create!(:device_token => "a" * 64, :app => 'my_app') }
7
+ let(:logger) { stub }
8
+
4
9
  before do
5
10
  Rapns::Daemon::Feeder.stub(:sleep)
6
11
  Rapns::Daemon::Feeder.stub(:interruptible_sleep)
7
- @notification = Rapns::Notification.create!(:device_token => "a" * 64)
8
- @logger = mock("Logger", :info => nil, :error => nil, :warn => nil)
9
- Rapns::Daemon.stub(:logger).and_return(@logger)
10
- @queue = mock(:push => nil, :notifications_processed? => true)
11
- Rapns::Daemon.stub(:delivery_queue).and_return(@queue)
12
- Rapns::Daemon.stub(:configuration => mock("Configuration", :push => stub(:poll => 2)))
12
+ Rapns::Daemon.stub(:logger => logger, :config => config)
13
13
  Rapns::Daemon::Feeder.instance_variable_set("@stop", false)
14
+ Rapns::Daemon::AppRunner.stub(:ready => ['my_app'])
15
+ Rapns::Daemon::AppRunner.stub(:ready => ['my_app'])
14
16
  end
15
17
 
16
- it "should reconnect to the database when daemonized" do
17
- Rapns::Daemon::Feeder.stub(:loop)
18
- Rapns::Daemon::Feeder.should_receive(:reconnect_database)
19
- Rapns::Daemon::Feeder.start(false)
20
- end
21
-
22
- it "should check for new notifications with the ability to reconnect the database" do
18
+ it "checks for new notifications with the ability to reconnect the database" do
23
19
  Rapns::Daemon::Feeder.should_receive(:with_database_reconnect_and_retry)
24
20
  Rapns::Daemon::Feeder.enqueue_notifications
25
21
  end
26
22
 
27
- it "should not reconnect to the database when running in the foreground" do
28
- Rapns::Daemon::Feeder.stub(:loop)
29
- Rapns::Daemon::Feeder.should_not_receive(:reconnect_database)
30
- Rapns::Daemon::Feeder.start(true)
23
+ it 'loads notifications in batches' do
24
+ relation = stub
25
+ relation.should_receive(:find_each).with(:batch_size => 5000)
26
+ Rapns::Notification.stub(:ready_for_delivery => relation)
27
+ Rapns::Daemon::Feeder.enqueue_notifications
31
28
  end
32
29
 
33
- it "should enqueue an undelivered notification" do
34
- @notification.update_attributes!(:delivered => false)
35
- Rapns::Daemon.delivery_queue.should_receive(:push)
30
+ it "delivers the notification" do
31
+ notification.update_attributes!(:delivered => false)
32
+ Rapns::Daemon::AppRunner.should_receive(:deliver).with(notification)
36
33
  Rapns::Daemon::Feeder.enqueue_notifications
37
34
  end
38
35
 
39
- it "should enqueue an undelivered notification without deliver_after set" do
40
- @notification.update_attributes!(:delivered => false, :deliver_after => nil)
41
- Rapns::Daemon.delivery_queue.should_receive(:push)
36
+ it 'does not enqueue the notification if the app runner is still processing the previous batch' do
37
+ Rapns::Daemon::AppRunner.stub(:ready => [])
38
+ Rapns::Daemon::AppRunner.should_not_receive(:deliver)
42
39
  Rapns::Daemon::Feeder.enqueue_notifications
43
40
  end
44
41
 
45
- it "should enqueue a notification with a deliver_after time in the past" do
46
- @notification.update_attributes!(:delivered => false, :deliver_after => 1.hour.ago)
47
- Rapns::Daemon.delivery_queue.should_receive(:push)
42
+ it "enqueues an undelivered notification without deliver_after set" do
43
+ notification.update_attributes!(:delivered => false, :deliver_after => nil)
44
+ Rapns::Daemon::AppRunner.should_receive(:deliver).with(notification)
48
45
  Rapns::Daemon::Feeder.enqueue_notifications
49
46
  end
50
47
 
51
- it "should not enqueue a notification with a deliver_after time in the future" do
52
- @notification.update_attributes!(:delivered => false, :deliver_after => 1.hour.from_now)
53
- Rapns::Daemon.delivery_queue.should_not_receive(:push)
48
+ it "enqueues a notification with a deliver_after time in the past" do
49
+ notification.update_attributes!(:delivered => false, :deliver_after => 1.hour.ago)
50
+ Rapns::Daemon::AppRunner.should_receive(:deliver).with(notification)
54
51
  Rapns::Daemon::Feeder.enqueue_notifications
55
52
  end
56
53
 
57
- it "should not enqueue a previously delivered notification" do
58
- @notification.update_attributes!(:delivered => true, :delivered_at => Time.now)
59
- Rapns::Daemon.delivery_queue.should_not_receive(:push)
54
+ it "does not enqueue a notification with a deliver_after time in the future" do
55
+ notification.update_attributes!(:delivered => false, :deliver_after => 1.hour.from_now)
56
+ Rapns::Daemon::AppRunner.should_not_receive(:deliver)
60
57
  Rapns::Daemon::Feeder.enqueue_notifications
61
58
  end
62
59
 
63
- it "should not enqueue a notification that has previously failed delivery" do
64
- @notification.update_attributes!(:delivered => false, :failed => true)
65
- Rapns::Daemon.delivery_queue.should_not_receive(:push)
60
+ it "does not enqueue a previously delivered notification" do
61
+ notification.update_attributes!(:delivered => true, :delivered_at => Time.now)
62
+ Rapns::Daemon::AppRunner.should_not_receive(:deliver)
66
63
  Rapns::Daemon::Feeder.enqueue_notifications
67
64
  end
68
65
 
69
- it "should not enqueue more notifications if other are still being processed" do
70
- Rapns::Daemon.delivery_queue.stub(:notifications_processed? => false)
71
- Rapns::Notification.should_not_receive(:ready_for_delivery)
72
- Rapns::Daemon.delivery_queue.should_not_receive(:push)
66
+ it "does not enqueue a notification that has previously failed delivery" do
67
+ notification.update_attributes!(:delivered => false, :failed => true)
68
+ Rapns::Daemon::AppRunner.should_not_receive(:deliver)
73
69
  Rapns::Daemon::Feeder.enqueue_notifications
74
70
  end
75
71
 
76
- it "should log errors" do
72
+ it "logs errors" do
77
73
  e = StandardError.new("bork")
78
74
  Rapns::Notification.stub(:ready_for_delivery).and_raise(e)
79
75
  Rapns::Daemon.logger.should_receive(:error).with(e)
@@ -88,12 +84,12 @@ describe Rapns::Daemon::Feeder do
88
84
  it "enqueues notifications when started" do
89
85
  Rapns::Daemon::Feeder.should_receive(:enqueue_notifications).at_least(:once)
90
86
  Rapns::Daemon::Feeder.stub(:loop).and_yield
91
- Rapns::Daemon::Feeder.start(true)
87
+ Rapns::Daemon::Feeder.start(poll)
92
88
  end
93
89
 
94
- it "should sleep for the given period" do
95
- Rapns::Daemon::Feeder.should_receive(:interruptible_sleep).with(2)
90
+ it "sleeps for the given period" do
91
+ Rapns::Daemon::Feeder.should_receive(:interruptible_sleep).with(poll)
96
92
  Rapns::Daemon::Feeder.stub(:loop).and_yield
97
- Rapns::Daemon::Feeder.start(true)
93
+ Rapns::Daemon::Feeder.start(poll)
98
94
  end
99
95
  end
@@ -21,17 +21,30 @@ module Airbrake
21
21
  end
22
22
 
23
23
  describe Rapns::Daemon::Logger do
24
+ let(:log) { stub(:sync= => true) }
25
+ let(:config) { stub(:airbrake_notify => true) }
26
+
24
27
  before do
25
28
  Rails.stub(:root).and_return("/rails_root")
26
29
  @buffered_logger = mock("BufferedLogger", :info => nil, :error => nil, :level => 0, :auto_flushing => 1, :auto_flushing= => nil)
27
30
  Rails.logger = @buffered_logger
28
31
  ActiveSupport::BufferedLogger.stub(:new).and_return(@buffered_logger)
29
- configuration = mock("Configuration", :airbrake_notify? => true)
30
- Rapns::Daemon.stub(:configuration).and_return(configuration)
32
+ Rapns::Daemon.stub(:config => config)
33
+ File.stub(:open => log)
31
34
  end
32
35
 
33
36
  it "should open the a log file in the Rails log directory" do
34
- ActiveSupport::BufferedLogger.should_receive(:new).with("/rails_root/log/rapns.log", Rails.logger.level)
37
+ File.should_receive(:open).with('/rails_root/log/rapns.log', 'w')
38
+ Rapns::Daemon::Logger.new(:foreground => true)
39
+ end
40
+
41
+ it 'sets sync mode on the log descriptor' do
42
+ log.should_receive(:sync=).with(true)
43
+ Rapns::Daemon::Logger.new(:foreground => true)
44
+ end
45
+
46
+ it 'instantiates the BufferedLogger' do
47
+ ActiveSupport::BufferedLogger.should_receive(:new).with(log, Rails.logger.level)
35
48
  Rapns::Daemon::Logger.new(:foreground => true)
36
49
  end
37
50
 
@@ -69,6 +82,7 @@ describe Rapns::Daemon::Logger do
69
82
 
70
83
  it "should handle an Exception instance" do
71
84
  e = RuntimeError.new("hi mom")
85
+ e.stub(:backtrace => [])
72
86
  logger = Rapns::Daemon::Logger.new(:foreground => false)
73
87
  @buffered_logger.should_receive(:error).with(/RuntimeError, hi mom/)
74
88
  logger.error(e)
@@ -76,6 +90,7 @@ describe Rapns::Daemon::Logger do
76
90
 
77
91
  it "should notify Airbrake of the exception" do
78
92
  e = RuntimeError.new("hi mom")
93
+ e.stub(:backtrace => [])
79
94
  logger = Rapns::Daemon::Logger.new(:foreground => false, :airbrake_notify => true)
80
95
  Airbrake.should_receive(:notify_or_ignore).with(e)
81
96
  logger.error(e)
@@ -95,6 +110,7 @@ describe Rapns::Daemon::Logger do
95
110
 
96
111
  it "should notify using HoptoadNotifier" do
97
112
  e = RuntimeError.new("hi mom")
113
+ e.stub(:backtrace => [])
98
114
  logger = Rapns::Daemon::Logger.new(:foreground => false, :airbrake_notify => true)
99
115
  HoptoadNotifier.should_receive(:notify_or_ignore).with(e)
100
116
  logger.error(e)
@@ -103,6 +119,7 @@ describe Rapns::Daemon::Logger do
103
119
 
104
120
  it "should not notify Airbrake of the exception if the airbrake_notify option is false" do
105
121
  e = RuntimeError.new("hi mom")
122
+ e.stub(:backtrace => [])
106
123
  logger = Rapns::Daemon::Logger.new(:foreground => false, :airbrake_notify => false)
107
124
  Airbrake.should_not_receive(:notify_or_ignore).with(e)
108
125
  logger.error(e)
@@ -110,6 +127,7 @@ describe Rapns::Daemon::Logger do
110
127
 
111
128
  it "should not notify Airbrake if explicitly disabled in the call to error" do
112
129
  e = RuntimeError.new("hi mom")
130
+ e.stub(:backtrace => [])
113
131
  logger = Rapns::Daemon::Logger.new(:foreground => false, :airbrake_notify => true)
114
132
  Airbrake.should_not_receive(:notify_or_ignore).with(e)
115
133
  logger.error(e, :airbrake_notify => false)