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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +30 -0
- data/.gitignore +1 -0
- data/README.md +145 -51
- data/fcm.gemspec +14 -13
- data/lib/fcm.rb +63 -91
- data/spec/fcm_spec.rb +331 -394
- metadata +28 -8
- data/.travis.yml +0 -7
data/spec/fcm_spec.rb
CHANGED
@@ -1,501 +1,438 @@
|
|
1
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
|
-
|
24
|
+
it "should initialize" do
|
25
|
+
expect { client }.not_to raise_error
|
28
26
|
end
|
29
27
|
|
30
|
-
describe "
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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(:
|
45
|
-
|
46
|
-
|
47
|
-
|
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:
|
54
|
+
status: status_code,
|
53
55
|
)
|
54
56
|
end
|
55
57
|
|
56
|
-
|
57
|
-
|
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
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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
|
-
|
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
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
93
|
-
let
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
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
|
-
|
109
|
-
let
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|
-
|
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
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
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
|
-
|
138
|
-
let
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
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
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
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
|
-
|
158
|
-
|
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
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
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
|
-
|
171
|
-
|
172
|
-
|
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
|
-
|
179
|
-
let(:
|
198
|
+
describe 'error handling' do
|
199
|
+
let(:send_v1_params) do
|
180
200
|
{
|
181
|
-
|
182
|
-
|
201
|
+
'token' => '4sdsx',
|
202
|
+
'notification' => {
|
203
|
+
'title' => 'Breaking News',
|
204
|
+
'body' => 'New news story available.'
|
205
|
+
}
|
183
206
|
}
|
184
207
|
end
|
185
208
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
).
|
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
|
208
|
-
|
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
|
220
|
-
|
221
|
-
|
222
|
-
|
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
|
228
|
-
|
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
|
240
|
-
|
241
|
-
|
242
|
-
|
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
|
248
|
-
|
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
|
260
|
-
|
261
|
-
|
262
|
-
|
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
|
-
|
269
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
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
|
-
|
296
|
-
|
281
|
+
before do
|
282
|
+
stub_fcm_send_to_topic_request
|
283
|
+
end
|
297
284
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
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
|
308
|
-
|
292
|
+
context 'when topic is invalid' do
|
293
|
+
let(:topic) { '/topics/news$' }
|
309
294
|
|
310
|
-
|
311
|
-
|
312
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
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
|
-
|
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
|
-
|
352
|
-
|
353
|
-
|
315
|
+
'data' => {
|
316
|
+
'story_id' => 'story_12345'
|
317
|
+
}
|
354
318
|
}
|
355
319
|
end
|
356
|
-
|
357
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
371
|
-
|
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
|
-
|
379
|
-
|
380
|
-
|
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
|
-
|
386
|
-
|
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
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
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
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
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
|
-
|
422
|
-
|
423
|
-
|
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
|
432
|
-
|
433
|
-
|
434
|
-
|
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
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
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
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
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
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
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
|
477
|
-
end
|
410
|
+
end
|
478
411
|
|
479
|
-
|
480
|
-
|
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
|
-
|
415
|
+
let(:uri) { "#{FCM::INSTANCE_ID_API}/iid/v1:batchAdd" }
|
416
|
+
let(:params) { { to: "/topics/#{topic}", registration_tokens: registration_tokens } }
|
493
417
|
|
494
|
-
|
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
|
-
|
499
|
-
|
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
|