fcm 0.0.2 → 1.0.8

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.
data/spec/fcm_spec.rb CHANGED
@@ -1,180 +1,281 @@
1
- require 'spec_helper'
1
+ require "spec_helper"
2
2
 
3
3
  describe FCM do
4
- let(:send_url) { "#{FCM.base_uri}/send" }
5
- let(:group_notification_base_uri) { "https://android.googleapis.com/gcm/notification" }
6
- let(:api_key) { 'AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA' }
7
- let(:registration_ids) { ['42'] }
8
- let(:key_name) { 'appUser-Chris' }
4
+ let(:send_url) { "#{FCM::BASE_URI}/fcm/send" }
5
+ let(:group_notification_base_uri) { "#{FCM::GROUP_NOTIFICATION_BASE_URI}/gcm/notification" }
6
+ let(:api_key) { "AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA" }
7
+ let(:registration_id) { "42" }
8
+ let(:registration_ids) { ["42"] }
9
+ let(:key_name) { "appUser-Chris" }
9
10
  let(:project_id) { "123456789" } # https://developers.google.com/cloud-messaging/gcm#senderid
10
11
  let(:notification_key) { "APA91bGHXQBB...9QgnYOEURwm0I3lmyqzk2TXQ" }
12
+ let(:valid_topic) { "TopicA" }
13
+ let(:invalid_topic) { "TopicA$" }
14
+ let(:valid_condition) { "'TopicA' in topics && ('TopicB' in topics || 'TopicC' in topics)" }
15
+ let(:invalid_condition) { "'TopicA' in topics and some other text ('TopicB' in topics || 'TopicC' in topics)" }
16
+ let(:invalid_condition_topic) { "'TopicA$' in topics" }
11
17
 
12
- it 'should raise an error if the api key is not provided' do
18
+ it "should raise an error if the api key is not provided" do
13
19
  expect { FCM.new }.to raise_error(ArgumentError)
14
20
  end
15
21
 
16
- it 'should raise error if time_to_live is given' do
22
+ it "should raise error if time_to_live is given" do
17
23
  # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#ttl
18
24
  end
19
25
 
20
- describe 'sending notification' do
26
+ describe "#send_v1" do
27
+ pending "should send message"
28
+ end
29
+
30
+ describe "sending notification" do
21
31
  let(:valid_request_body) do
22
32
  { registration_ids: registration_ids }
23
33
  end
34
+ let(:valid_request_body_with_string) do
35
+ { registration_ids: registration_id }
36
+ end
24
37
  let(:valid_request_headers) do
25
38
  {
26
- 'Content-Type' => 'application/json',
27
- 'Authorization' => "key=#{api_key}"
39
+ "Content-Type" => "application/json",
40
+ "Authorization" => "key=#{api_key}",
28
41
  }
29
42
  end
30
43
 
31
44
  let(:stub_fcm_send_request) do
32
45
  stub_request(:post, send_url).with(
33
46
  body: valid_request_body.to_json,
34
- headers: valid_request_headers
47
+ headers: valid_request_headers,
35
48
  ).to_return(
36
49
  # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
37
- body: '{}',
50
+ body: "{}",
51
+ headers: {},
52
+ status: 200,
53
+ )
54
+ end
55
+
56
+ let(:stub_fcm_send_request_with_string) do
57
+ stub_request(:post, send_url).with(
58
+ body: valid_request_body_with_string.to_json,
59
+ headers: valid_request_headers,
60
+ ).to_return(
61
+ body: "{}",
38
62
  headers: {},
39
- status: 200
63
+ status: 200,
40
64
  )
41
65
  end
42
66
 
43
67
  let(:stub_fcm_send_request_with_basic_auth) do
44
68
  uri = URI.parse(send_url)
45
- uri.user = 'a'
46
- uri.password = 'b'
47
- stub_request(:post, uri.to_s).to_return(body: '{}', headers: {}, status: 200)
69
+ uri.user = "a"
70
+ uri.password = "b"
71
+ stub_request(:post, uri.to_s).to_return(body: "{}", headers: {}, status: 200)
48
72
  end
49
73
 
50
74
  before(:each) do
51
75
  stub_fcm_send_request
76
+ stub_fcm_send_request_with_string
52
77
  stub_fcm_send_request_with_basic_auth
53
78
  end
54
79
 
55
- it 'should send notification using POST to FCM server' do
80
+ it "should send notification using POST to FCM server" do
81
+ fcm = FCM.new(api_key)
82
+ fcm.send(registration_ids).should eq(response: "success", body: "{}", headers: {}, status_code: 200, canonical_ids: [], not_registered_ids: [])
83
+ stub_fcm_send_request.should have_been_made.times(1)
84
+ end
85
+
86
+ it "should send notification using POST to FCM if id provided as string" do
56
87
  fcm = FCM.new(api_key)
57
- fcm.send(registration_ids).should eq(response: 'success', body: '{}', headers: {}, status_code: 200, canonical_ids: [], not_registered_ids: [])
88
+ fcm.send(registration_id).should eq(response: "success", body: "{}", headers: {}, status_code: 200, canonical_ids: [], not_registered_ids: [])
58
89
  stub_fcm_send_request.should have_been_made.times(1)
59
90
  end
60
91
 
61
- context 'send notification with data' do
92
+ context "send notification with data" do
62
93
  let!(:stub_with_data) do
63
94
  stub_request(:post, send_url)
64
95
  .with(body: '{"registration_ids":["42"],"data":{"score":"5x1","time":"15:10"}}',
65
96
  headers: valid_request_headers)
66
- .to_return(status: 200, body: '', headers: {})
97
+ .to_return(status: 200, body: "", headers: {})
67
98
  end
68
99
  before do
69
100
  end
70
- it 'should send the data in a post request to fcm' do
101
+ it "should send the data in a post request to fcm" do
71
102
  fcm = FCM.new(api_key)
72
- fcm.send(registration_ids, data: { score: '5x1', time: '15:10' })
103
+ fcm.send(registration_ids, data: { score: "5x1", time: "15:10" })
73
104
  stub_with_data.should have_been_requested
74
105
  end
75
106
  end
76
107
 
77
- context 'when send_notification responds with failure' do
108
+ context "sending notification to a topic" do
109
+ let!(:stub_with_valid_topic) do
110
+ stub_request(:post, send_url)
111
+ .with(body: '{"to":"/topics/TopicA","data":{"score":"5x1","time":"15:10"}}',
112
+ headers: valid_request_headers)
113
+ .to_return(status: 200, body: "", headers: {})
114
+ end
115
+ let!(:stub_with_invalid_topic) do
116
+ stub_request(:post, send_url)
117
+ .with(body: '{"condition":"/topics/TopicA$","data":{"score":"5x1","time":"15:10"}}',
118
+ headers: valid_request_headers)
119
+ .to_return(status: 200, body: "", headers: {})
120
+ end
121
+
122
+ describe "#send_to_topic" do
123
+ it "should send the data in a post request to fcm" do
124
+ fcm = FCM.new(api_key)
125
+ fcm.send_to_topic(valid_topic, data: { score: "5x1", time: "15:10" })
126
+ stub_with_valid_topic.should have_been_requested
127
+ end
128
+
129
+ it "should not send to invalid topics" do
130
+ fcm = FCM.new(api_key)
131
+ fcm.send_to_topic(invalid_topic, data: { score: "5x1", time: "15:10" })
132
+ stub_with_invalid_topic.should_not have_been_requested
133
+ end
134
+ end
135
+ end
136
+
137
+ context "sending notification to a topic condition" do
138
+ let!(:stub_with_valid_condition) do
139
+ stub_request(:post, send_url)
140
+ .with(body: '{"condition":"\'TopicA\' in topics && (\'TopicB\' in topics || \'TopicC\' in topics)","data":{"score":"5x1","time":"15:10"}}',
141
+ headers: valid_request_headers)
142
+ .to_return(status: 200, body: "", headers: {})
143
+ end
144
+ let!(:stub_with_invalid_condition) do
145
+ stub_request(:post, send_url)
146
+ .with(body: '{"condition":"\'TopicA\' in topics and some other text (\'TopicB\' in topics || \'TopicC\' in topics)","data":{"score":"5x1","time":"15:10"}}',
147
+ headers: valid_request_headers)
148
+ .to_return(status: 200, body: "", headers: {})
149
+ end
150
+ let!(:stub_with_invalid_condition_topic) do
151
+ stub_request(:post, send_url)
152
+ .with(body: '{"condition":"\'TopicA$\' in topics","data":{"score":"5x1","time":"15:10"}}',
153
+ headers: valid_request_headers)
154
+ .to_return(status: 200, body: "", headers: {})
155
+ end
156
+
157
+ describe "#send_to_topic_condition" do
158
+ it "should send the data in a post request to fcm" do
159
+ fcm = FCM.new(api_key)
160
+ fcm.send_to_topic_condition(valid_condition, data: { score: "5x1", time: "15:10" })
161
+ stub_with_valid_condition.should have_been_requested
162
+ end
163
+
164
+ it "should not send to invalid conditions" do
165
+ fcm = FCM.new(api_key)
166
+ fcm.send_to_topic_condition(invalid_condition, data: { score: "5x1", time: "15:10" })
167
+ stub_with_invalid_condition.should_not have_been_requested
168
+ end
169
+
170
+ it "should not send to invalid topics in a condition" do
171
+ fcm = FCM.new(api_key)
172
+ fcm.send_to_topic_condition(invalid_condition_topic, data: { score: "5x1", time: "15:10" })
173
+ stub_with_invalid_condition_topic.should_not have_been_requested
174
+ end
175
+ end
176
+ end
177
+
178
+ context "when send_notification responds with failure" do
78
179
  let(:mock_request_attributes) do
79
180
  {
80
181
  body: valid_request_body.to_json,
81
- headers: valid_request_headers
182
+ headers: valid_request_headers,
82
183
  }
83
184
  end
84
185
 
85
186
  subject { FCM.new(api_key) }
86
187
 
87
- context 'on failure code 400' do
188
+ context "on failure code 400" do
88
189
  before do
89
190
  stub_request(:post, send_url).with(
90
191
  mock_request_attributes
91
192
  ).to_return(
92
193
  # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
93
- body: '{}',
194
+ body: "{}",
94
195
  headers: {},
95
- status: 400
196
+ status: 400,
96
197
  )
97
198
  end
98
- it 'should not send notification due to 400' do
99
- subject.send(registration_ids).should eq(body: '{}',
199
+ it "should not send notification due to 400" do
200
+ subject.send(registration_ids).should eq(body: "{}",
100
201
  headers: {},
101
- response: 'Only applies for JSON requests. Indicates that the request could not be parsed as JSON, or it contained invalid fields.',
202
+ response: "Only applies for JSON requests. Indicates that the request could not be parsed as JSON, or it contained invalid fields.",
102
203
  status_code: 400)
103
204
  end
104
205
  end
105
206
 
106
- context 'on failure code 401' do
207
+ context "on failure code 401" do
107
208
  before do
108
209
  stub_request(:post, send_url).with(
109
210
  mock_request_attributes
110
211
  ).to_return(
111
212
  # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
112
- body: '{}',
213
+ body: "{}",
113
214
  headers: {},
114
- status: 401
215
+ status: 401,
115
216
  )
116
217
  end
117
218
 
118
- it 'should not send notification due to 401' do
119
- subject.send(registration_ids).should eq(body: '{}',
219
+ it "should not send notification due to 401" do
220
+ subject.send(registration_ids).should eq(body: "{}",
120
221
  headers: {},
121
- response: 'There was an error authenticating the sender account.',
222
+ response: "There was an error authenticating the sender account.",
122
223
  status_code: 401)
123
224
  end
124
225
  end
125
226
 
126
- context 'on failure code 503' do
227
+ context "on failure code 503" do
127
228
  before do
128
229
  stub_request(:post, send_url).with(
129
230
  mock_request_attributes
130
231
  ).to_return(
131
232
  # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
132
- body: '{}',
233
+ body: "{}",
133
234
  headers: {},
134
- status: 503
235
+ status: 503,
135
236
  )
136
237
  end
137
238
 
138
- it 'should not send notification due to 503' do
139
- subject.send(registration_ids).should eq(body: '{}',
239
+ it "should not send notification due to 503" do
240
+ subject.send(registration_ids).should eq(body: "{}",
140
241
  headers: {},
141
- response: 'Server is temporarily unavailable.',
242
+ response: "Server is temporarily unavailable.",
142
243
  status_code: 503)
143
244
  end
144
245
  end
145
246
 
146
- context 'on failure code 5xx' do
247
+ context "on failure code 5xx" do
147
248
  before do
148
249
  stub_request(:post, send_url).with(
149
250
  mock_request_attributes
150
251
  ).to_return(
151
252
  # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
152
253
  body: '{"body-key" => "Body value"}',
153
- headers: { 'header-key' => 'Header value' },
154
- status: 599
254
+ headers: { "header-key" => "Header value" },
255
+ status: 599,
155
256
  )
156
257
  end
157
258
 
158
- it 'should not send notification due to 599' do
259
+ it "should not send notification due to 599" do
159
260
  subject.send(registration_ids).should eq(body: '{"body-key" => "Body value"}',
160
- headers: { 'header-key' => ['Header value'] },
161
- response: 'There was an internal error in the FCM server while trying to process the request.',
261
+ headers: { "header-key" => "Header value" },
262
+ response: "There was an internal error in the FCM server while trying to process the request.",
162
263
  status_code: 599)
163
264
  end
164
265
  end
165
266
  end
166
267
 
167
- context 'when send_notification responds canonical_ids' do
268
+ context "when send_notification responds canonical_ids" do
168
269
  let(:mock_request_attributes) do
169
270
  {
170
271
  body: valid_request_body.to_json,
171
- headers: valid_request_headers
272
+ headers: valid_request_headers,
172
273
  }
173
274
  end
174
275
 
175
276
  let(:valid_response_body_with_canonical_ids) do
176
277
  {
177
- failure: 0, canonical_ids: 1, results: [{ registration_id: '43', message_id: '0:1385025861956342%572c22801bb3' }]
278
+ failure: 0, canonical_ids: 1, results: [{ registration_id: "43", message_id: "0:1385025861956342%572c22801bb3" }],
178
279
  }
179
280
  end
180
281
 
@@ -187,35 +288,35 @@ describe FCM do
187
288
  # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
188
289
  body: valid_response_body_with_canonical_ids.to_json,
189
290
  headers: {},
190
- status: 200
291
+ status: 200,
191
292
  )
192
293
  end
193
294
 
194
- it 'should contain canonical_ids' do
295
+ it "should contain canonical_ids" do
195
296
  response = subject.send(registration_ids)
196
297
 
197
298
  response.should eq(headers: {},
198
- canonical_ids: [{ old: '42', new: '43' }],
299
+ canonical_ids: [{ old: "42", new: "43" }],
199
300
  not_registered_ids: [],
200
301
  status_code: 200,
201
- response: 'success',
302
+ response: "success",
202
303
  body: '{"failure":0,"canonical_ids":1,"results":[{"registration_id":"43","message_id":"0:1385025861956342%572c22801bb3"}]}')
203
304
  end
204
305
  end
205
306
 
206
- context 'when send_notification responds with NotRegistered' do
307
+ context "when send_notification responds with NotRegistered" do
207
308
  subject { FCM.new(api_key) }
208
309
 
209
310
  let(:mock_request_attributes) do
210
311
  {
211
312
  body: valid_request_body.to_json,
212
- headers: valid_request_headers
313
+ headers: valid_request_headers,
213
314
  }
214
315
  end
215
316
 
216
317
  let(:valid_response_body_with_not_registered_ids) do
217
318
  {
218
- canonical_ids: 0, failure: 1, results: [{ error: 'NotRegistered' }]
319
+ canonical_ids: 0, failure: 1, results: [{ error: "NotRegistered" }],
219
320
  }
220
321
  end
221
322
 
@@ -225,31 +326,31 @@ describe FCM do
225
326
  ).to_return(
226
327
  body: valid_response_body_with_not_registered_ids.to_json,
227
328
  headers: {},
228
- status: 200
329
+ status: 200,
229
330
  )
230
331
  end
231
332
 
232
- it 'should contain not_registered_ids' do
333
+ it "should contain not_registered_ids" do
233
334
  response = subject.send(registration_ids)
234
335
  response.should eq(
235
336
  headers: {},
236
337
  canonical_ids: [],
237
338
  not_registered_ids: registration_ids,
238
339
  status_code: 200,
239
- response: 'success',
240
- body: '{"canonical_ids":0,"failure":1,"results":[{"error":"NotRegistered"}]}'
340
+ response: "success",
341
+ body: '{"canonical_ids":0,"failure":1,"results":[{"error":"NotRegistered"}]}',
241
342
  )
242
343
  end
243
344
  end
244
345
  end
245
346
 
246
- describe 'sending group notifications' do
347
+ describe "sending group notifications" do
247
348
  # TODO: refactor to should_behave_like
248
349
  let(:valid_request_headers) do
249
350
  {
250
351
  "Authorization" => "key=#{api_key}",
251
- "Content-Type" => 'application/json',
252
- "Project-Id" => project_id
352
+ "Content-Type" => "application/json",
353
+ "Project-Id" => project_id,
253
354
  }
254
355
  end
255
356
  let(:valid_response_body) do
@@ -260,24 +361,24 @@ describe FCM do
260
361
  {
261
362
  registration_ids: registration_ids,
262
363
  operation: "create",
263
- notification_key_name: key_name
364
+ notification_key_name: key_name,
264
365
  }
265
366
  end
266
367
 
267
368
  subject { FCM.new(api_key) }
268
369
 
269
370
  # ref: https://firebase.google.com/docs/cloud-messaging/notifications#managing-device-groups-on-the-app-server
270
- context 'create' do
371
+ context "create" do
271
372
  let(:valid_request_body) do
272
373
  default_valid_request_body.merge({
273
- operation: "create"
374
+ operation: "create",
274
375
  })
275
376
  end
276
377
 
277
378
  let(:mock_request_attributes) do
278
379
  {
279
380
  body: valid_request_body.to_json,
280
- headers: valid_request_headers
381
+ headers: valid_request_headers,
281
382
  }
282
383
  end
283
384
 
@@ -287,33 +388,33 @@ describe FCM do
287
388
  ).to_return(
288
389
  body: valid_response_body.to_json,
289
390
  headers: {},
290
- status: 200
391
+ status: 200,
291
392
  )
292
393
  end
293
394
 
294
- it 'should send a post request' do
395
+ it "should send a post request" do
295
396
  response = subject.create(key_name, project_id, registration_ids)
296
397
  response.should eq(
297
398
  headers: {},
298
399
  status_code: 200,
299
- response: 'success',
300
- body: valid_response_body.to_json
400
+ response: "success",
401
+ body: valid_response_body.to_json,
301
402
  )
302
403
  end
303
404
  end # create context
304
405
 
305
- context 'add' do
406
+ context "add" do
306
407
  let(:valid_request_body) do
307
408
  default_valid_request_body.merge({
308
409
  operation: "add",
309
- notification_key: notification_key
410
+ notification_key: notification_key,
310
411
  })
311
412
  end
312
413
 
313
414
  let(:mock_request_attributes) do
314
415
  {
315
416
  body: valid_request_body.to_json,
316
- headers: valid_request_headers
417
+ headers: valid_request_headers,
317
418
  }
318
419
  end
319
420
 
@@ -323,33 +424,33 @@ describe FCM do
323
424
  ).to_return(
324
425
  body: valid_response_body.to_json,
325
426
  headers: {},
326
- status: 200
427
+ status: 200,
327
428
  )
328
429
  end
329
430
 
330
- it 'should send a post request' do
431
+ it "should send a post request" do
331
432
  response = subject.add(key_name, project_id, notification_key, registration_ids)
332
433
  response.should eq(
333
434
  headers: {},
334
435
  status_code: 200,
335
- response: 'success',
336
- body: valid_response_body.to_json
436
+ response: "success",
437
+ body: valid_response_body.to_json,
337
438
  )
338
439
  end
339
440
  end # add context
340
441
 
341
- context 'remove' do
442
+ context "remove" do
342
443
  let(:valid_request_body) do
343
444
  default_valid_request_body.merge({
344
445
  operation: "remove",
345
- notification_key: notification_key
446
+ notification_key: notification_key,
346
447
  })
347
448
  end
348
449
 
349
450
  let(:mock_request_attributes) do
350
451
  {
351
452
  body: valid_request_body.to_json,
352
- headers: valid_request_headers
453
+ headers: valid_request_headers,
353
454
  }
354
455
  end
355
456
 
@@ -359,20 +460,88 @@ describe FCM do
359
460
  ).to_return(
360
461
  body: valid_response_body.to_json,
361
462
  headers: {},
362
- status: 200
463
+ status: 200,
363
464
  )
364
465
  end
365
466
 
366
- it 'should send a post request' do
467
+ it "should send a post request" do
367
468
  response = subject.remove(key_name, project_id, notification_key, registration_ids)
368
469
  response.should eq(
369
470
  headers: {},
370
471
  status_code: 200,
371
- response: 'success',
372
- body: valid_response_body.to_json
472
+ response: "success",
473
+ body: valid_response_body.to_json,
373
474
  )
374
475
  end
375
476
  end # remove context
477
+ end
376
478
 
479
+ describe "#recover_notification_key" do
480
+ it "sends a 'retrieve notification key' request" do
481
+ uri = "#{FCM::GROUP_NOTIFICATION_BASE_URI}/gcm/notification"
482
+ endpoint = stub_request(:get, uri).with(
483
+ headers: {
484
+ "Content-Type" => "application/json",
485
+ "Authorization" => "key=TEST_SERVER_KEY",
486
+ "project_id" => "TEST_PROJECT_ID",
487
+ },
488
+ query: { notification_key_name: "TEST_KEY_NAME" },
489
+ )
490
+ client = FCM.new("TEST_SERVER_KEY")
491
+
492
+ client.recover_notification_key("TEST_KEY_NAME", "TEST_PROJECT_ID")
493
+
494
+ expect(endpoint).to have_been_requested
495
+ end
496
+ end
497
+
498
+ describe "subscribing to a topic" do
499
+ # TODO
500
+ end
501
+
502
+ describe 'getting instance info' do
503
+ subject(:get_info) { client.get_instance_id_info(registration_id, options) }
504
+
505
+ let(:options) { nil }
506
+ let(:client) { FCM.new('TEST_SERVER_KEY') }
507
+ let(:base_uri) { "#{FCM::INSTANCE_ID_API}/iid/info" }
508
+ let(:uri) { "#{base_uri}/#{registration_id}" }
509
+ let(:mock_request_attributes) do
510
+ { headers: {
511
+ 'Authorization' => 'key=TEST_SERVER_KEY',
512
+ 'Content-Type' => 'application/json'
513
+ } }
514
+ end
515
+
516
+ context 'without options' do
517
+ it 'calls info endpoint' do
518
+ endpoint = stub_request(:get, uri).with(mock_request_attributes)
519
+ get_info
520
+ expect(endpoint).to have_been_requested
521
+ end
522
+ end
523
+
524
+ context 'with detail option' do
525
+ let(:uri) { "#{base_uri}/#{registration_id}?details=true" }
526
+ let(:options) { { details: true } }
527
+
528
+ it 'calls info endpoint' do
529
+ endpoint = stub_request(:get, uri).with(mock_request_attributes)
530
+ get_info
531
+ expect(endpoint).to have_been_requested
532
+ end
533
+ end
534
+ end
535
+
536
+ describe "credentials path" do
537
+ it "can be a path to a file" do
538
+ fcm = FCM.new("test", "README.md")
539
+ expect(fcm.__send__(:json_key).class).to eq(File)
540
+ end
541
+
542
+ it "can be an IO object" do
543
+ fcm = FCM.new("test", StringIO.new("hey"))
544
+ expect(fcm.__send__(:json_key).class).to eq(StringIO)
545
+ end
377
546
  end
378
547
  end