fcm 1.0.8 → 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 +1 -1
- data/.gitignore +1 -0
- data/README.md +129 -48
- data/fcm.gemspec +1 -1
- data/lib/fcm.rb +48 -85
- data/spec/fcm_spec.rb +317 -426
- metadata +3 -3
data/spec/fcm_spec.rb
CHANGED
@@ -1,547 +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 }
|
36
|
-
end
|
37
|
-
let(:valid_request_headers) do
|
38
|
-
{
|
39
|
-
"Content-Type" => "application/json",
|
40
|
-
"Authorization" => "key=#{api_key}",
|
41
|
-
}
|
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)
|
42
32
|
end
|
43
33
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
headers: valid_request_headers,
|
48
|
-
).to_return(
|
49
|
-
# ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
|
50
|
-
body: "{}",
|
51
|
-
headers: {},
|
52
|
-
status: 200,
|
53
|
-
)
|
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)
|
54
37
|
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#send_v1 or #send_notification_v1" do
|
41
|
+
let(:client) { FCM.new(json_key_path, project_name) }
|
42
|
+
|
43
|
+
let(:uri) { "#{FCM::BASE_URI_V1}#{project_name}/messages:send" }
|
44
|
+
let(:status_code) { 200 }
|
55
45
|
|
56
|
-
let(:
|
57
|
-
stub_request(:post,
|
58
|
-
body:
|
59
|
-
headers:
|
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
|
60
50
|
).to_return(
|
51
|
+
# ref: https://firebase.google.com/docs/cloud-messaging/http-server-ref#interpret-downstream
|
61
52
|
body: "{}",
|
62
53
|
headers: {},
|
63
|
-
status:
|
54
|
+
status: status_code,
|
64
55
|
)
|
65
56
|
end
|
66
57
|
|
67
|
-
|
68
|
-
|
69
|
-
uri.user = "a"
|
70
|
-
uri.password = "b"
|
71
|
-
stub_request(:post, uri.to_s).to_return(body: "{}", headers: {}, status: 200)
|
58
|
+
before do
|
59
|
+
stub_fcm_send_v1_request
|
72
60
|
end
|
73
61
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
it "should send notification using POST to FCM server" do
|
81
|
-
fcm = FCM.new(api_key)
|
82
|
-
fcm.send(registration_ids).should eq(response: "success", body: "{}", headers: {}, status_code: 200, canonical_ids: [], not_registered_ids: [])
|
83
|
-
stub_fcm_send_request.should have_been_made.times(1)
|
84
|
-
end
|
85
|
-
|
86
|
-
it "should send notification using POST to FCM if id provided as string" do
|
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)
|
90
|
-
end
|
91
|
-
|
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
|
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)
|
105
68
|
end
|
106
69
|
end
|
107
70
|
|
108
|
-
|
109
|
-
let
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
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
|
+
}
|
120
97
|
end
|
121
98
|
|
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
|
99
|
+
include_examples 'succesfuly send notification'
|
128
100
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
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
|
134
109
|
end
|
135
110
|
end
|
136
111
|
|
137
|
-
|
138
|
-
let
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
headers: valid_request_headers)
|
148
|
-
.to_return(status: 200, body: "", headers: {})
|
149
|
-
end
|
150
|
-
let!(:stub_with_invalid_condition_topic) do
|
151
|
-
stub_request(:post, send_url)
|
152
|
-
.with(body: '{"condition":"\'TopicA$\' in topics","data":{"score":"5x1","time":"15:10"}}',
|
153
|
-
headers: valid_request_headers)
|
154
|
-
.to_return(status: 200, body: "", headers: {})
|
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
|
+
}
|
155
122
|
end
|
156
123
|
|
157
|
-
|
158
|
-
it "should send the data in a post request to fcm" do
|
159
|
-
fcm = FCM.new(api_key)
|
160
|
-
fcm.send_to_topic_condition(valid_condition, data: { score: "5x1", time: "15:10" })
|
161
|
-
stub_with_valid_condition.should have_been_requested
|
162
|
-
end
|
163
|
-
|
164
|
-
it "should not send to invalid conditions" do
|
165
|
-
fcm = FCM.new(api_key)
|
166
|
-
fcm.send_to_topic_condition(invalid_condition, data: { score: "5x1", time: "15:10" })
|
167
|
-
stub_with_invalid_condition.should_not have_been_requested
|
168
|
-
end
|
169
|
-
|
170
|
-
it "should not send to invalid topics in a condition" do
|
171
|
-
fcm = FCM.new(api_key)
|
172
|
-
fcm.send_to_topic_condition(invalid_condition_topic, data: { score: "5x1", time: "15:10" })
|
173
|
-
stub_with_invalid_condition_topic.should_not have_been_requested
|
174
|
-
end
|
175
|
-
end
|
124
|
+
include_examples 'succesfuly send notification'
|
176
125
|
end
|
177
126
|
|
178
|
-
|
179
|
-
let(:
|
127
|
+
describe 'send to topic' do
|
128
|
+
let(:topic) { 'news' }
|
129
|
+
let(:send_v1_params) do
|
180
130
|
{
|
181
|
-
|
182
|
-
|
131
|
+
'topic' => topic,
|
132
|
+
'notification' => {
|
133
|
+
'title' => 'Breaking News',
|
134
|
+
'body' => 'New news story available.'
|
135
|
+
}
|
183
136
|
}
|
184
137
|
end
|
185
138
|
|
186
|
-
|
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)
|
204
|
-
end
|
205
|
-
end
|
139
|
+
include_examples 'succesfuly send notification'
|
206
140
|
|
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
|
141
|
+
context 'when topic is invalid' do
|
142
|
+
let(:topic) { '/topics/news$' }
|
218
143
|
|
219
|
-
it
|
220
|
-
|
221
|
-
headers: {},
|
222
|
-
response: "There was an error authenticating the sender account.",
|
223
|
-
status_code: 401)
|
144
|
+
it 'should raise error' do
|
145
|
+
stub_fcm_send_v1_request.should_not have_been_requested
|
224
146
|
end
|
225
147
|
end
|
148
|
+
end
|
226
149
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
end
|
238
|
-
|
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)
|
244
|
-
end
|
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
|
+
}
|
245
160
|
end
|
246
161
|
|
247
|
-
|
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
|
258
|
-
|
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)
|
264
|
-
end
|
265
|
-
end
|
162
|
+
include_examples 'succesfuly send notification'
|
266
163
|
end
|
267
164
|
|
268
|
-
|
269
|
-
let(:
|
165
|
+
describe 'send to notification_key' do
|
166
|
+
let(:notification_key) { 'notification_key' }
|
167
|
+
let(:send_v1_params) do
|
270
168
|
{
|
271
|
-
|
272
|
-
|
169
|
+
'notification_key' => notification_key,
|
170
|
+
'notification' => {
|
171
|
+
'title' => 'Breaking News',
|
172
|
+
'body' => 'New news story available.'
|
173
|
+
}
|
273
174
|
}
|
274
175
|
end
|
275
176
|
|
276
|
-
|
177
|
+
include_examples 'succesfuly send notification'
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'when project_name is empty' do
|
181
|
+
let(:project_name) { '' }
|
182
|
+
let(:send_v1_params) do
|
277
183
|
{
|
278
|
-
|
184
|
+
'token' => '4sdsx',
|
185
|
+
'notification' => {
|
186
|
+
'title' => 'Breaking News',
|
187
|
+
'body' => 'New news story available.'
|
188
|
+
}
|
279
189
|
}
|
280
190
|
end
|
281
191
|
|
282
|
-
|
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
|
195
|
+
end
|
196
|
+
end
|
283
197
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
198
|
+
describe 'error handling' do
|
199
|
+
let(:send_v1_params) do
|
200
|
+
{
|
201
|
+
'token' => '4sdsx',
|
202
|
+
'notification' => {
|
203
|
+
'title' => 'Breaking News',
|
204
|
+
'body' => 'New news story available.'
|
205
|
+
}
|
206
|
+
}
|
293
207
|
end
|
294
208
|
|
295
|
-
|
296
|
-
|
209
|
+
context 'when status_code is 400' do
|
210
|
+
let(:status_code) { 400 }
|
297
211
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
body: '{"failure":0,"canonical_ids":1,"results":[{"registration_id":"43","message_id":"0:1385025861956342%572c22801bb3"}]}')
|
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')
|
216
|
+
end
|
304
217
|
end
|
305
|
-
end
|
306
218
|
|
307
|
-
|
308
|
-
|
219
|
+
context 'when status_code is 401' do
|
220
|
+
let(:status_code) { 401 }
|
309
221
|
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
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')
|
226
|
+
end
|
315
227
|
end
|
316
228
|
|
317
|
-
|
318
|
-
{
|
319
|
-
canonical_ids: 0, failure: 1, results: [{ error: "NotRegistered" }],
|
320
|
-
}
|
321
|
-
end
|
229
|
+
context 'when status_code is 500' do
|
230
|
+
let(:status_code) { 500 }
|
322
231
|
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
headers: {},
|
329
|
-
status: 200,
|
330
|
-
)
|
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')
|
236
|
+
end
|
331
237
|
end
|
332
238
|
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
body: '{"canonical_ids":0,"failure":1,"results":[{"error":"NotRegistered"}]}',
|
342
|
-
)
|
239
|
+
context 'when status_code is 503' do
|
240
|
+
let(:status_code) { 503 }
|
241
|
+
|
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')
|
246
|
+
end
|
343
247
|
end
|
344
248
|
end
|
345
249
|
end
|
346
250
|
|
347
|
-
describe
|
348
|
-
|
349
|
-
|
251
|
+
describe '#send_to_topic' do
|
252
|
+
let(:client) { FCM.new(json_key_path, project_name) }
|
253
|
+
|
254
|
+
let(:uri) { "#{FCM::BASE_URI_V1}#{project_name}/messages:send" }
|
255
|
+
|
256
|
+
let(:topic) { 'news' }
|
257
|
+
let(:params) do
|
350
258
|
{
|
351
|
-
|
352
|
-
|
353
|
-
"Project-Id" => project_id,
|
354
|
-
}
|
259
|
+
'topic' => topic
|
260
|
+
}.merge(options)
|
355
261
|
end
|
356
|
-
let(:
|
357
|
-
{ notification_key: "APA91bGHXQBB...9QgnYOEURwm0I3lmyqzk2TXQ" }
|
358
|
-
end
|
359
|
-
|
360
|
-
let(:default_valid_request_body) do
|
262
|
+
let(:options) do
|
361
263
|
{
|
362
|
-
|
363
|
-
|
364
|
-
|
264
|
+
'data' => {
|
265
|
+
'story_id' => 'story_12345'
|
266
|
+
}
|
365
267
|
}
|
366
268
|
end
|
367
269
|
|
368
|
-
|
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
|
369
280
|
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
default_valid_request_body.merge({
|
374
|
-
operation: "create",
|
375
|
-
})
|
376
|
-
end
|
281
|
+
before do
|
282
|
+
stub_fcm_send_to_topic_request
|
283
|
+
end
|
377
284
|
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
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)
|
290
|
+
end
|
384
291
|
|
385
|
-
|
386
|
-
|
387
|
-
mock_request_attributes
|
388
|
-
).to_return(
|
389
|
-
body: valid_response_body.to_json,
|
390
|
-
headers: {},
|
391
|
-
status: 200,
|
392
|
-
)
|
393
|
-
end
|
292
|
+
context 'when topic is invalid' do
|
293
|
+
let(:topic) { '/topics/news$' }
|
394
294
|
|
395
|
-
it
|
396
|
-
|
397
|
-
|
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
|
413
|
-
|
414
|
-
let(:mock_request_attributes) do
|
415
|
-
{
|
416
|
-
body: valid_request_body.to_json,
|
417
|
-
headers: valid_request_headers,
|
418
|
-
}
|
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
|
419
298
|
end
|
299
|
+
end
|
300
|
+
end
|
420
301
|
|
421
|
-
|
422
|
-
|
423
|
-
mock_request_attributes
|
424
|
-
).to_return(
|
425
|
-
body: valid_response_body.to_json,
|
426
|
-
headers: {},
|
427
|
-
status: 200,
|
428
|
-
)
|
429
|
-
end
|
302
|
+
describe "#send_to_topic_condition" do
|
303
|
+
let(:client) { FCM.new(json_key_path, project_name) }
|
430
304
|
|
431
|
-
|
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
|
-
})
|
448
|
-
end
|
305
|
+
let(:uri) { "#{FCM::BASE_URI_V1}#{project_name}/messages:send" }
|
449
306
|
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
307
|
+
let(:topic_condition) { "'foo' in topics" }
|
308
|
+
let(:params) do
|
309
|
+
{
|
310
|
+
'condition' => topic_condition
|
311
|
+
}.merge(options)
|
312
|
+
end
|
313
|
+
let(:options) do
|
314
|
+
{
|
315
|
+
'data' => {
|
316
|
+
'story_id' => 'story_12345'
|
454
317
|
}
|
455
|
-
|
318
|
+
}
|
319
|
+
end
|
456
320
|
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
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
|
+
)
|
330
|
+
end
|
466
331
|
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
headers: {},
|
471
|
-
status_code: 200,
|
472
|
-
response: "success",
|
473
|
-
body: valid_response_body.to_json,
|
474
|
-
)
|
475
|
-
end
|
476
|
-
end # remove context
|
477
|
-
end
|
332
|
+
before do
|
333
|
+
stub_fcm_send_to_topic_condition_request
|
334
|
+
end
|
478
335
|
|
479
|
-
|
480
|
-
|
481
|
-
|
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" },
|
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
|
489
339
|
)
|
490
|
-
|
340
|
+
stub_fcm_send_to_topic_condition_request.should have_been_made.times(1)
|
341
|
+
end
|
491
342
|
|
492
|
-
|
343
|
+
context 'when topic_condition is invalid' do
|
344
|
+
let(:topic_condition) { "'foo' in topics$" }
|
493
345
|
|
494
|
-
|
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
|
349
|
+
end
|
495
350
|
end
|
496
351
|
end
|
497
352
|
|
498
|
-
describe "
|
499
|
-
|
500
|
-
end
|
501
|
-
|
502
|
-
describe 'getting instance info' do
|
503
|
-
subject(:get_info) { client.get_instance_id_info(registration_id, options) }
|
353
|
+
describe "#get_instance_id_info" do
|
354
|
+
subject(:get_info) { client.get_instance_id_info(registration_token, options) }
|
504
355
|
|
505
356
|
let(:options) { nil }
|
506
|
-
let(:client) { FCM.new('TEST_SERVER_KEY') }
|
507
357
|
let(:base_uri) { "#{FCM::INSTANCE_ID_API}/iid/info" }
|
508
|
-
let(:uri) { "#{base_uri}/#{
|
509
|
-
let(:
|
510
|
-
{ headers: {
|
511
|
-
'Authorization' => 'key=TEST_SERVER_KEY',
|
512
|
-
'Content-Type' => 'application/json'
|
513
|
-
} }
|
514
|
-
end
|
358
|
+
let(:uri) { "#{base_uri}/#{registration_token}" }
|
359
|
+
let(:registration_token) { "42" }
|
515
360
|
|
516
361
|
context 'without options' do
|
517
362
|
it 'calls info endpoint' do
|
518
|
-
endpoint = stub_request(:get, uri).with(
|
363
|
+
endpoint = stub_request(:get, uri).with(headers: mock_headers)
|
519
364
|
get_info
|
520
365
|
expect(endpoint).to have_been_requested
|
521
366
|
end
|
522
367
|
end
|
523
368
|
|
524
369
|
context 'with detail option' do
|
525
|
-
let(:uri) { "#{base_uri}/#{
|
370
|
+
let(:uri) { "#{base_uri}/#{registration_token}?details=true" }
|
526
371
|
let(:options) { { details: true } }
|
527
372
|
|
528
373
|
it 'calls info endpoint' do
|
529
|
-
endpoint = stub_request(:get, uri).with(
|
374
|
+
endpoint = stub_request(:get, uri).with(headers: mock_headers)
|
530
375
|
get_info
|
531
376
|
expect(endpoint).to have_been_requested
|
532
377
|
end
|
533
378
|
end
|
534
379
|
end
|
535
380
|
|
536
|
-
describe "
|
537
|
-
|
538
|
-
|
539
|
-
|
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] }
|
386
|
+
|
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
|
396
|
+
end
|
540
397
|
end
|
541
398
|
|
542
|
-
|
543
|
-
|
544
|
-
|
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
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
describe "#batch_topic_subscription" do
|
413
|
+
subject(:batch_subscribe) { client.batch_topic_subscription(topic, registration_tokens) }
|
414
|
+
|
415
|
+
let(:uri) { "#{FCM::INSTANCE_ID_API}/iid/v1:batchAdd" }
|
416
|
+
let(:params) { { to: "/topics/#{topic}", registration_tokens: registration_tokens } }
|
417
|
+
|
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
|
423
|
+
end
|
424
|
+
|
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
|
545
436
|
end
|
546
437
|
end
|
547
438
|
end
|