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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +30 -0
- data/.gitignore +1 -0
- data/Gemfile +1 -0
- data/README.md +180 -42
- data/fcm.gemspec +14 -13
- data/lib/fcm.rb +143 -110
- data/spec/fcm_spec.rb +335 -394
- metadata +32 -12
- data/.travis.yml +0 -7
data/spec/fcm_spec.rb
CHANGED
@@ -1,497 +1,438 @@
|
|
1
|
-
require
|
1
|
+
require "spec_helper"
|
2
2
|
|
3
3
|
describe FCM do
|
4
|
-
let(:
|
5
|
-
let(:
|
6
|
-
let(:
|
7
|
-
|
8
|
-
let(:
|
9
|
-
let(:
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
23
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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(:
|
41
|
-
|
42
|
-
|
43
|
-
|
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:
|
54
|
+
status: status_code,
|
49
55
|
)
|
50
56
|
end
|
51
57
|
|
52
|
-
|
53
|
-
|
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
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
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
|
-
|
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
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
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
|
-
|
89
|
-
let
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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
|
-
|
105
|
-
let
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
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
|
-
|
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
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
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
|
-
|
134
|
-
let
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
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
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
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
|
-
|
154
|
-
|
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
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
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
|
-
|
167
|
-
|
168
|
-
|
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
|
-
|
175
|
-
let(:
|
198
|
+
describe 'error handling' do
|
199
|
+
let(:send_v1_params) do
|
176
200
|
{
|
177
|
-
|
178
|
-
|
201
|
+
'token' => '4sdsx',
|
202
|
+
'notification' => {
|
203
|
+
'title' => 'Breaking News',
|
204
|
+
'body' => 'New news story available.'
|
205
|
+
}
|
179
206
|
}
|
180
207
|
end
|
181
208
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
).
|
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 '
|
204
|
-
|
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
|
216
|
-
|
217
|
-
|
218
|
-
|
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 '
|
224
|
-
|
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
|
236
|
-
|
237
|
-
|
238
|
-
|
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 '
|
244
|
-
|
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
|
256
|
-
|
257
|
-
|
258
|
-
|
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
|
-
|
265
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
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
|
-
|
292
|
-
|
281
|
+
before do
|
282
|
+
stub_fcm_send_to_topic_request
|
283
|
+
end
|
293
284
|
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
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
|
304
|
-
|
292
|
+
context 'when topic is invalid' do
|
293
|
+
let(:topic) { '/topics/news$' }
|
305
294
|
|
306
|
-
|
307
|
-
|
308
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
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
|
-
|
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
|
-
|
348
|
-
|
349
|
-
|
315
|
+
'data' => {
|
316
|
+
'story_id' => 'story_12345'
|
317
|
+
}
|
350
318
|
}
|
351
319
|
end
|
352
|
-
|
353
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
367
|
-
|
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
|
-
|
375
|
-
|
376
|
-
|
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
|
-
|
382
|
-
|
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
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
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
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
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
|
-
|
418
|
-
|
419
|
-
|
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 '
|
428
|
-
|
429
|
-
|
430
|
-
|
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
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
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
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
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
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
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
|
473
|
-
end
|
410
|
+
end
|
474
411
|
|
475
|
-
|
476
|
-
|
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
|
-
|
415
|
+
let(:uri) { "#{FCM::INSTANCE_ID_API}/iid/v1:batchAdd" }
|
416
|
+
let(:params) { { to: "/topics/#{topic}", registration_tokens: registration_tokens } }
|
489
417
|
|
490
|
-
|
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
|
-
|
495
|
-
|
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
|