rpush 4.2.0 → 7.0.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.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +307 -163
  3. data/README.md +105 -19
  4. data/lib/generators/templates/add_adm.rb +1 -1
  5. data/lib/generators/templates/add_alert_is_json_to_rapns_notifications.rb +2 -2
  6. data/lib/generators/templates/add_app_to_rapns.rb +2 -2
  7. data/lib/generators/templates/add_fail_after_to_rpush_notifications.rb +1 -1
  8. data/lib/generators/templates/add_gcm.rb +11 -25
  9. data/lib/generators/templates/add_rpush.rb +33 -83
  10. data/lib/generators/templates/add_wpns.rb +1 -1
  11. data/lib/generators/templates/create_rapns_apps.rb +1 -1
  12. data/lib/generators/templates/create_rapns_feedback.rb +3 -9
  13. data/lib/generators/templates/create_rapns_notifications.rb +3 -9
  14. data/lib/generators/templates/rename_rapns_to_rpush.rb +9 -33
  15. data/lib/generators/templates/rpush.rb +5 -4
  16. data/lib/generators/templates/rpush_2_0_0_updates.rb +10 -18
  17. data/lib/generators/templates/rpush_2_1_0_updates.rb +1 -1
  18. data/lib/generators/templates/rpush_2_6_0_updates.rb +1 -1
  19. data/lib/generators/templates/rpush_2_7_0_updates.rb +1 -1
  20. data/lib/generators/templates/rpush_3_0_0_updates.rb +1 -1
  21. data/lib/generators/templates/rpush_3_0_1_updates.rb +1 -1
  22. data/lib/generators/templates/rpush_3_1_0_add_pushy.rb +1 -1
  23. data/lib/generators/templates/rpush_3_1_1_updates.rb +1 -1
  24. data/lib/generators/templates/rpush_3_2_0_add_apns_p8.rb +1 -1
  25. data/lib/generators/templates/rpush_3_2_4_updates.rb +1 -1
  26. data/lib/generators/templates/rpush_3_3_0_updates.rb +1 -1
  27. data/lib/generators/templates/rpush_3_3_1_updates.rb +3 -3
  28. data/lib/generators/templates/rpush_4_1_0_updates.rb +1 -1
  29. data/lib/generators/templates/rpush_4_1_1_updates.rb +1 -1
  30. data/lib/generators/templates/rpush_4_2_0_updates.rb +1 -1
  31. data/lib/rpush/cli.rb +1 -1
  32. data/lib/rpush/client/active_model/adm/data_validator.rb +1 -1
  33. data/lib/rpush/client/active_model/apns/app.rb +1 -17
  34. data/lib/rpush/client/active_model/apns/device_token_format_validator.rb +2 -2
  35. data/lib/rpush/client/active_model/apns/notification.rb +13 -1
  36. data/lib/rpush/client/active_model/apns/notification_payload_size_validator.rb +15 -0
  37. data/lib/rpush/client/active_model/apns2/app.rb +7 -1
  38. data/lib/rpush/client/active_model/apns2/notification.rb +14 -0
  39. data/lib/rpush/client/active_model/certificate_private_key_validator.rb +19 -0
  40. data/lib/rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +1 -1
  41. data/lib/rpush/client/active_model/gcm/notification.rb +2 -2
  42. data/lib/rpush/client/active_model/payload_data_size_validator.rb +1 -1
  43. data/lib/rpush/client/active_model/registration_ids_count_validator.rb +1 -1
  44. data/lib/rpush/client/active_model/webpush/app.rb +41 -0
  45. data/lib/rpush/client/active_model/webpush/notification.rb +66 -0
  46. data/lib/rpush/client/active_model.rb +5 -1
  47. data/lib/rpush/client/active_record/apns/active_record_serializable_notification.rb +65 -0
  48. data/lib/rpush/client/active_record/apns/notification.rb +1 -57
  49. data/lib/rpush/client/active_record/apns2/notification.rb +4 -1
  50. data/lib/rpush/client/active_record/apnsp8/notification.rb +1 -0
  51. data/lib/rpush/client/active_record/webpush/app.rb +11 -0
  52. data/lib/rpush/client/active_record/webpush/notification.rb +12 -0
  53. data/lib/rpush/client/active_record.rb +4 -0
  54. data/lib/rpush/client/redis/apns2/notification.rb +1 -0
  55. data/lib/rpush/client/redis/apnsp8/notification.rb +2 -0
  56. data/lib/rpush/client/redis/pushy/notification.rb +0 -1
  57. data/lib/rpush/client/redis/webpush/app.rb +15 -0
  58. data/lib/rpush/client/redis/webpush/notification.rb +15 -0
  59. data/lib/rpush/client/redis.rb +3 -0
  60. data/lib/rpush/configuration.rb +3 -2
  61. data/lib/rpush/daemon/apns/feedback_receiver.rb +1 -1
  62. data/lib/rpush/daemon/apns2/delivery.rb +14 -2
  63. data/lib/rpush/daemon/apnsp8/delivery.rb +14 -3
  64. data/lib/rpush/daemon/app_runner.rb +1 -1
  65. data/lib/rpush/daemon/batch.rb +12 -5
  66. data/lib/rpush/daemon/delivery.rb +1 -2
  67. data/lib/rpush/daemon/store/active_record/reconnectable.rb +1 -1
  68. data/lib/rpush/daemon/store/active_record.rb +11 -7
  69. data/lib/rpush/daemon/store/redis.rb +6 -6
  70. data/lib/rpush/daemon/string_helpers.rb +1 -1
  71. data/lib/rpush/daemon/webpush/delivery.rb +114 -0
  72. data/lib/rpush/daemon/webpush.rb +10 -0
  73. data/lib/rpush/daemon.rb +4 -1
  74. data/lib/rpush/logger.rb +2 -1
  75. data/lib/rpush/version.rb +3 -3
  76. data/spec/functional/apns2_spec.rb +99 -2
  77. data/spec/functional/gcm_priority_spec.rb +40 -0
  78. data/spec/functional/retry_spec.rb +1 -1
  79. data/spec/functional/webpush_spec.rb +31 -0
  80. data/spec/spec_helper.rb +3 -1
  81. data/spec/support/active_record_setup.rb +4 -3
  82. data/spec/support/config/database.yml +4 -4
  83. data/spec/support/simplecov_helper.rb +2 -2
  84. data/spec/unit/client/active_record/adm/app_spec.rb +2 -54
  85. data/spec/unit/client/active_record/adm/notification_spec.rb +2 -39
  86. data/spec/unit/client/active_record/apns/app_spec.rb +3 -26
  87. data/spec/unit/client/active_record/apns/feedback_spec.rb +1 -5
  88. data/spec/unit/client/active_record/apns/notification_spec.rb +29 -293
  89. data/spec/unit/client/active_record/apns2/app_spec.rb +5 -0
  90. data/spec/unit/client/active_record/apns2/notification_spec.rb +65 -0
  91. data/spec/unit/client/active_record/apnsp8/notification_spec.rb +28 -0
  92. data/spec/unit/client/active_record/app_spec.rb +1 -26
  93. data/spec/unit/client/active_record/gcm/app_spec.rb +3 -1
  94. data/spec/unit/client/active_record/gcm/notification_spec.rb +6 -88
  95. data/spec/unit/client/active_record/notification_spec.rb +3 -11
  96. data/spec/unit/client/active_record/pushy/app_spec.rb +2 -13
  97. data/spec/unit/client/active_record/pushy/notification_spec.rb +2 -55
  98. data/spec/unit/client/active_record/shared/app.rb +14 -0
  99. data/spec/unit/{notification_shared.rb → client/active_record/shared/notification.rb} +12 -7
  100. data/spec/unit/client/active_record/webpush/app_spec.rb +6 -0
  101. data/spec/unit/client/active_record/webpush/notification_spec.rb +6 -0
  102. data/spec/unit/client/active_record/wns/badge_notification_spec.rb +1 -11
  103. data/spec/unit/client/active_record/wns/raw_notification_spec.rb +3 -12
  104. data/spec/unit/client/active_record/wpns/app_spec.rb +3 -1
  105. data/spec/unit/client/active_record/wpns/notification_spec.rb +2 -17
  106. data/spec/unit/client/redis/adm/app_spec.rb +5 -0
  107. data/spec/unit/client/redis/adm/notification_spec.rb +5 -0
  108. data/spec/unit/client/redis/apns/app_spec.rb +5 -0
  109. data/spec/unit/client/redis/apns/feedback_spec.rb +5 -0
  110. data/spec/unit/client/redis/apns/notification_spec.rb +50 -0
  111. data/spec/unit/client/redis/apns2/app_spec.rb +4 -0
  112. data/spec/unit/client/redis/apns2/notification_spec.rb +50 -0
  113. data/spec/unit/client/redis/apnsp8/notification_spec.rb +29 -0
  114. data/spec/unit/client/redis/app_spec.rb +5 -0
  115. data/spec/unit/client/redis/gcm/app_spec.rb +5 -0
  116. data/spec/unit/client/redis/gcm/notification_spec.rb +5 -0
  117. data/spec/unit/client/redis/notification_spec.rb +5 -0
  118. data/spec/unit/client/redis/pushy/app_spec.rb +5 -0
  119. data/spec/unit/client/redis/pushy/notification_spec.rb +5 -0
  120. data/spec/unit/client/redis/webpush/app_spec.rb +5 -0
  121. data/spec/unit/client/redis/webpush/notification_spec.rb +5 -0
  122. data/spec/unit/client/redis/wns/badge_notification_spec.rb +5 -0
  123. data/spec/unit/client/redis/wns/raw_notification_spec.rb +22 -0
  124. data/spec/unit/client/redis/wpns/app_spec.rb +5 -0
  125. data/spec/unit/client/redis/wpns/notification_spec.rb +5 -0
  126. data/spec/unit/client/shared/adm/app.rb +51 -0
  127. data/spec/unit/client/shared/adm/notification.rb +39 -0
  128. data/spec/unit/client/shared/apns/app.rb +29 -0
  129. data/spec/unit/client/shared/apns/feedback.rb +9 -0
  130. data/spec/unit/client/shared/apns/notification.rb +277 -0
  131. data/spec/unit/client/shared/app.rb +17 -0
  132. data/spec/unit/client/shared/gcm/app.rb +4 -0
  133. data/spec/unit/client/shared/gcm/notification.rb +77 -0
  134. data/spec/unit/client/shared/notification.rb +10 -0
  135. data/spec/unit/client/shared/pushy/app.rb +17 -0
  136. data/spec/unit/client/shared/pushy/notification.rb +55 -0
  137. data/spec/unit/client/shared/webpush/app.rb +33 -0
  138. data/spec/unit/client/shared/webpush/notification.rb +83 -0
  139. data/spec/unit/client/shared/wns/badge_notification.rb +15 -0
  140. data/spec/unit/client/shared/wns/raw_notification.rb +21 -0
  141. data/spec/unit/client/shared/wpns/app.rb +4 -0
  142. data/spec/unit/client/shared/wpns/notification.rb +18 -0
  143. data/spec/unit/daemon/apnsp8/delivery_spec.rb +53 -0
  144. data/spec/unit/daemon/batch_spec.rb +50 -2
  145. data/spec/unit/daemon/delivery_spec.rb +10 -0
  146. data/spec/unit/daemon/pushy/delivery_spec.rb +5 -3
  147. data/spec/unit/daemon/shared/store.rb +312 -0
  148. data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +7 -7
  149. data/spec/unit/daemon/store/active_record_spec.rb +6 -287
  150. data/spec/unit/daemon/store/redis_spec.rb +2 -291
  151. data/spec/unit/daemon/webpush/delivery_spec.rb +144 -0
  152. data/spec/unit_spec_helper.rb +3 -0
  153. metadata +145 -18
  154. data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +0 -16
@@ -0,0 +1,277 @@
1
+ # encoding: US-ASCII
2
+
3
+ require "unit_spec_helper"
4
+
5
+ shared_examples 'Rpush::Client::Apns::Notification' do
6
+ let(:notification) { described_class.new }
7
+ let(:app) { Rpush::Apns::App.create!(name: 'my_app', environment: 'development', certificate: TEST_CERT) }
8
+
9
+ it "should validate the format of the device_token" do
10
+ notification = described_class.new(device_token: "{$%^&*()}")
11
+ expect(notification.valid?).to be_falsey
12
+ expect(notification.errors[:device_token].include?("is invalid")).to be_truthy
13
+ end
14
+
15
+ it "should store long alerts" do
16
+ notification.app = app
17
+ notification.device_token = "a" * 108
18
+ notification.alert = "*" * 300
19
+ expect(notification.valid?).to be_truthy
20
+
21
+ notification.save!
22
+ notification.reload
23
+ expect(notification.alert).to eq("*" * 300)
24
+ end
25
+
26
+ it "should default the expiry to 1 day" do
27
+ expect(notification.expiry).to eq 1.day.to_i
28
+ end
29
+
30
+ describe "when assigning the device token" do
31
+ it "should strip spaces from the given string" do
32
+ notification = described_class.new(device_token: "o m g")
33
+ expect(notification.device_token).to eq "omg"
34
+ end
35
+
36
+ it "should strip chevrons from the given string" do
37
+ notification = described_class.new(device_token: "<omg>")
38
+ expect(notification.device_token).to eq "omg"
39
+ end
40
+ end
41
+
42
+ describe "as_json" do
43
+ it "should include the alert if present" do
44
+ notification = described_class.new(alert: "hi mom")
45
+ expect(notification.as_json["aps"]["alert"]).to eq "hi mom"
46
+ end
47
+
48
+ it "should not include the alert key if the alert is not present" do
49
+ notification = described_class.new(alert: nil)
50
+ expect(notification.as_json["aps"].key?("alert")).to be_falsey
51
+ end
52
+
53
+ it "should encode the alert as JSON if it is a Hash" do
54
+ notification = described_class.new(alert: { 'body' => "hi mom", 'alert-loc-key' => "View" })
55
+ expect(notification.as_json["aps"]["alert"]).to eq('body' => "hi mom", 'alert-loc-key' => "View")
56
+ end
57
+
58
+ it "should include the badge if present" do
59
+ notification = described_class.new(badge: 6)
60
+ expect(notification.as_json["aps"]["badge"]).to eq 6
61
+ end
62
+
63
+ it "should not include the badge key if the badge is not present" do
64
+ notification = described_class.new(badge: nil)
65
+ expect(notification.as_json["aps"].key?("badge")).to be_falsey
66
+ end
67
+
68
+ it "should include the sound if present" do
69
+ notification = described_class.new(sound: "my_sound.aiff")
70
+ expect(notification.as_json["aps"]["sound"]).to eq "my_sound.aiff"
71
+ end
72
+
73
+ it "should not include the sound key if the sound is not present" do
74
+ notification = described_class.new(sound: nil)
75
+ expect(notification.as_json["aps"].key?("sound")).to be_falsey
76
+ end
77
+
78
+ it "should encode the sound as JSON if it is a Hash" do
79
+ notification = described_class.new(sound: { 'name' => "my_sound.aiff", 'critical' => 1, 'volume' => 0.5 })
80
+ expect(notification.as_json["aps"]["sound"]).to eq('name' => "my_sound.aiff", 'critical' => 1, 'volume' => 0.5)
81
+ end
82
+
83
+ it "should include attributes for the device" do
84
+ notification = described_class.new
85
+ notification.data = { 'omg' => 'lol', 'wtf' => 'dunno' }
86
+ expect(notification.as_json["omg"]).to eq "lol"
87
+ expect(notification.as_json["wtf"]).to eq "dunno"
88
+ end
89
+
90
+ it "should allow attributes to include a hash" do
91
+ notification = described_class.new
92
+ notification.data = { 'omg' => { 'ilike' => 'hashes' } }
93
+ expect(notification.as_json["omg"]["ilike"]).to eq "hashes"
94
+ end
95
+ end
96
+
97
+ describe 'MDM' do
98
+ let(:magic) { 'abc123' }
99
+
100
+ before do
101
+ notification.device_token = "a" * 108
102
+ notification.id = 1234
103
+ end
104
+
105
+ it 'includes the mdm magic in the payload' do
106
+ notification.mdm = magic
107
+ expect(notification.as_json).to eq('mdm' => magic)
108
+ end
109
+
110
+ it 'does not include aps attribute' do
111
+ notification.alert = "i'm doomed"
112
+ notification.mdm = magic
113
+ expect(notification.as_json.key?('aps')).to be_falsey
114
+ end
115
+
116
+ it 'can be converted to binary' do
117
+ notification.mdm = magic
118
+ expect(notification.to_binary).to be_present
119
+ end
120
+ end
121
+
122
+ describe 'mutable-content' do
123
+ it 'includes mutable-content in the payload' do
124
+ notification.mutable_content = true
125
+ expect(notification.as_json['aps']['mutable-content']).to eq 1
126
+ end
127
+
128
+ it 'does not include content-available in the payload if not set' do
129
+ expect(notification.as_json['aps'].key?('mutable-content')).to be_falsey
130
+ end
131
+
132
+ it 'does not include mutable-content as a non-aps attribute' do
133
+ notification.mutable_content = true
134
+ expect(notification.as_json.key?('mutable-content')).to be_falsey
135
+ end
136
+
137
+ it 'does not overwrite existing attributes for the device' do
138
+ notification.data = { 'hi' => 'mom' }
139
+ notification.mutable_content = true
140
+ expect(notification.as_json['aps']['mutable-content']).to eq 1
141
+ expect(notification.as_json['hi']).to eq 'mom'
142
+ end
143
+ end
144
+
145
+ describe 'content-available' do
146
+ it 'includes content-available in the payload' do
147
+ notification.content_available = true
148
+ expect(notification.as_json['aps']['content-available']).to eq 1
149
+ end
150
+
151
+ it 'does not include content-available in the payload if not set' do
152
+ expect(notification.as_json['aps'].key?('content-available')).to be_falsey
153
+ end
154
+
155
+ it 'does not include content-available as a non-aps attribute' do
156
+ notification.content_available = true
157
+ expect(notification.as_json.key?('content-available')).to be_falsey
158
+ end
159
+
160
+ it 'does not overwrite existing attributes for the device' do
161
+ notification.data = { 'hi' => 'mom' }
162
+ notification.content_available = true
163
+ expect(notification.as_json['aps']['content-available']).to eq 1
164
+ expect(notification.as_json['hi']).to eq 'mom'
165
+ end
166
+ end
167
+
168
+ describe 'content_available?' do
169
+ context 'if not set' do
170
+ it 'should be false' do
171
+ expect(notification.content_available?).to be_falsey
172
+ end
173
+ end
174
+
175
+ context 'if set' do
176
+ it 'should be true' do
177
+ notification.content_available = true
178
+ expect(notification.content_available?).to be_truthy
179
+ end
180
+ end
181
+ end
182
+
183
+ describe 'url-args' do
184
+ it 'includes url-args in the payload' do
185
+ notification.url_args = ['url-arg-1']
186
+ expect(notification.as_json['aps']['url-args']).to eq ['url-arg-1']
187
+ end
188
+
189
+ it 'does not include url-args in the payload if not set' do
190
+ expect(notification.as_json['aps'].key?('url-args')).to be_falsey
191
+ end
192
+ end
193
+
194
+ describe 'category' do
195
+ it 'includes category in the payload' do
196
+ notification.category = 'INVITE_CATEGORY'
197
+ expect(notification.as_json['aps']['category']).to eq 'INVITE_CATEGORY'
198
+ end
199
+
200
+ it 'does not include category in the payload if not set' do
201
+ expect(notification.as_json['aps'].key?('category')).to be_falsey
202
+ end
203
+ end
204
+
205
+ describe 'to_binary' do
206
+ before do
207
+ notification.device_token = "a" * 108
208
+ notification.id = 1234
209
+ end
210
+
211
+ it 'uses APNS_PRIORITY_CONSERVE_POWER if content-available is the only key' do
212
+ notification.alert = nil
213
+ notification.badge = nil
214
+ notification.sound = nil
215
+ notification.content_available = true
216
+ bytes = notification.to_binary.bytes.to_a[-4..-1]
217
+ expect(bytes.first).to eq 5 # priority item ID
218
+ expect(bytes.last).to eq described_class::APNS_PRIORITY_CONSERVE_POWER
219
+ end
220
+
221
+ it 'uses APNS_PRIORITY_IMMEDIATE if content-available is not the only key' do
222
+ notification.alert = "New stuff!"
223
+ notification.badge = nil
224
+ notification.sound = nil
225
+ notification.content_available = true
226
+ bytes = notification.to_binary.bytes.to_a[-4..-1]
227
+ expect(bytes.first).to eq 5 # priority item ID
228
+ expect(bytes.last).to eq described_class::APNS_PRIORITY_IMMEDIATE
229
+ end
230
+
231
+ it "should correctly convert the notification to binary" do
232
+ notification.sound = "1.aiff"
233
+ notification.badge = 3
234
+ notification.alert = "Don't panic Mr Mainwaring, don't panic!"
235
+ notification.data = { hi: :mom }
236
+ notification.expiry = 86_400 # 1 day
237
+ notification.priority = described_class::APNS_PRIORITY_IMMEDIATE
238
+ notification.app = app
239
+ now = Time.now
240
+ allow(Time).to receive_messages(now: now)
241
+ expect(notification.to_binary).to eq "\x02\x00\x00\x00\xAF\x01\x00 \xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\x02\x00a{\"aps\":{\"alert\":\"Don't panic Mr Mainwaring, don't panic!\",\"badge\":3,\"sound\":\"1.aiff\"},\"hi\":\"mom\"}\x03\x00\x04\x00\x00\x04\xD2\x04\x00\x04#{[now.to_i + 86_400].pack('N')}\x05\x00\x01\n"
242
+ end
243
+ end
244
+
245
+ describe "bug #31" do
246
+ it 'does not confuse a JSON looking string as JSON' do
247
+ notification = described_class.new
248
+ notification.alert = "{\"one\":2}"
249
+ expect(notification.alert).to eq "{\"one\":2}"
250
+ end
251
+ end
252
+
253
+ describe "bug #35" do
254
+ it "should limit payload size to 256 bytes but not the entire packet" do
255
+ notification = described_class.new.tap do |n|
256
+ n.device_token = "a" * 108
257
+ n.alert = "a" * 210
258
+ n.app = app
259
+ end
260
+
261
+ expect(notification.to_binary(for_validation: true).bytesize).to be > 256
262
+ expect(notification.payload.bytesize).to be < 256
263
+ expect(notification).to be_valid
264
+ end
265
+ end
266
+
267
+ describe 'thread-id' do
268
+ it 'includes thread-id in the payload' do
269
+ notification.thread_id = 'THREAD-ID'
270
+ expect(notification.as_json['aps']['thread-id']).to eq 'THREAD-ID'
271
+ end
272
+
273
+ it 'does not include thread-id in the payload if not set' do
274
+ expect(notification.as_json['aps']).to_not have_key('thread-id')
275
+ end
276
+ end
277
+ end
@@ -0,0 +1,17 @@
1
+ require 'unit_spec_helper'
2
+
3
+ shared_examples 'Rpush::Client::App' do
4
+ context 'validating certificates' do
5
+ it 'rescues from certificate error' do
6
+ app = Rpush::Apns::App.new(name: 'test', environment: 'development', certificate: 'bad')
7
+ expect { app.valid? }.not_to raise_error
8
+ expect(app.valid?).to eq(false)
9
+ end
10
+
11
+ it 'raises other errors' do
12
+ app = Rpush::Apns::App.new(name: 'test', environment: 'development', certificate: 'bad')
13
+ allow(OpenSSL::X509::Certificate).to receive(:new).and_raise(NameError, 'simulating no openssl')
14
+ expect { app.valid? }.to raise_error(NameError)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,4 @@
1
+ require 'unit_spec_helper'
2
+
3
+ shared_examples 'Rpush::Client::Gcm::App' do
4
+ end
@@ -0,0 +1,77 @@
1
+ require 'unit_spec_helper'
2
+
3
+ shared_examples 'Rpush::Client::Gcm::Notification' do
4
+ let(:app) { Rpush::Gcm::App.create!(name: 'test', auth_key: 'abc') }
5
+ let(:notification) { described_class.new }
6
+
7
+ it "has a 'data' payload limit of 4096 bytes" do
8
+ notification.data = { key: "a" * 4096 }
9
+ expect(notification.valid?).to be_falsey
10
+ expect(notification.errors[:base]).to eq ["Notification payload data cannot be larger than 4096 bytes."]
11
+ end
12
+
13
+ it 'limits the number of registration ids to 1000' do
14
+ notification.registration_ids = ['a'] * (1000 + 1)
15
+ expect(notification.valid?).to be_falsey
16
+ expect(notification.errors[:base]).to eq ["Number of registration_ids cannot be larger than 1000."]
17
+ end
18
+
19
+ it 'validates expiry is present if collapse_key is set' do
20
+ notification.collapse_key = 'test'
21
+ notification.expiry = nil
22
+ expect(notification.valid?).to be_falsey
23
+ expect(notification.errors[:expiry]).to eq ['must be set when using a collapse_key']
24
+ end
25
+
26
+ it 'includes time_to_live in the payload' do
27
+ notification.expiry = 100
28
+ expect(notification.as_json['time_to_live']).to eq 100
29
+ end
30
+
31
+ it 'includes content_available in the payload' do
32
+ notification.content_available = true
33
+ expect(notification.as_json['content_available']).to eq true
34
+ end
35
+
36
+ it 'includes mutable_content in the payload' do
37
+ notification.mutable_content = true
38
+ expect(notification.as_json['mutable_content']).to eq true
39
+ end
40
+
41
+ it 'sets the priority to high when set to high' do
42
+ notification.priority = 'high'
43
+ expect(notification.as_json['priority']).to eq 'high'
44
+ end
45
+
46
+ it 'sets the priority to normal when set to normal' do
47
+ notification.priority = 'normal'
48
+ expect(notification.as_json['priority']).to eq 'normal'
49
+ end
50
+
51
+ it 'validates the priority is either "normal" or "high"' do
52
+ notification.priority = 'invalid'
53
+ expect(notification.errors[:priority]).to eq ['must be one of either "normal" or "high"']
54
+ end
55
+
56
+ it 'excludes the priority if it is not defined' do
57
+ expect(notification.as_json).not_to have_key 'priority'
58
+ end
59
+
60
+ it 'includes the notification payload if defined' do
61
+ notification.notification = { key: 'any key is allowed' }
62
+ expect(notification.as_json).to have_key 'notification'
63
+ end
64
+
65
+ it 'excludes the notification payload if undefined' do
66
+ expect(notification.as_json).not_to have_key 'notification'
67
+ end
68
+
69
+ it 'includes the dry_run payload if defined' do
70
+ notification.dry_run = true
71
+ expect(notification.as_json['dry_run']).to eq true
72
+ end
73
+
74
+ it 'excludes the dry_run payload if undefined' do
75
+ expect(notification.as_json).not_to have_key 'dry_run'
76
+ end
77
+ end
@@ -0,0 +1,10 @@
1
+ require 'unit_spec_helper'
2
+
3
+ shared_examples 'Rpush::Client::Notification' do
4
+ let(:notification) { described_class.new }
5
+
6
+ it 'allows assignment of many registration IDs' do
7
+ notification.registration_ids = %w[a b]
8
+ expect(notification.registration_ids).to eq %w[a b]
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+ require 'unit_spec_helper'
2
+
3
+ shared_examples 'Rpush::Client::Pushy::App' do
4
+ describe 'validates' do
5
+ subject { described_class.new }
6
+
7
+ it 'validates presence of name' do
8
+ is_expected.not_to be_valid
9
+ expect(subject.errors[:name]).to eq ["can't be blank"]
10
+ end
11
+
12
+ it 'validates presence of api_key' do
13
+ is_expected.not_to be_valid
14
+ expect(subject.errors[:api_key]).to eq ["can't be blank"]
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,55 @@
1
+ require 'unit_spec_helper'
2
+
3
+ shared_examples 'Rpush::Client::Pushy::Notification' do
4
+ subject(:notification) { described_class.new }
5
+
6
+ describe 'validates' do
7
+ let(:app) { Rpush::Pushy::App.create!(name: 'MyApp', api_key: 'my_api_key') }
8
+
9
+ describe 'data' do
10
+ subject { described_class.new(app: app, registration_ids: ['id']) }
11
+ it 'validates presence' do
12
+ is_expected.not_to be_valid
13
+ expect(subject.errors[:data]).to eq ["can't be blank"]
14
+ end
15
+
16
+ it "has a 'data' payload limit of 4096 bytes" do
17
+ subject.data = { message: 'a' * 4096 }
18
+ is_expected.not_to be_valid
19
+ expected_errors = ["Notification payload data cannot be larger than 4096 bytes."]
20
+ expect(subject.errors[:base]).to eq expected_errors
21
+ end
22
+ end
23
+
24
+ describe 'registration_ids' do
25
+ subject { described_class.new(app: app, data: { message: 'test' }) }
26
+ it 'validates presence' do
27
+ is_expected.not_to be_valid
28
+ expect(subject.errors[:registration_ids]).to eq ["can't be blank"]
29
+ end
30
+
31
+ it 'limits the number of registration ids to 1000' do
32
+ subject.registration_ids = ['a'] * (1000 + 1)
33
+ is_expected.not_to be_valid
34
+ expected_errors = ["Number of registration_ids cannot be larger than 1000."]
35
+ expect(subject.errors[:base]).to eq expected_errors
36
+ end
37
+ end
38
+
39
+ describe 'time_to_live' do
40
+ subject { described_class.new(app: app, data: { message: 'test' }, registration_ids: ['id']) }
41
+
42
+ it 'should be > 0' do
43
+ subject.time_to_live = -1
44
+ is_expected.not_to be_valid
45
+ expect(subject.errors[:time_to_live]).to eq ['must be greater than 0']
46
+ end
47
+
48
+ it 'should be <= 1.year.seconds' do
49
+ subject.time_to_live = 2.years.seconds.to_i
50
+ is_expected.not_to be_valid
51
+ expect(subject.errors[:time_to_live]).to eq ['The maximum value is 1 year']
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,33 @@
1
+ require 'unit_spec_helper'
2
+
3
+ shared_examples 'Rpush::Client::Webpush::App' do
4
+ describe 'validates' do
5
+ subject { described_class.new }
6
+
7
+ it 'validates presence of name' do
8
+ is_expected.not_to be_valid
9
+ expect(subject.errors[:name]).to eq ["can't be blank"]
10
+ end
11
+
12
+ it 'validates presence of vapid_keypair' do
13
+ is_expected.not_to be_valid
14
+ expect(subject.errors[:vapid_keypair]).to eq ["can't be blank"]
15
+ end
16
+
17
+ it 'should require the vapid keypair to have subject, public and private key' do
18
+ subject.vapid_keypair = {}.to_json
19
+ is_expected.not_to be_valid
20
+ expect(subject.errors[:vapid_keypair].sort).to eq [
21
+ 'must have a private_key entry',
22
+ 'must have a public_key entry',
23
+ 'must have a subject entry',
24
+ ]
25
+ end
26
+
27
+ it 'should require valid json for the keypair' do
28
+ subject.vapid_keypair = 'invalid'
29
+ is_expected.not_to be_valid
30
+ expect(subject.errors[:vapid_keypair].sort).to eq [ 'must be valid JSON' ]
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,83 @@
1
+ require 'unit_spec_helper'
2
+
3
+ shared_examples 'Rpush::Client::Webpush::Notification' do
4
+ subject(:notification) { described_class.new }
5
+
6
+ describe 'notification attributes' do
7
+ describe 'data' do
8
+ subject { described_class.new(data: { message: 'test', urgency: 'normal' } ) }
9
+ it 'has a message' do
10
+ expect(subject.message).to eq "test"
11
+ end
12
+ it 'has an urgency' do
13
+ expect(subject.urgency).to eq "normal"
14
+ end
15
+ end
16
+
17
+ describe 'subscription' do
18
+ let(:subscription){ { endpoint: 'https://push.example.org/foo', keys: {'foo' => 'bar'}} }
19
+ subject { described_class.new(registration_ids: [subscription]) }
20
+
21
+ it "has a subscription" do
22
+ expect(subject.subscription).to eq({ endpoint: 'https://push.example.org/foo', keys: {foo: 'bar'} })
23
+ end
24
+ end
25
+ end
26
+
27
+
28
+ describe 'validates' do
29
+ let(:app) { Rpush::Webpush::App.create!(name: 'MyApp', vapid_keypair: VAPID_KEYPAIR) }
30
+
31
+ describe 'data' do
32
+ subject { described_class.new(app: app, registration_ids: [{endpoint: 'https://push.example.org/foo', keys: {'foo' => 'bar'}}]) }
33
+ it 'validates presence' do
34
+ is_expected.not_to be_valid
35
+ expect(subject.errors[:data]).to eq ["can't be blank"]
36
+ end
37
+
38
+ it "has a 'data' payload limit of 4096 bytes" do
39
+ subject.data = { message: 'a' * 4096 }
40
+ is_expected.not_to be_valid
41
+ expected_errors = ["Notification payload data cannot be larger than 4096 bytes."]
42
+ expect(subject.errors[:base]).to eq expected_errors
43
+ end
44
+ end
45
+
46
+ describe 'registration_ids' do
47
+ subject { described_class.new(app: app, data: { message: 'test' }) }
48
+ it 'validates presence' do
49
+ is_expected.not_to be_valid
50
+ expect(subject.errors[:registration_ids]).to eq ["can't be blank"]
51
+ end
52
+
53
+ it 'limits the number of registration ids to exactly 1' do
54
+ subject.registration_ids = [{endpoint: 'string', keys: { 'a' => 'hash' }}] * 2
55
+ is_expected.not_to be_valid
56
+ expected_errors = ["Number of registration_ids cannot be larger than 1."]
57
+ expect(subject.errors[:base]).to eq expected_errors
58
+ end
59
+
60
+ it 'validates the structure of the registration' do
61
+ subject.registration_ids = ['a']
62
+ is_expected.not_to be_valid
63
+ expect(subject.errors[:base]).to eq [
64
+ "Registration must have :endpoint (String) and :keys (Hash) keys"
65
+ ]
66
+
67
+ subject.registration_ids = [{endpoint: 'string', keys: { 'a' => 'hash' }}]
68
+ is_expected.to be_valid
69
+ end
70
+ end
71
+
72
+ describe 'time_to_live' do
73
+ subject { described_class.new(app: app, data: { message: 'test' }, registration_ids: [{endpoint: 'https://push.example.org/foo', keys: {'foo' => 'bar'}}]) }
74
+
75
+ it 'should be > 0' do
76
+ subject.time_to_live = -1
77
+ is_expected.not_to be_valid
78
+ expect(subject.errors[:time_to_live]).to eq ['must be greater than 0']
79
+ end
80
+ end
81
+
82
+ end
83
+ end
@@ -0,0 +1,15 @@
1
+ require 'unit_spec_helper'
2
+
3
+ shared_examples 'Rpush::Client::Wns::BadgeNotification' do
4
+ let(:notification) do
5
+ notif = described_class.new
6
+ notif.app = Rpush::Wns::App.create!(name: "MyApp", client_id: "someclient", client_secret: "somesecret")
7
+ notif.uri = 'https://db5.notify.windows.com/?token=TOKEN'
8
+ notif.badge = 42
9
+ notif
10
+ end
11
+
12
+ it 'should allow a notification without data' do
13
+ expect(notification.valid?).to be(true)
14
+ end
15
+ end
@@ -0,0 +1,21 @@
1
+ require 'unit_spec_helper'
2
+
3
+ shared_examples 'Rpush::Client::Wns::RawNotification' do
4
+ let(:notification) do
5
+ notif = described_class.new
6
+ notif.app = Rpush::Wns::App.create!(name: "MyApp", client_id: "someclient", client_secret: "somesecret")
7
+ notif.uri = 'https://db5.notify.windows.com/?token=TOKEN'
8
+ notif.data = { foo: 'foo', bar: 'bar' }
9
+ notif
10
+ end
11
+
12
+ it 'allows exact payload of 5 KB' do
13
+ allow(notification).to receive(:payload_data_size) { 5120 }
14
+ expect(notification.valid?).to be(true)
15
+ end
16
+
17
+ it 'allows the size of payload under 5 KB' do
18
+ allow(notification).to receive(:payload_data_size) { 5119 }
19
+ expect(notification.valid?).to be(true)
20
+ end
21
+ end
@@ -0,0 +1,4 @@
1
+ require 'unit_spec_helper'
2
+
3
+ shared_examples 'Rpush::Client::Wpns::App' do
4
+ end
@@ -0,0 +1,18 @@
1
+ require 'unit_spec_helper'
2
+
3
+ shared_examples 'Rpush::Client::Wpns::Notification' do
4
+ let(:app) { Rpush::Wpns::App.create!(name: 'test', auth_key: 'abc') }
5
+ let(:notification) { described_class.new }
6
+
7
+ it "should have an url in the uri parameter" do
8
+ notification = described_class.new(uri: "somthing")
9
+ notification.valid?
10
+ expect(notification.errors[:uri]).to include('is invalid')
11
+ end
12
+
13
+ it "should be invalid if there's no data" do
14
+ notification = described_class.new(data: {})
15
+ notification.valid?
16
+ expect(notification.errors[:data]).to include("can't be blank")
17
+ end
18
+ end