rapns_rails_2 3.4.3

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 (113) hide show
  1. checksums.yaml +15 -0
  2. data/CHANGELOG.md +83 -0
  3. data/LICENSE +7 -0
  4. data/README.md +168 -0
  5. data/bin/rapns +37 -0
  6. data/config/database.yml +44 -0
  7. data/lib/generators/rapns_generator.rb +25 -0
  8. data/lib/generators/templates/add_alert_is_json_to_rapns_notifications.rb +9 -0
  9. data/lib/generators/templates/add_app_to_rapns.rb +11 -0
  10. data/lib/generators/templates/add_gcm.rb +95 -0
  11. data/lib/generators/templates/create_rapns_apps.rb +16 -0
  12. data/lib/generators/templates/create_rapns_feedback.rb +15 -0
  13. data/lib/generators/templates/create_rapns_notifications.rb +26 -0
  14. data/lib/generators/templates/rapns.rb +87 -0
  15. data/lib/rapns/TODO +3 -0
  16. data/lib/rapns/apns/app.rb +25 -0
  17. data/lib/rapns/apns/binary_notification_validator.rb +12 -0
  18. data/lib/rapns/apns/device_token_format_validator.rb +12 -0
  19. data/lib/rapns/apns/feedback.rb +16 -0
  20. data/lib/rapns/apns/notification.rb +91 -0
  21. data/lib/rapns/apns_feedback.rb +13 -0
  22. data/lib/rapns/app.rb +16 -0
  23. data/lib/rapns/configuration.rb +89 -0
  24. data/lib/rapns/daemon/apns/app_runner.rb +26 -0
  25. data/lib/rapns/daemon/apns/certificate_expired_error.rb +20 -0
  26. data/lib/rapns/daemon/apns/connection.rb +142 -0
  27. data/lib/rapns/daemon/apns/delivery.rb +64 -0
  28. data/lib/rapns/daemon/apns/delivery_handler.rb +35 -0
  29. data/lib/rapns/daemon/apns/disconnection_error.rb +20 -0
  30. data/lib/rapns/daemon/apns/feedback_receiver.rb +89 -0
  31. data/lib/rapns/daemon/app_runner.rb +179 -0
  32. data/lib/rapns/daemon/batch.rb +112 -0
  33. data/lib/rapns/daemon/delivery.rb +23 -0
  34. data/lib/rapns/daemon/delivery_error.rb +19 -0
  35. data/lib/rapns/daemon/delivery_handler.rb +52 -0
  36. data/lib/rapns/daemon/delivery_handler_collection.rb +33 -0
  37. data/lib/rapns/daemon/feeder.rb +65 -0
  38. data/lib/rapns/daemon/gcm/app_runner.rb +13 -0
  39. data/lib/rapns/daemon/gcm/delivery.rb +228 -0
  40. data/lib/rapns/daemon/gcm/delivery_handler.rb +20 -0
  41. data/lib/rapns/daemon/interruptible_sleep.rb +65 -0
  42. data/lib/rapns/daemon/reflectable.rb +13 -0
  43. data/lib/rapns/daemon/store/active_record/reconnectable.rb +66 -0
  44. data/lib/rapns/daemon/store/active_record.rb +128 -0
  45. data/lib/rapns/daemon.rb +129 -0
  46. data/lib/rapns/deprecatable.rb +23 -0
  47. data/lib/rapns/deprecation.rb +23 -0
  48. data/lib/rapns/embed.rb +28 -0
  49. data/lib/rapns/gcm/app.rb +7 -0
  50. data/lib/rapns/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +11 -0
  51. data/lib/rapns/gcm/notification.rb +37 -0
  52. data/lib/rapns/gcm/payload_data_size_validator.rb +13 -0
  53. data/lib/rapns/gcm/registration_ids_count_validator.rb +13 -0
  54. data/lib/rapns/logger.rb +76 -0
  55. data/lib/rapns/multi_json_helper.rb +16 -0
  56. data/lib/rapns/notification.rb +62 -0
  57. data/lib/rapns/notifier.rb +35 -0
  58. data/lib/rapns/push.rb +17 -0
  59. data/lib/rapns/rails-2-compatibility.rb +34 -0
  60. data/lib/rapns/reflection.rb +44 -0
  61. data/lib/rapns/upgraded.rb +31 -0
  62. data/lib/rapns/version.rb +3 -0
  63. data/lib/rapns_rails_2.rb +67 -0
  64. data/lib/tasks/cane.rake +18 -0
  65. data/lib/tasks/test.rake +38 -0
  66. data/spec/support/cert_with_password.pem +90 -0
  67. data/spec/support/cert_without_password.pem +59 -0
  68. data/spec/support/simplecov_helper.rb +13 -0
  69. data/spec/support/simplecov_quality_formatter.rb +8 -0
  70. data/spec/tmp/.gitkeep +0 -0
  71. data/spec/unit/apns/app_spec.rb +29 -0
  72. data/spec/unit/apns/feedback_spec.rb +9 -0
  73. data/spec/unit/apns/notification_spec.rb +215 -0
  74. data/spec/unit/apns_feedback_spec.rb +21 -0
  75. data/spec/unit/app_spec.rb +16 -0
  76. data/spec/unit/configuration_spec.rb +55 -0
  77. data/spec/unit/daemon/apns/app_runner_spec.rb +45 -0
  78. data/spec/unit/daemon/apns/certificate_expired_error_spec.rb +11 -0
  79. data/spec/unit/daemon/apns/connection_spec.rb +287 -0
  80. data/spec/unit/daemon/apns/delivery_handler_spec.rb +59 -0
  81. data/spec/unit/daemon/apns/delivery_spec.rb +101 -0
  82. data/spec/unit/daemon/apns/disconnection_error_spec.rb +18 -0
  83. data/spec/unit/daemon/apns/feedback_receiver_spec.rb +134 -0
  84. data/spec/unit/daemon/app_runner_shared.rb +83 -0
  85. data/spec/unit/daemon/app_runner_spec.rb +170 -0
  86. data/spec/unit/daemon/batch_spec.rb +219 -0
  87. data/spec/unit/daemon/delivery_error_spec.rb +13 -0
  88. data/spec/unit/daemon/delivery_handler_collection_spec.rb +37 -0
  89. data/spec/unit/daemon/delivery_handler_shared.rb +45 -0
  90. data/spec/unit/daemon/feeder_spec.rb +81 -0
  91. data/spec/unit/daemon/gcm/app_runner_spec.rb +19 -0
  92. data/spec/unit/daemon/gcm/delivery_handler_spec.rb +44 -0
  93. data/spec/unit/daemon/gcm/delivery_spec.rb +289 -0
  94. data/spec/unit/daemon/interruptible_sleep_spec.rb +68 -0
  95. data/spec/unit/daemon/reflectable_spec.rb +27 -0
  96. data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +114 -0
  97. data/spec/unit/daemon/store/active_record_spec.rb +281 -0
  98. data/spec/unit/daemon_spec.rb +157 -0
  99. data/spec/unit/deprecatable_spec.rb +32 -0
  100. data/spec/unit/deprecation_spec.rb +15 -0
  101. data/spec/unit/embed_spec.rb +50 -0
  102. data/spec/unit/gcm/app_spec.rb +4 -0
  103. data/spec/unit/gcm/notification_spec.rb +52 -0
  104. data/spec/unit/logger_spec.rb +180 -0
  105. data/spec/unit/notification_shared.rb +45 -0
  106. data/spec/unit/notification_spec.rb +4 -0
  107. data/spec/unit/notifier_spec.rb +32 -0
  108. data/spec/unit/push_spec.rb +44 -0
  109. data/spec/unit/rapns_spec.rb +9 -0
  110. data/spec/unit/reflection_spec.rb +30 -0
  111. data/spec/unit/upgraded_spec.rb +40 -0
  112. data/spec/unit_spec_helper.rb +137 -0
  113. metadata +232 -0
@@ -0,0 +1,170 @@
1
+ require File.expand_path("spec/unit_spec_helper")
2
+
3
+ describe Rapns::Daemon::AppRunner, 'stop' do
4
+ let(:runner) { double }
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, 'enqueue' do
15
+ let(:runner) { double(:enqueue => nil) }
16
+ let(:notification1) { double(:app_id => 1) }
17
+ let(:notification2) { double(:app_id => 2) }
18
+ let(:logger) { double(:error => nil) }
19
+
20
+ before do
21
+ Rapns.stub(:logger => logger)
22
+ Rapns::Daemon::AppRunner.runners[1] = runner
23
+ end
24
+
25
+ after { Rapns::Daemon::AppRunner.runners.clear }
26
+
27
+ it 'batches notifications by app' do
28
+ batch = double
29
+ batch.stub!(:describe)
30
+ Rapns::Daemon::Batch.stub(:new => batch)
31
+ Rapns::Daemon::Batch.should_receive(:new).with([notification1])
32
+ Rapns::Daemon::Batch.should_receive(:new).with([notification2])
33
+ Rapns::Daemon::AppRunner.enqueue([notification1, notification2])
34
+ end
35
+
36
+ it 'enqueues each batch' do
37
+ runner.should_receive(:enqueue).with(kind_of(Rapns::Daemon::Batch))
38
+ Rapns::Daemon::AppRunner.enqueue([notification1])
39
+ end
40
+
41
+ it 'logs an error if there is no runner to deliver the notification' do
42
+ notification1.stub(:app_id => 2, :id => 123)
43
+ notification2.stub(:app_id => 2, :id => 456)
44
+ logger.should_receive(:error).with("No such app '#{notification1.app_id}' for notifications 123, 456.")
45
+ Rapns::Daemon::AppRunner.enqueue([notification1, notification2])
46
+ end
47
+ end
48
+
49
+ describe Rapns::Daemon::AppRunner, 'sync' do
50
+ let(:app) { Rapns::Apns::App.new }
51
+ let(:new_app) { Rapns::Apns::App.new }
52
+ let(:runner) { double(:sync => nil, :stop => nil, :start => nil) }
53
+ let(:logger) { double(:error => nil, :warn => nil) }
54
+ let(:queue) { Queue.new }
55
+
56
+ before do
57
+ app.stub(:id => 1)
58
+ new_app.stub(:id => 2)
59
+ Queue.stub(:new => queue)
60
+ Rapns::Daemon::AppRunner.runners[app.id] = runner
61
+ Rapns::App.stub(:all => [app])
62
+ Rapns.stub(:logger => logger)
63
+ end
64
+
65
+ after { Rapns::Daemon::AppRunner.runners.clear }
66
+
67
+ it 'loads all apps' do
68
+ Rapns::App.should_receive(:all)
69
+ Rapns::Daemon::AppRunner.sync
70
+ end
71
+
72
+ it 'instructs existing runners to sync' do
73
+ runner.should_receive(:sync).with(app)
74
+ Rapns::Daemon::AppRunner.sync
75
+ end
76
+
77
+ it 'starts a runner for a new app' do
78
+ Rapns::App.stub(:all => [app, new_app])
79
+ new_runner = double
80
+ Rapns::Daemon::Apns::AppRunner.should_receive(:new).with(new_app).and_return(new_runner)
81
+ new_runner.should_receive(:start)
82
+ Rapns::Daemon::AppRunner.sync
83
+ end
84
+
85
+ it 'deletes old apps' do
86
+ Rapns::App.stub(:all => [])
87
+ runner.should_receive(:stop)
88
+ Rapns::Daemon::AppRunner.sync
89
+ end
90
+
91
+ it 'logs an error if the app could not be started' do
92
+ Rapns::App.stub(:all => [app, new_app])
93
+ new_runner = double
94
+ Rapns::Daemon::Apns::AppRunner.should_receive(:new).with(new_app).and_return(new_runner)
95
+ new_runner.stub(:start).and_raise(StandardError)
96
+ Rapns.logger.should_receive(:error)
97
+ Rapns::Daemon::AppRunner.sync
98
+ end
99
+
100
+ it 'reflects errors if the app could not be started' do
101
+ Rapns::App.stub(:all => [app, new_app])
102
+ new_runner = double
103
+ Rapns::Daemon::Apns::AppRunner.should_receive(:new).with(new_app).and_return(new_runner)
104
+ e = StandardError.new
105
+ new_runner.stub(:start).and_raise(e)
106
+ Rapns::Daemon::AppRunner.should_receive(:reflect).with(:error, e)
107
+ Rapns::Daemon::AppRunner.sync
108
+ end
109
+ end
110
+
111
+ describe Rapns::Daemon::AppRunner, 'debug' do
112
+ let!(:app) { Rapns::Apns::App.create!(:name => 'test', :connections => 1,
113
+ :environment => 'development', :certificate => TEST_CERT) }
114
+ let(:logger) { double(:info => nil) }
115
+
116
+ before do
117
+ Rapns::Daemon.stub(:config => {})
118
+ Rapns::Daemon::Apns::FeedbackReceiver.stub(:new => double.as_null_object)
119
+ Rapns::Daemon::Apns::Connection.stub(:new => double.as_null_object)
120
+ Rapns.stub(:logger => logger)
121
+ Rapns::Daemon::AppRunner.sync
122
+ end
123
+
124
+ after { Rapns::Daemon::AppRunner.runners.clear }
125
+
126
+ it 'prints debug app states to the log' do
127
+ Rapns.logger.should_receive(:info).with("\ntest:\n handlers: 1\n queued: 0\n batch size: 0\n batch processed: 0\n idle: true\n")
128
+ Rapns::Daemon::AppRunner.debug
129
+ end
130
+ end
131
+
132
+ describe Rapns::Daemon::AppRunner, 'idle' do
133
+ let!(:app) { Rapns::Apns::App.create!(:name => 'test', :connections => 1,
134
+ :environment => 'development', :certificate => TEST_CERT) }
135
+ let(:logger) { double(:info => nil) }
136
+
137
+ before do
138
+ Rapns.stub(:logger => logger)
139
+ Rapns::Daemon::Apns::FeedbackReceiver.stub(:new => double.as_null_object)
140
+ Rapns::Daemon::Apns::Connection.stub(:new => double.as_null_object)
141
+ Rapns::Daemon::AppRunner.sync
142
+ end
143
+
144
+ after { Rapns::Daemon::AppRunner.runners.clear }
145
+
146
+ it 'returns idle runners' do
147
+ runner = Rapns::Daemon::AppRunner.runners[app.id]
148
+ Rapns::Daemon::AppRunner.idle.should == [runner]
149
+ end
150
+ end
151
+
152
+ describe Rapns::Daemon::AppRunner, 'wait' do
153
+ let!(:app) { Rapns::Apns::App.create!(:name => 'test', :connections => 1,
154
+ :environment => 'development', :certificate => TEST_CERT) }
155
+ let(:logger) { double(:info => nil) }
156
+
157
+ before do
158
+ Rapns.stub(:logger => logger)
159
+ Rapns::Daemon::Apns::FeedbackReceiver.stub(:new => double.as_null_object)
160
+ Rapns::Daemon::Apns::Connection.stub(:new => double.as_null_object)
161
+ Rapns::Daemon::AppRunner.sync
162
+ end
163
+
164
+ after { Rapns::Daemon::AppRunner.runners.clear }
165
+
166
+ it 'waits until all runners are idle' do
167
+ Rapns::Daemon::AppRunner.runners.count.should == 1
168
+ Timeout.timeout(5) { Rapns::Daemon::AppRunner.wait }
169
+ end
170
+ end
@@ -0,0 +1,219 @@
1
+ require File.expand_path("spec/unit_spec_helper")
2
+
3
+ describe Rapns::Daemon::Batch do
4
+ let(:notification1) { double(:notification1, :id => 1) }
5
+ let(:notification2) { double(:notification2, :id => 2) }
6
+ let(:batch) { Rapns::Daemon::Batch.new([notification1, notification2]) }
7
+ let(:store) { double.as_null_object }
8
+
9
+ before do
10
+ Rapns::Daemon.stub(:store => store)
11
+ end
12
+
13
+ it 'exposes the notifications' do
14
+ batch.notifications.should == [notification1, notification2]
15
+ end
16
+
17
+ it 'exposes the number notifications' do
18
+ batch.num_notifications.should == 2
19
+ end
20
+
21
+ it 'exposes the number notifications processed' do
22
+ batch.num_processed.should == 0
23
+ end
24
+
25
+ it 'increments the processed notifications count' do
26
+ expect { batch.notification_processed }.to change(batch, :num_processed).to(1)
27
+ end
28
+
29
+ it 'completes the batch when all notifications have been processed' do
30
+ batch.should_receive(:complete)
31
+ 2.times { batch.notification_processed }
32
+ end
33
+
34
+ it 'can be described' do
35
+ batch.describe.should == '1, 2'
36
+ end
37
+
38
+ describe 'mark_delivered' do
39
+ describe 'batching is disabled' do
40
+ before { Rapns.config.batch_storage_updates = false }
41
+
42
+ it 'marks the notification as delivered immediately' do
43
+ store.should_receive(:mark_delivered).with(notification1)
44
+ batch.mark_delivered(notification1)
45
+ end
46
+
47
+ it 'reflects the notification was delivered' do
48
+ batch.should_receive(:reflect).with(:notification_delivered, notification1)
49
+ batch.mark_delivered(notification1)
50
+ end
51
+ end
52
+
53
+ describe 'batching is enabled' do
54
+ before { Rapns.config.batch_storage_updates = true }
55
+
56
+ it 'defers marking the notification as delivered until the batch is complete' do
57
+ batch.mark_delivered(notification1)
58
+ batch.delivered.should == [notification1]
59
+ end
60
+ end
61
+ end
62
+
63
+ describe 'mark_failed' do
64
+ describe 'batching is disabled' do
65
+ before { Rapns.config.batch_storage_updates = false }
66
+
67
+ it 'marks the notification as failed' do
68
+ store.should_receive(:mark_failed).with(notification1, 1, 'an error')
69
+ batch.mark_failed(notification1, 1, 'an error')
70
+ end
71
+
72
+ it 'reflects the notification failed' do
73
+ batch.should_receive(:reflect).with(:notification_delivered, notification1)
74
+ batch.mark_delivered(notification1)
75
+ end
76
+ end
77
+
78
+ describe 'batching is enabled' do
79
+ before { Rapns.config.batch_storage_updates = true }
80
+
81
+ it 'defers marking the notification as failed' do
82
+ Rapns.config.batch_storage_updates = true
83
+ batch.mark_failed(notification1, 1, 'an error')
84
+ batch.failed.should == {[1, 'an error'] => [notification1]}
85
+ end
86
+ end
87
+ end
88
+
89
+ describe 'mark_retryable' do
90
+ let(:time) { Time.now }
91
+
92
+ describe 'batching is disabled' do
93
+ before { Rapns.config.batch_storage_updates = false }
94
+
95
+ it 'marks the notification as retryable' do
96
+ store.should_receive(:mark_retryable).with(notification1, time)
97
+ batch.mark_retryable(notification1, time)
98
+ end
99
+
100
+ it 'reflects the notification will be retried' do
101
+ batch.should_receive(:reflect).with(:notification_will_retry, notification1)
102
+ batch.mark_retryable(notification1, time)
103
+ end
104
+ end
105
+
106
+ describe 'batching is enabled' do
107
+ before { Rapns.config.batch_storage_updates = true }
108
+
109
+ it 'defers marking the notification as retryable' do
110
+ batch.mark_retryable(notification1, time)
111
+ batch.retryable.should == {time => [notification1]}
112
+ end
113
+ end
114
+ end
115
+
116
+ describe 'complete' do
117
+ before do
118
+ Rapns.config.batch_storage_updates = true
119
+ Rapns.stub(:logger => double.as_null_object)
120
+ batch.stub(:reflect)
121
+ end
122
+
123
+ it 'clears the notifications' do
124
+ expect do
125
+ 2.times { batch.notification_processed }
126
+ end.to change(batch.notifications, :length).to(0)
127
+ end
128
+
129
+ it 'identifies as complete' do
130
+ expect do
131
+ 2.times { batch.notification_processed }
132
+ end.to change(batch, :complete?).to(true)
133
+ end
134
+
135
+ it 'reflects errors raised during completion' do
136
+ e = StandardError.new
137
+ batch.stub(:complete_delivered).and_raise(e)
138
+ batch.should_receive(:reflect).with(:error, e)
139
+ 2.times { batch.notification_processed }
140
+ end
141
+
142
+ describe 'delivered' do
143
+ def complete
144
+ [notification1, notification2].each do |n|
145
+ batch.mark_delivered(n)
146
+ batch.notification_processed
147
+ end
148
+ end
149
+
150
+ it 'marks the batch as delivered' do
151
+ store.should_receive(:mark_batch_delivered).with([notification1, notification2])
152
+ complete
153
+ end
154
+
155
+ it 'reflects the notifications were delivered' do
156
+ batch.should_receive(:reflect).with(:notification_delivered, notification1)
157
+ batch.should_receive(:reflect).with(:notification_delivered, notification2)
158
+ complete
159
+ end
160
+
161
+ it 'clears the delivered notifications' do
162
+ complete
163
+ batch.delivered.should == []
164
+ end
165
+ end
166
+
167
+ describe 'failed' do
168
+ def complete
169
+ [notification1, notification2].each do |n|
170
+ batch.mark_failed(n, 1, 'an error')
171
+ batch.notification_processed
172
+ end
173
+ end
174
+
175
+ it 'marks the batch as failed' do
176
+ store.should_receive(:mark_batch_failed).with([notification1, notification2], 1, 'an error')
177
+ complete
178
+ end
179
+
180
+ it 'reflects the notifications failed' do
181
+ batch.should_receive(:reflect).with(:notification_failed, notification1)
182
+ batch.should_receive(:reflect).with(:notification_failed, notification2)
183
+ complete
184
+ end
185
+
186
+ it 'clears the failed notifications' do
187
+ complete
188
+ batch.failed.should == {}
189
+ end
190
+ end
191
+
192
+ describe 'retryable' do
193
+ let(:time) { Time.now }
194
+
195
+ def complete
196
+ [notification1, notification2].each do |n|
197
+ batch.mark_retryable(n, time)
198
+ batch.notification_processed
199
+ end
200
+ end
201
+
202
+ it 'marks the batch as retryable' do
203
+ store.should_receive(:mark_batch_retryable).with([notification1, notification2], time)
204
+ complete
205
+ end
206
+
207
+ it 'reflects the notifications will be retried' do
208
+ batch.should_receive(:reflect).with(:notification_will_retry, notification1)
209
+ batch.should_receive(:reflect).with(:notification_will_retry, notification2)
210
+ complete
211
+ end
212
+
213
+ it 'clears the retryable notifications' do
214
+ complete
215
+ batch.retryable.should == {}
216
+ end
217
+ end
218
+ end
219
+ end
@@ -0,0 +1,13 @@
1
+ require File.expand_path("spec/unit_spec_helper")
2
+
3
+ describe Rapns::DeliveryError do
4
+ let(:error) { Rapns::DeliveryError.new(4, 12, "Missing payload") }
5
+
6
+ it "returns an informative message" do
7
+ error.to_s.should == "Unable to deliver notification 12, received error 4 (Missing payload)"
8
+ end
9
+
10
+ it "returns the error code" do
11
+ error.code.should == 4
12
+ end
13
+ end
@@ -0,0 +1,37 @@
1
+ require File.expand_path("spec/unit_spec_helper")
2
+
3
+ describe Rapns::Daemon::DeliveryHandlerCollection do
4
+ let(:handler) { double.as_null_object }
5
+ let(:collection) { Rapns::Daemon::DeliveryHandlerCollection.new }
6
+
7
+ it 'returns the size of the collection' do
8
+ collection.push(handler)
9
+ collection.size.should == 1
10
+ end
11
+
12
+ it 'pops a handler from the collection' do
13
+ collection.push(handler)
14
+ handler.should_receive(:stop)
15
+ handler.should_receive(:wakeup)
16
+ handler.should_receive(:wait)
17
+ collection.pop
18
+ collection.size.should == 0
19
+ end
20
+
21
+ it 'wakes up all handlers when popping a single handler' do
22
+ collection.push(handler)
23
+ handler2 = double.as_null_object
24
+ collection.push(handler2)
25
+ handler.should_receive(:wakeup)
26
+ handler2.should_receive(:wakeup)
27
+ collection.pop
28
+ end
29
+
30
+ it 'stops all handlers' do
31
+ collection.push(handler)
32
+ handler.should_receive(:stop)
33
+ handler.should_receive(:wakeup)
34
+ handler.should_receive(:wait)
35
+ collection.stop
36
+ end
37
+ end
@@ -0,0 +1,45 @@
1
+ shared_examples_for 'an DeliveryHandler subclass' do
2
+ def run_delivery_handler
3
+ delivery_handler.start
4
+ delivery_handler.stop
5
+ delivery_handler.wakeup
6
+ delivery_handler.wait
7
+ end
8
+
9
+ it 'logs all delivery errors' do
10
+ logger = double
11
+ Rapns.stub(:logger => logger)
12
+ error = StandardError.new
13
+ delivery_handler.stub(:deliver).and_raise(error)
14
+ Rapns.logger.should_receive(:error).with(error)
15
+ run_delivery_handler
16
+ end
17
+
18
+ it 'reflects an exception' do
19
+ Rapns.stub(:logger => double(:error => nil))
20
+ error = StandardError.new
21
+ delivery_handler.stub(:deliver).and_raise(error)
22
+ delivery_handler.should_receive(:reflect).with(:error, error)
23
+ run_delivery_handler
24
+ end
25
+
26
+ it 'instructs the batch that the notification has been processed' do
27
+ batch.should_receive(:notification_processed)
28
+ run_delivery_handler
29
+ end
30
+
31
+ it "instructs the queue to wakeup the thread when told to stop" do
32
+ queue.should_receive(:push).with(Rapns::Daemon::DeliveryHandler::WAKEUP) { |*a| queue.proxied_by_rspec__push(*a) }
33
+ run_delivery_handler
34
+ end
35
+
36
+ describe "when being stopped" do
37
+ before { queue.pop }
38
+
39
+ it "does not attempt to deliver a notification when a WAKEUP is dequeued" do
40
+ queue.stub(:pop).and_return(Rapns::Daemon::DeliveryHandler::WAKEUP)
41
+ delivery_handler.should_not_receive(:deliver)
42
+ delivery_handler.send(:handle_next_notification)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,81 @@
1
+ require File.expand_path("spec/unit_spec_helper")
2
+
3
+ describe Rapns::Daemon::Feeder do
4
+ let(:config) { double(:batch_size => 5000,
5
+ :push_poll => 0,
6
+ :embedded => false,
7
+ :push => false,
8
+ :udp_wake_host => nil,
9
+ :udp_wake_port => nil) }
10
+ let!(:app) { Rapns::Apns::App.create!(:name => 'my_app', :environment => 'development', :certificate => TEST_CERT) }
11
+ let(:notification) { Rapns::Apns::Notification.create!(:device_token => "a" * 64, :app => app) }
12
+ let(:logger) { double }
13
+
14
+ before do
15
+ Rapns.stub(:config => config,:logger => logger)
16
+ Rapns::Daemon.stub(:store => double(:deliverable_notifications => [notification]))
17
+ Rapns::Daemon::Feeder.stub(:stop? => true)
18
+ Rapns::Daemon::AppRunner.stub(:enqueue => nil, :idle => [double(:app => app)])
19
+ end
20
+
21
+ def start
22
+ Rapns::Daemon::Feeder.start
23
+ end
24
+
25
+ it "starts the loop in a new thread if embedded" do
26
+ config.stub(:embedded => true)
27
+ Thread.should_receive(:new).and_yield
28
+ Rapns::Daemon::Feeder.should_receive(:feed_forever)
29
+ start
30
+ end
31
+
32
+ it 'loads deliverable notifications' do
33
+ Rapns::Daemon.store.should_receive(:deliverable_notifications).with([app])
34
+ start
35
+ end
36
+
37
+ it 'does not attempt to load deliverable notifications if there are no idle runners' do
38
+ Rapns::Daemon::AppRunner.stub(:idle => [])
39
+ Rapns::Daemon.store.should_not_receive(:deliverable_notifications)
40
+ start
41
+ end
42
+
43
+ it 'enqueues notifications without looping if in push mode' do
44
+ config.stub(:push => true)
45
+ Rapns::Daemon::Feeder.should_not_receive(:feed_forever)
46
+ Rapns::Daemon::Feeder.should_receive(:enqueue_notifications)
47
+ start
48
+ end
49
+
50
+ it "enqueues the notifications" do
51
+ Rapns::Daemon::AppRunner.should_receive(:enqueue).with([notification])
52
+ start
53
+ end
54
+
55
+ it "logs errors" do
56
+ e = StandardError.new("bork")
57
+ Rapns::Daemon.store.stub(:deliverable_notifications).and_raise(e)
58
+ Rapns.logger.should_receive(:error).with(e)
59
+ start
60
+ end
61
+
62
+ it "interrupts sleep when stopped" do
63
+ Rapns::Daemon::Feeder.should_receive(:interrupt_sleep)
64
+ Rapns::Daemon::Feeder.stop
65
+ end
66
+
67
+ it "enqueues notifications when started" do
68
+ Rapns::Daemon::Feeder.should_receive(:enqueue_notifications).at_least(:once)
69
+ Rapns::Daemon::Feeder.stub(:loop).and_yield
70
+ start
71
+ end
72
+
73
+ it "sleeps for the given period" do
74
+ config.stub(:push_poll => 2)
75
+ sleeper = double(:sleep => true)
76
+ sleeper.should_receive(:sleep).with(2)
77
+ Rapns::Daemon::Feeder.stub(:interruptible_sleeper => sleeper)
78
+ Rapns::Daemon::Feeder.stub(:loop).and_yield
79
+ Rapns::Daemon::Feeder.start
80
+ end
81
+ end
@@ -0,0 +1,19 @@
1
+ require File.expand_path("spec/unit_spec_helper")
2
+ require File.dirname(__FILE__) + '/../app_runner_shared.rb'
3
+
4
+ describe Rapns::Daemon::Gcm::AppRunner do
5
+ it_should_behave_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) { double(:start => nil, :queue= => nil, :wakeup => nil, :wait => nil) }
11
+ let(:handler_collection) { double(:handler_collection, :push => nil, :size => 1, :stop => nil) }
12
+ let(:logger) { double(:info => nil) }
13
+
14
+ before do
15
+ Rapns.stub(:logger => logger)
16
+ Rapns::Daemon::Gcm::DeliveryHandler.stub(:new => handler)
17
+ Rapns::Daemon::DeliveryHandlerCollection.stub(:new => handler_collection)
18
+ end
19
+ end
@@ -0,0 +1,44 @@
1
+ require File.expand_path("spec/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(:notification) { double }
8
+ let(:batch) { double(:notification_processed => nil) }
9
+ let(:queue) { Queue.new }
10
+ let(:app) { double }
11
+ let(:delivery_handler) { Rapns::Daemon::Gcm::DeliveryHandler.new(app) }
12
+ let(:http) { double(:shutdown => nil) }
13
+ let(:delivery) { double(:perform => nil) }
14
+
15
+ before do
16
+ Net::HTTP::Persistent.stub(:new => http)
17
+ Rapns::Daemon::Gcm::Delivery.stub(:new => delivery)
18
+ delivery_handler.queue = queue
19
+ queue.push([notification, batch])
20
+ end
21
+
22
+ def run_delivery_handler
23
+ delivery_handler.start
24
+ delivery_handler.stop
25
+ delivery_handler.wakeup
26
+ delivery_handler.wait
27
+ end
28
+
29
+ it 'performs delivery of an notification' do
30
+ Rapns::Daemon::Gcm::Delivery.should_receive(:new).with(app, http, notification, batch).and_return(delivery)
31
+ delivery.should_receive(:perform)
32
+ run_delivery_handler
33
+ end
34
+
35
+ it 'initiates a persistent connection object' do
36
+ Net::HTTP::Persistent.should_receive(:new).with('rapns')
37
+ Rapns::Daemon::Gcm::DeliveryHandler.new(app)
38
+ end
39
+
40
+ it 'shuts down the http connection stopped' do
41
+ http.should_receive(:shutdown)
42
+ run_delivery_handler
43
+ end
44
+ end