fcm 1.0.5 → 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,501 +1,438 @@
1
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 "#send_v1" do
27
- pending "should send message"
24
+ it "should initialize" do
25
+ expect { client }.not_to raise_error
28
26
  end
29
27
 
30
- describe "sending notification" do
31
- let(:valid_request_body) do
32
- { registration_ids: registration_ids }
33
- end
34
- let(:valid_request_body_with_string) do
35
- { registration_ids: registration_id }
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)
36
32
  end
37
- let(:valid_request_headers) do
38
- {
39
- "Content-Type" => "application/json",
40
- "Authorization" => "key=#{api_key}",
41
- }
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)
42
37
  end
38
+ end
39
+
40
+ describe "#send_v1 or #send_notification_v1" do
41
+ let(:client) { FCM.new(json_key_path, project_name) }
43
42
 
44
- let(:stub_fcm_send_request) do
45
- stub_request(:post, send_url).with(
46
- body: valid_request_body.to_json,
47
- 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
48
50
  ).to_return(
49
51
  # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
50
52
  body: "{}",
51
53
  headers: {},
52
- status: 200,
54
+ status: status_code,
53
55
  )
54
56
  end
55
57
 
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: "{}",
62
- headers: {},
63
- status: 200,
64
- )
58
+ before do
59
+ stub_fcm_send_v1_request
65
60
  end
66
61
 
67
- let(:stub_fcm_send_request_with_basic_auth) do
68
- uri = URI.parse(send_url)
69
- uri.user = "a"
70
- uri.password = "b"
71
- 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
72
69
  end
73
70
 
74
- before(:each) do
75
- stub_fcm_send_request
76
- stub_fcm_send_request_with_string
77
- stub_fcm_send_request_with_basic_auth
78
- 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
79
98
 
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
99
+ include_examples 'succesfuly send notification'
85
100
 
86
- it "should send notification using POST to FCM if id provided as string" do
87
- fcm = FCM.new(api_key)
88
- fcm.send(registration_id).should eq(response: "success", body: "{}", headers: {}, status_code: 200, canonical_ids: [], not_registered_ids: [])
89
- 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
90
110
  end
91
111
 
92
- context "send notification with data" do
93
- let!(:stub_with_data) do
94
- stub_request(:post, send_url)
95
- .with(body: '{"registration_ids":["42"],"data":{"score":"5x1","time":"15:10"}}',
96
- headers: valid_request_headers)
97
- .to_return(status: 200, body: "", headers: {})
98
- end
99
- before do
100
- end
101
- it "should send the data in a post request to fcm" do
102
- fcm = FCM.new(api_key)
103
- fcm.send(registration_ids, data: { score: "5x1", time: "15:10" })
104
- 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
+ }
105
122
  end
123
+
124
+ include_examples 'succesfuly send notification'
106
125
  end
107
126
 
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: {})
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
+ }
120
137
  end
121
138
 
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
139
+ include_examples 'succesfuly send notification'
128
140
 
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
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
133
146
  end
134
147
  end
135
148
  end
136
149
 
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: {})
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
+ }
149
160
  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: {})
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
+ }
155
175
  end
156
176
 
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
177
+ include_examples 'succesfuly send notification'
178
+ end
163
179
 
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
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
169
191
 
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
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
175
195
  end
176
196
  end
177
197
 
178
- context "when send_notification responds with failure" do
179
- let(:mock_request_attributes) do
198
+ describe 'error handling' do
199
+ let(:send_v1_params) do
180
200
  {
181
- body: valid_request_body.to_json,
182
- headers: valid_request_headers,
201
+ 'token' => '4sdsx',
202
+ 'notification' => {
203
+ 'title' => 'Breaking News',
204
+ 'body' => 'New news story available.'
205
+ }
183
206
  }
184
207
  end
185
208
 
186
- subject { FCM.new(api_key) }
187
-
188
- context "on failure code 400" do
189
- before do
190
- stub_request(:post, send_url).with(
191
- mock_request_attributes
192
- ).to_return(
193
- # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
194
- body: "{}",
195
- headers: {},
196
- status: 400,
197
- )
198
- end
199
- it "should not send notification due to 400" do
200
- subject.send(registration_ids).should eq(body: "{}",
201
- headers: {},
202
- response: "Only applies for JSON requests. Indicates that the request could not be parsed as JSON, or it contained invalid fields.",
203
- 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')
204
216
  end
205
217
  end
206
218
 
207
- context "on failure code 401" do
208
- before do
209
- stub_request(:post, send_url).with(
210
- mock_request_attributes
211
- ).to_return(
212
- # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
213
- body: "{}",
214
- headers: {},
215
- status: 401,
216
- )
217
- end
219
+ context 'when status_code is 401' do
220
+ let(:status_code) { 401 }
218
221
 
219
- it "should not send notification due to 401" do
220
- subject.send(registration_ids).should eq(body: "{}",
221
- headers: {},
222
- response: "There was an error authenticating the sender account.",
223
- 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')
224
226
  end
225
227
  end
226
228
 
227
- context "on failure code 503" do
228
- before do
229
- stub_request(:post, send_url).with(
230
- mock_request_attributes
231
- ).to_return(
232
- # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
233
- body: "{}",
234
- headers: {},
235
- status: 503,
236
- )
237
- end
229
+ context 'when status_code is 500' do
230
+ let(:status_code) { 500 }
238
231
 
239
- it "should not send notification due to 503" do
240
- subject.send(registration_ids).should eq(body: "{}",
241
- headers: {},
242
- response: "Server is temporarily unavailable.",
243
- 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')
244
236
  end
245
237
  end
246
238
 
247
- context "on failure code 5xx" do
248
- before do
249
- stub_request(:post, send_url).with(
250
- mock_request_attributes
251
- ).to_return(
252
- # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
253
- body: '{"body-key" => "Body value"}',
254
- headers: { "header-key" => "Header value" },
255
- status: 599,
256
- )
257
- end
239
+ context 'when status_code is 503' do
240
+ let(:status_code) { 503 }
258
241
 
259
- it "should not send notification due to 599" do
260
- subject.send(registration_ids).should eq(body: '{"body-key" => "Body value"}',
261
- headers: { "header-key" => "Header value" },
262
- response: "There was an internal error in the FCM server while trying to process the request.",
263
- 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')
264
246
  end
265
247
  end
266
248
  end
249
+ end
267
250
 
268
- context "when send_notification responds canonical_ids" do
269
- let(:mock_request_attributes) do
270
- {
271
- body: valid_request_body.to_json,
272
- headers: valid_request_headers,
273
- }
274
- end
251
+ describe '#send_to_topic' do
252
+ let(:client) { FCM.new(json_key_path, project_name) }
275
253
 
276
- let(:valid_response_body_with_canonical_ids) do
277
- {
278
- failure: 0, canonical_ids: 1, results: [{ registration_id: "43", message_id: "0:1385025861956342%572c22801bb3" }],
279
- }
280
- end
254
+ let(:uri) { "#{FCM::BASE_URI_V1}#{project_name}/messages:send" }
281
255
 
282
- 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
283
269
 
284
- before do
285
- stub_request(:post, send_url).with(
286
- mock_request_attributes
287
- ).to_return(
288
- # ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
289
- body: valid_response_body_with_canonical_ids.to_json,
290
- headers: {},
291
- status: 200,
292
- )
293
- 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
294
280
 
295
- it "should contain canonical_ids" do
296
- response = subject.send(registration_ids)
281
+ before do
282
+ stub_fcm_send_to_topic_request
283
+ end
297
284
 
298
- response.should eq(headers: {},
299
- canonical_ids: [{ old: "42", new: "43" }],
300
- not_registered_ids: [],
301
- status_code: 200,
302
- response: "success",
303
- body: '{"failure":0,"canonical_ids":1,"results":[{"registration_id":"43","message_id":"0:1385025861956342%572c22801bb3"}]}')
304
- 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)
305
290
  end
306
291
 
307
- context "when send_notification responds with NotRegistered" do
308
- subject { FCM.new(api_key) }
292
+ context 'when topic is invalid' do
293
+ let(:topic) { '/topics/news$' }
309
294
 
310
- let(:mock_request_attributes) do
311
- {
312
- body: valid_request_body.to_json,
313
- headers: valid_request_headers,
314
- }
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
315
298
  end
299
+ end
300
+ end
316
301
 
317
- let(:valid_response_body_with_not_registered_ids) do
318
- {
319
- canonical_ids: 0, failure: 1, results: [{ error: "NotRegistered" }],
320
- }
321
- end
302
+ describe "#send_to_topic_condition" do
303
+ let(:client) { FCM.new(json_key_path, project_name) }
322
304
 
323
- before do
324
- stub_request(:post, send_url).with(
325
- mock_request_attributes
326
- ).to_return(
327
- body: valid_response_body_with_not_registered_ids.to_json,
328
- headers: {},
329
- status: 200,
330
- )
331
- end
305
+ let(:uri) { "#{FCM::BASE_URI_V1}#{project_name}/messages:send" }
332
306
 
333
- it "should contain not_registered_ids" do
334
- response = subject.send(registration_ids)
335
- response.should eq(
336
- headers: {},
337
- canonical_ids: [],
338
- not_registered_ids: registration_ids,
339
- status_code: 200,
340
- response: "success",
341
- body: '{"canonical_ids":0,"failure":1,"results":[{"error":"NotRegistered"}]}',
342
- )
343
- end
307
+ let(:topic_condition) { "'foo' in topics" }
308
+ let(:params) do
309
+ {
310
+ 'condition' => topic_condition
311
+ }.merge(options)
344
312
  end
345
- end
346
-
347
- describe "sending group notifications" do
348
- # TODO: refactor to should_behave_like
349
- let(:valid_request_headers) do
313
+ let(:options) do
350
314
  {
351
- "Authorization" => "key=#{api_key}",
352
- "Content-Type" => "application/json",
353
- "Project-Id" => project_id,
315
+ 'data' => {
316
+ 'story_id' => 'story_12345'
317
+ }
354
318
  }
355
319
  end
356
- let(:valid_response_body) do
357
- { 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
+ )
358
330
  end
359
331
 
360
- let(:default_valid_request_body) do
361
- {
362
- registration_ids: registration_ids,
363
- operation: "create",
364
- notification_key_name: key_name,
365
- }
332
+ before do
333
+ stub_fcm_send_to_topic_condition_request
366
334
  end
367
335
 
368
- 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
369
342
 
370
- # ref: https://firebase.google.com/docs/cloud-messaging/notifications#managing-device-groups-on-the-app-server
371
- context "create" do
372
- let(:valid_request_body) do
373
- default_valid_request_body.merge({
374
- operation: "create",
375
- })
376
- end
343
+ context 'when topic_condition is invalid' do
344
+ let(:topic_condition) { "'foo' in topics$" }
377
345
 
378
- let(:mock_request_attributes) do
379
- {
380
- body: valid_request_body.to_json,
381
- headers: valid_request_headers,
382
- }
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
383
349
  end
350
+ end
351
+ end
384
352
 
385
- before do
386
- stub_request(:post, group_notification_base_uri).with(
387
- mock_request_attributes
388
- ).to_return(
389
- body: valid_response_body.to_json,
390
- headers: {},
391
- status: 200,
392
- )
393
- end
353
+ describe "#get_instance_id_info" do
354
+ subject(:get_info) { client.get_instance_id_info(registration_token, options) }
394
355
 
395
- it "should send a post request" do
396
- response = subject.create(key_name, project_id, registration_ids)
397
- response.should eq(
398
- headers: {},
399
- status_code: 200,
400
- response: "success",
401
- body: valid_response_body.to_json,
402
- )
403
- end
404
- end # create context
405
-
406
- context "add" do
407
- let(:valid_request_body) do
408
- default_valid_request_body.merge({
409
- operation: "add",
410
- notification_key: notification_key,
411
- })
412
- 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" }
413
360
 
414
- let(:mock_request_attributes) do
415
- {
416
- body: valid_request_body.to_json,
417
- headers: valid_request_headers,
418
- }
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
419
366
  end
367
+ end
420
368
 
421
- before do
422
- stub_request(:post, group_notification_base_uri).with(
423
- mock_request_attributes
424
- ).to_return(
425
- body: valid_response_body.to_json,
426
- headers: {},
427
- status: 200,
428
- )
429
- end
369
+ context 'with detail option' do
370
+ let(:uri) { "#{base_uri}/#{registration_token}?details=true" }
371
+ let(:options) { { details: true } }
430
372
 
431
- it "should send a post request" do
432
- response = subject.add(key_name, project_id, notification_key, registration_ids)
433
- response.should eq(
434
- headers: {},
435
- status_code: 200,
436
- response: "success",
437
- body: valid_response_body.to_json,
438
- )
439
- end
440
- end # add context
441
-
442
- context "remove" do
443
- let(:valid_request_body) do
444
- default_valid_request_body.merge({
445
- operation: "remove",
446
- notification_key: notification_key,
447
- })
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
448
377
  end
378
+ end
379
+ end
449
380
 
450
- let(:mock_request_attributes) do
451
- {
452
- body: valid_request_body.to_json,
453
- headers: valid_request_headers,
454
- }
455
- 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] }
456
386
 
457
- before do
458
- stub_request(:post, group_notification_base_uri).with(
459
- mock_request_attributes
460
- ).to_return(
461
- body: valid_response_body.to_json,
462
- headers: {},
463
- status: 200,
464
- )
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
465
396
  end
397
+ end
466
398
 
467
- it "should send a post request" do
468
- response = subject.remove(key_name, project_id, notification_key, registration_ids)
469
- response.should eq(
470
- headers: {},
471
- status_code: 200,
472
- response: "success",
473
- body: valid_response_body.to_json,
474
- )
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
475
409
  end
476
- end # remove context
477
- end
410
+ end
478
411
 
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")
412
+ describe "#batch_topic_subscription" do
413
+ subject(:batch_subscribe) { client.batch_topic_subscription(topic, registration_tokens) }
491
414
 
492
- 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 } }
493
417
 
494
- 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
495
423
  end
496
- end
497
424
 
498
- describe "subscribing to a topic" do
499
- # 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
500
437
  end
501
438
  end