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