rapns 2.0.5 → 3.0.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (82) hide show
  1. data/lib/generators/rapns_generator.rb +1 -0
  2. data/lib/generators/templates/add_gcm.rb +86 -0
  3. data/lib/generators/templates/create_rapns_notifications.rb +1 -1
  4. data/lib/rapns/apns/app.rb +8 -0
  5. data/lib/rapns/apns/binary_notification_validator.rb +12 -0
  6. data/lib/rapns/apns/device_token_format_validator.rb +12 -0
  7. data/lib/rapns/apns/feedback.rb +14 -0
  8. data/lib/rapns/apns/notification.rb +84 -0
  9. data/lib/rapns/app.rb +5 -6
  10. data/lib/rapns/{config.rb → configuration.rb} +5 -5
  11. data/lib/rapns/daemon/apns/app_runner.rb +36 -0
  12. data/lib/rapns/daemon/apns/connection.rb +113 -0
  13. data/lib/rapns/daemon/apns/delivery.rb +63 -0
  14. data/lib/rapns/daemon/apns/delivery_handler.rb +21 -0
  15. data/lib/rapns/daemon/apns/disconnection_error.rb +20 -0
  16. data/lib/rapns/daemon/apns/feedback_receiver.rb +74 -0
  17. data/lib/rapns/daemon/app_runner.rb +76 -77
  18. data/lib/rapns/daemon/database_reconnectable.rb +3 -3
  19. data/lib/rapns/daemon/delivery.rb +43 -0
  20. data/lib/rapns/daemon/delivery_error.rb +6 -2
  21. data/lib/rapns/daemon/delivery_handler.rb +13 -79
  22. data/lib/rapns/daemon/delivery_queue_18.rb +2 -2
  23. data/lib/rapns/daemon/delivery_queue_19.rb +3 -3
  24. data/lib/rapns/daemon/feeder.rb +5 -5
  25. data/lib/rapns/daemon/gcm/app_runner.rb +13 -0
  26. data/lib/rapns/daemon/gcm/delivery.rb +206 -0
  27. data/lib/rapns/daemon/gcm/delivery_handler.rb +20 -0
  28. data/lib/rapns/daemon.rb +31 -20
  29. data/lib/rapns/gcm/app.rb +7 -0
  30. data/lib/rapns/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +11 -0
  31. data/lib/rapns/gcm/notification.rb +31 -0
  32. data/lib/rapns/gcm/payload_size_validator.rb +13 -0
  33. data/lib/rapns/multi_json_helper.rb +16 -0
  34. data/lib/rapns/notification.rb +28 -95
  35. data/lib/rapns/version.rb +1 -1
  36. data/lib/rapns.rb +14 -4
  37. data/lib/tasks/cane.rake +19 -0
  38. data/lib/tasks/test.rake +34 -0
  39. data/spec/acceptance/gcm_upgrade_spec.rb +34 -0
  40. data/spec/acceptance_spec_helper.rb +85 -0
  41. data/spec/support/simplecov_helper.rb +13 -0
  42. data/spec/support/simplecov_quality_formatter.rb +8 -0
  43. data/spec/unit/apns/app_spec.rb +15 -0
  44. data/spec/unit/apns/feedback_spec.rb +12 -0
  45. data/spec/{rapns → unit/apns}/notification_spec.rb +44 -72
  46. data/spec/unit/app_spec.rb +18 -0
  47. data/spec/unit/daemon/apns/app_runner_spec.rb +37 -0
  48. data/spec/{rapns/daemon → unit/daemon/apns}/connection_spec.rb +9 -9
  49. data/spec/unit/daemon/apns/delivery_handler_spec.rb +48 -0
  50. data/spec/unit/daemon/apns/delivery_spec.rb +154 -0
  51. data/spec/{rapns/daemon → unit/daemon/apns}/feedback_receiver_spec.rb +14 -14
  52. data/spec/unit/daemon/app_runner_shared.rb +66 -0
  53. data/spec/unit/daemon/app_runner_spec.rb +78 -0
  54. data/spec/{rapns → unit}/daemon/database_reconnectable_spec.rb +4 -5
  55. data/spec/{rapns → unit}/daemon/delivery_error_spec.rb +2 -2
  56. data/spec/unit/daemon/delivery_handler_shared.rb +19 -0
  57. data/spec/{rapns → unit}/daemon/delivery_queue_spec.rb +1 -1
  58. data/spec/{rapns → unit}/daemon/feeder_spec.rb +33 -33
  59. data/spec/unit/daemon/gcm/app_runner_spec.rb +15 -0
  60. data/spec/unit/daemon/gcm/delivery_handler_spec.rb +36 -0
  61. data/spec/unit/daemon/gcm/delivery_spec.rb +236 -0
  62. data/spec/{rapns → unit}/daemon/interruptible_sleep_spec.rb +1 -1
  63. data/spec/{rapns → unit}/daemon/logger_spec.rb +1 -1
  64. data/spec/{rapns → unit}/daemon_spec.rb +1 -1
  65. data/spec/unit/gcm/app_spec.rb +5 -0
  66. data/spec/unit/gcm/notification_spec.rb +55 -0
  67. data/spec/unit/notification_shared.rb +38 -0
  68. data/spec/unit/notification_spec.rb +6 -0
  69. data/spec/{rapns/app_spec.rb → unit_spec_helper.rb} +76 -16
  70. metadata +107 -45
  71. data/lib/rapns/binary_notification_validator.rb +0 -10
  72. data/lib/rapns/daemon/connection.rb +0 -114
  73. data/lib/rapns/daemon/delivery_handler_pool.rb +0 -18
  74. data/lib/rapns/daemon/disconnection_error.rb +0 -14
  75. data/lib/rapns/daemon/feedback_receiver.rb +0 -82
  76. data/lib/rapns/device_token_format_validator.rb +0 -10
  77. data/lib/rapns/feedback.rb +0 -12
  78. data/spec/rapns/daemon/app_runner_spec.rb +0 -193
  79. data/spec/rapns/daemon/delivery_handler_pool_spec.rb +0 -17
  80. data/spec/rapns/daemon/delivery_handler_spec.rb +0 -206
  81. data/spec/rapns/feedback_spec.rb +0 -12
  82. 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 "spec_helper"
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, certificate, password) }
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 => 'my_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
- lambda { receiver.check_for_feedback }.should raise_error
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::configuration.feedback_callback = Proc.new {}
95
+ Rapns.configuration.feedback_callback = Proc.new {}
96
96
  feedback = Object.new
97
- Rapns::Feedback.stub(:create! => feedback)
98
- Rapns::configuration.feedback_callback.should_receive(:call).with(feedback)
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 "spec_helper"
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("[TestDouble] Lost connection to database, reconnecting...")
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("[TestDouble] Attempt 1")
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("[TestDouble] Attempt 2")
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 "spec_helper"
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 APN error 4 (Missing payload)"
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,4 +1,4 @@
1
- require "spec_helper"
1
+ require "unit_spec_helper"
2
2
 
3
3
  describe Rapns::Daemon::DeliveryQueue do
4
4
  let(:queue) { Rapns::Daemon::DeliveryQueue.new }
@@ -1,79 +1,79 @@
1
- require "spec_helper"
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(:notification) { Rapns::Notification.create!(:device_token => "a" * 64, :app => 'my_app') }
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", false)
14
- Rapns::Daemon::AppRunner.stub(:ready => ['my_app'])
15
- Rapns::Daemon::AppRunner.stub(:ready => ['my_app'])
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
- Rapns::Daemon::Feeder.enqueue_notifications
21
+ start
21
22
  end
22
23
 
23
24
  it 'loads notifications in batches' do
24
- relation = stub
25
- relation.should_receive(:find_each).with(:batch_size => 5000)
25
+ relation = stub.as_null_object
26
+ relation.should_receive(:limit).with(5000)
26
27
  Rapns::Notification.stub(:ready_for_delivery => relation)
27
- Rapns::Daemon::Feeder.enqueue_notifications
28
+ start
28
29
  end
29
30
 
30
- it "delivers the notification" do
31
+ it "enqueue the notification" do
31
32
  notification.update_attributes!(:delivered => false)
32
- Rapns::Daemon::AppRunner.should_receive(:deliver).with(notification)
33
- Rapns::Daemon::Feeder.enqueue_notifications
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.stub(:ready => [])
38
- Rapns::Daemon::AppRunner.should_not_receive(:deliver)
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(:deliver).with(notification)
45
- Rapns::Daemon::Feeder.enqueue_notifications
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(:deliver).with(notification)
51
- Rapns::Daemon::Feeder.enqueue_notifications
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(:deliver)
57
- Rapns::Daemon::Feeder.enqueue_notifications
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(:deliver)
63
- Rapns::Daemon::Feeder.enqueue_notifications
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(:deliver)
69
- Rapns::Daemon::Feeder.enqueue_notifications
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
- Rapns::Daemon::Feeder.enqueue_notifications
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
- Rapns::Daemon::Feeder.start(poll)
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(poll)
91
+ Rapns::Daemon::Feeder.should_receive(:interruptible_sleep).with(2)
92
92
  Rapns::Daemon::Feeder.stub(:loop).and_yield
93
- Rapns::Daemon::Feeder.start(poll)
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