rpush 4.2.0 → 5.4.0

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 (121) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +248 -163
  3. data/README.md +103 -17
  4. data/lib/generators/templates/add_gcm.rb +4 -4
  5. data/lib/generators/templates/add_rpush.rb +4 -4
  6. data/lib/generators/templates/rpush.rb +4 -0
  7. data/lib/generators/templates/rpush_3_3_1_updates.rb +2 -2
  8. data/lib/rpush/cli.rb +1 -1
  9. data/lib/rpush/client/active_model.rb +4 -1
  10. data/lib/rpush/client/active_model/adm/data_validator.rb +1 -1
  11. data/lib/rpush/client/active_model/apns/device_token_format_validator.rb +2 -2
  12. data/lib/rpush/client/active_model/apns/notification.rb +9 -1
  13. data/lib/rpush/client/active_model/apns/notification_payload_size_validator.rb +15 -0
  14. data/lib/rpush/client/active_model/apns2/notification.rb +14 -0
  15. data/lib/rpush/client/active_model/gcm/expiry_collapse_key_mutual_inclusion_validator.rb +1 -1
  16. data/lib/rpush/client/active_model/gcm/notification.rb +2 -2
  17. data/lib/rpush/client/active_model/payload_data_size_validator.rb +1 -1
  18. data/lib/rpush/client/active_model/registration_ids_count_validator.rb +1 -1
  19. data/lib/rpush/client/active_model/webpush/app.rb +41 -0
  20. data/lib/rpush/client/active_model/webpush/notification.rb +66 -0
  21. data/lib/rpush/client/active_record.rb +4 -0
  22. data/lib/rpush/client/active_record/apns/active_record_serializable_notification.rb +65 -0
  23. data/lib/rpush/client/active_record/apns/notification.rb +1 -57
  24. data/lib/rpush/client/active_record/apns2/notification.rb +4 -1
  25. data/lib/rpush/client/active_record/apnsp8/notification.rb +1 -0
  26. data/lib/rpush/client/active_record/webpush/app.rb +11 -0
  27. data/lib/rpush/client/active_record/webpush/notification.rb +12 -0
  28. data/lib/rpush/client/redis.rb +3 -0
  29. data/lib/rpush/client/redis/apns2/notification.rb +1 -0
  30. data/lib/rpush/client/redis/apnsp8/notification.rb +2 -0
  31. data/lib/rpush/client/redis/pushy/notification.rb +0 -1
  32. data/lib/rpush/client/redis/webpush/app.rb +15 -0
  33. data/lib/rpush/client/redis/webpush/notification.rb +15 -0
  34. data/lib/rpush/configuration.rb +3 -2
  35. data/lib/rpush/daemon.rb +4 -1
  36. data/lib/rpush/daemon/apns/feedback_receiver.rb +1 -1
  37. data/lib/rpush/daemon/apns2/delivery.rb +13 -2
  38. data/lib/rpush/daemon/apnsp8/delivery.rb +7 -2
  39. data/lib/rpush/daemon/app_runner.rb +1 -1
  40. data/lib/rpush/daemon/batch.rb +12 -5
  41. data/lib/rpush/daemon/delivery.rb +1 -2
  42. data/lib/rpush/daemon/store/active_record/reconnectable.rb +1 -1
  43. data/lib/rpush/daemon/webpush.rb +10 -0
  44. data/lib/rpush/daemon/webpush/delivery.rb +114 -0
  45. data/lib/rpush/logger.rb +1 -0
  46. data/lib/rpush/version.rb +2 -2
  47. data/spec/functional/apns2_spec.rb +97 -2
  48. data/spec/functional/gcm_priority_spec.rb +40 -0
  49. data/spec/functional/webpush_spec.rb +30 -0
  50. data/spec/spec_helper.rb +2 -0
  51. data/spec/support/simplecov_helper.rb +1 -1
  52. data/spec/unit/client/active_record/adm/app_spec.rb +2 -54
  53. data/spec/unit/client/active_record/adm/notification_spec.rb +2 -39
  54. data/spec/unit/client/active_record/apns/app_spec.rb +3 -26
  55. data/spec/unit/client/active_record/apns/feedback_spec.rb +1 -5
  56. data/spec/unit/client/active_record/apns/notification_spec.rb +29 -293
  57. data/spec/unit/client/active_record/apns2/app_spec.rb +4 -0
  58. data/spec/unit/client/active_record/apns2/notification_spec.rb +65 -0
  59. data/spec/unit/client/active_record/apnsp8/notification_spec.rb +28 -0
  60. data/spec/unit/client/active_record/app_spec.rb +1 -26
  61. data/spec/unit/client/active_record/gcm/app_spec.rb +3 -1
  62. data/spec/unit/client/active_record/gcm/notification_spec.rb +6 -88
  63. data/spec/unit/client/active_record/notification_spec.rb +3 -11
  64. data/spec/unit/client/active_record/pushy/app_spec.rb +2 -13
  65. data/spec/unit/client/active_record/pushy/notification_spec.rb +2 -55
  66. data/spec/unit/client/active_record/shared/app.rb +14 -0
  67. data/spec/unit/{notification_shared.rb → client/active_record/shared/notification.rb} +12 -7
  68. data/spec/unit/client/active_record/webpush/app_spec.rb +6 -0
  69. data/spec/unit/client/active_record/webpush/notification_spec.rb +6 -0
  70. data/spec/unit/client/active_record/wns/badge_notification_spec.rb +1 -11
  71. data/spec/unit/client/active_record/wns/raw_notification_spec.rb +3 -12
  72. data/spec/unit/client/active_record/wpns/app_spec.rb +3 -1
  73. data/spec/unit/client/active_record/wpns/notification_spec.rb +2 -17
  74. data/spec/unit/client/redis/adm/app_spec.rb +5 -0
  75. data/spec/unit/client/redis/adm/notification_spec.rb +5 -0
  76. data/spec/unit/client/redis/apns/app_spec.rb +5 -0
  77. data/spec/unit/client/redis/apns/feedback_spec.rb +5 -0
  78. data/spec/unit/client/redis/apns/notification_spec.rb +50 -0
  79. data/spec/unit/client/redis/apns2/app_spec.rb +4 -0
  80. data/spec/unit/client/redis/apns2/notification_spec.rb +50 -0
  81. data/spec/unit/client/redis/apnsp8/notification_spec.rb +29 -0
  82. data/spec/unit/client/redis/app_spec.rb +5 -0
  83. data/spec/unit/client/redis/gcm/app_spec.rb +5 -0
  84. data/spec/unit/client/redis/gcm/notification_spec.rb +5 -0
  85. data/spec/unit/client/redis/notification_spec.rb +5 -0
  86. data/spec/unit/client/redis/pushy/app_spec.rb +5 -0
  87. data/spec/unit/client/redis/pushy/notification_spec.rb +5 -0
  88. data/spec/unit/client/redis/webpush/app_spec.rb +5 -0
  89. data/spec/unit/client/redis/webpush/notification_spec.rb +5 -0
  90. data/spec/unit/client/redis/wns/badge_notification_spec.rb +5 -0
  91. data/spec/unit/client/redis/wns/raw_notification_spec.rb +22 -0
  92. data/spec/unit/client/redis/wpns/app_spec.rb +5 -0
  93. data/spec/unit/client/redis/wpns/notification_spec.rb +5 -0
  94. data/spec/unit/client/shared/adm/app.rb +51 -0
  95. data/spec/unit/client/shared/adm/notification.rb +39 -0
  96. data/spec/unit/client/shared/apns/app.rb +29 -0
  97. data/spec/unit/client/shared/apns/feedback.rb +9 -0
  98. data/spec/unit/client/shared/apns/notification.rb +262 -0
  99. data/spec/unit/client/shared/app.rb +17 -0
  100. data/spec/unit/client/shared/gcm/app.rb +4 -0
  101. data/spec/unit/client/shared/gcm/notification.rb +77 -0
  102. data/spec/unit/client/shared/notification.rb +10 -0
  103. data/spec/unit/client/shared/pushy/app.rb +17 -0
  104. data/spec/unit/client/shared/pushy/notification.rb +55 -0
  105. data/spec/unit/client/shared/webpush/app.rb +33 -0
  106. data/spec/unit/client/shared/webpush/notification.rb +83 -0
  107. data/spec/unit/client/shared/wns/badge_notification.rb +15 -0
  108. data/spec/unit/client/shared/wns/raw_notification.rb +21 -0
  109. data/spec/unit/client/shared/wpns/app.rb +4 -0
  110. data/spec/unit/client/shared/wpns/notification.rb +18 -0
  111. data/spec/unit/daemon/batch_spec.rb +50 -2
  112. data/spec/unit/daemon/delivery_spec.rb +10 -0
  113. data/spec/unit/daemon/pushy/delivery_spec.rb +5 -3
  114. data/spec/unit/daemon/shared/store.rb +312 -0
  115. data/spec/unit/daemon/store/active_record/reconnectable_spec.rb +7 -7
  116. data/spec/unit/daemon/store/active_record_spec.rb +2 -290
  117. data/spec/unit/daemon/store/redis_spec.rb +2 -291
  118. data/spec/unit/daemon/webpush/delivery_spec.rb +144 -0
  119. data/spec/unit_spec_helper.rb +3 -0
  120. metadata +135 -12
  121. data/lib/rpush/client/active_model/apns/binary_notification_validator.rb +0 -16
@@ -0,0 +1,9 @@
1
+ require 'unit_spec_helper'
2
+
3
+ shared_examples 'Rpush::Client::Apns::Feedback' do
4
+ it 'validates the format of the device_token' do
5
+ notification = described_class.new(device_token: "{$%^&*()}")
6
+ expect(notification.valid?).to be_falsey
7
+ expect(notification.errors[:device_token]).to include('is invalid')
8
+ end
9
+ end
@@ -0,0 +1,262 @@
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 'url-args' do
169
+ it 'includes url-args in the payload' do
170
+ notification.url_args = ['url-arg-1']
171
+ expect(notification.as_json['aps']['url-args']).to eq ['url-arg-1']
172
+ end
173
+
174
+ it 'does not include url-args in the payload if not set' do
175
+ expect(notification.as_json['aps'].key?('url-args')).to be_falsey
176
+ end
177
+ end
178
+
179
+ describe 'category' do
180
+ it 'includes category in the payload' do
181
+ notification.category = 'INVITE_CATEGORY'
182
+ expect(notification.as_json['aps']['category']).to eq 'INVITE_CATEGORY'
183
+ end
184
+
185
+ it 'does not include category in the payload if not set' do
186
+ expect(notification.as_json['aps'].key?('category')).to be_falsey
187
+ end
188
+ end
189
+
190
+ describe 'to_binary' do
191
+ before do
192
+ notification.device_token = "a" * 108
193
+ notification.id = 1234
194
+ end
195
+
196
+ it 'uses APNS_PRIORITY_CONSERVE_POWER if content-available is the only key' do
197
+ notification.alert = nil
198
+ notification.badge = nil
199
+ notification.sound = nil
200
+ notification.content_available = true
201
+ bytes = notification.to_binary.bytes.to_a[-4..-1]
202
+ expect(bytes.first).to eq 5 # priority item ID
203
+ expect(bytes.last).to eq described_class::APNS_PRIORITY_CONSERVE_POWER
204
+ end
205
+
206
+ it 'uses APNS_PRIORITY_IMMEDIATE if content-available is not the only key' do
207
+ notification.alert = "New stuff!"
208
+ notification.badge = nil
209
+ notification.sound = nil
210
+ notification.content_available = true
211
+ bytes = notification.to_binary.bytes.to_a[-4..-1]
212
+ expect(bytes.first).to eq 5 # priority item ID
213
+ expect(bytes.last).to eq described_class::APNS_PRIORITY_IMMEDIATE
214
+ end
215
+
216
+ it "should correctly convert the notification to binary" do
217
+ notification.sound = "1.aiff"
218
+ notification.badge = 3
219
+ notification.alert = "Don't panic Mr Mainwaring, don't panic!"
220
+ notification.data = { hi: :mom }
221
+ notification.expiry = 86_400 # 1 day
222
+ notification.priority = described_class::APNS_PRIORITY_IMMEDIATE
223
+ notification.app = app
224
+ now = Time.now
225
+ allow(Time).to receive_messages(now: now)
226
+ 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"
227
+ end
228
+ end
229
+
230
+ describe "bug #31" do
231
+ it 'does not confuse a JSON looking string as JSON' do
232
+ notification = described_class.new
233
+ notification.alert = "{\"one\":2}"
234
+ expect(notification.alert).to eq "{\"one\":2}"
235
+ end
236
+ end
237
+
238
+ describe "bug #35" do
239
+ it "should limit payload size to 256 bytes but not the entire packet" do
240
+ notification = described_class.new.tap do |n|
241
+ n.device_token = "a" * 108
242
+ n.alert = "a" * 210
243
+ n.app = app
244
+ end
245
+
246
+ expect(notification.to_binary(for_validation: true).bytesize).to be > 256
247
+ expect(notification.payload.bytesize).to be < 256
248
+ expect(notification).to be_valid
249
+ end
250
+ end
251
+
252
+ describe 'thread-id' do
253
+ it 'includes thread-id in the payload' do
254
+ notification.thread_id = 'THREAD-ID'
255
+ expect(notification.as_json['aps']['thread-id']).to eq 'THREAD-ID'
256
+ end
257
+
258
+ it 'does not include thread-id in the payload if not set' do
259
+ expect(notification.as_json['aps']).to_not have_key('thread-id')
260
+ end
261
+ end
262
+ 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