Skip to content

Commit a74644c

Browse files
authored
Housekeeping (#69)
Housekeeping
1 parent 6b5f8a7 commit a74644c

File tree

6 files changed

+274
-32
lines changed

6 files changed

+274
-32
lines changed

spec/APNS.spec.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@ describe('APNS', () => {
3535
fail('should not be reached');
3636
});
3737

38+
it('fails to initialize with no options', (done) => {
39+
try {
40+
new APNS();
41+
} catch(e) {
42+
expect(e.code).toBe(Parse.Error.PUSH_MISCONFIGURED);
43+
done();
44+
return;
45+
}
46+
fail('should not be reached');
47+
});
48+
3849
it('fails to initialize without a bundleID', (done) => {
3950
const apnsArgs = {
4051
production: true,
@@ -431,4 +442,35 @@ describe('APNS', () => {
431442
});
432443
done();
433444
});
445+
446+
it('reports proper error when no conn is available', (done) => {
447+
var args = [{
448+
cert: 'prodCert.pem',
449+
key: 'prodKey.pem',
450+
production: true,
451+
bundleId: 'bundleId'
452+
}];
453+
var data = {
454+
'data': {
455+
'alert': 'alert'
456+
}
457+
}
458+
var devices = [
459+
{
460+
deviceToken: '112233',
461+
appIdentifier: 'invalidBundleId'
462+
},
463+
]
464+
var apns = new APNS(args);
465+
apns.send(data, devices).then((results) => {
466+
expect(results.length).toBe(1);
467+
let result = results[0];
468+
expect(result.transmitted).toBe(false);
469+
expect(result.result.error).toBe('No connection available');
470+
done();
471+
}, (err) => {
472+
fail('should not fail');
473+
done();
474+
})
475+
})
434476
});

spec/GCM.spec.js

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,35 @@
11
var GCM = require('../src/GCM');
22

3+
function mockSender(gcm) {
4+
return spyOn(gcm.sender, 'send').and.callFake(function(message, options, timeout, cb) {
5+
/*{ "multicast_id":7680139367771848000,
6+
"success":0,
7+
"failure":4,
8+
"canonical_ids":0,
9+
"results":[ {"error":"InvalidRegistration"},
10+
{"error":"InvalidRegistration"},
11+
{"error":"InvalidRegistration"},
12+
{"error":"InvalidRegistration"}] }*/
13+
14+
let tokens = options.registrationTokens;
15+
const response = {
16+
multicast_id: 7680139367771848000,
17+
success: tokens.length,
18+
failure: 0,
19+
cannonical_ids: 0,
20+
results: tokens.map((token, index) => {
21+
return {
22+
message_id: 7680139367771848000+''+index,
23+
registration_id: token
24+
}
25+
})
26+
}
27+
process.nextTick(() => {
28+
cb(null, response);
29+
});
30+
});
31+
}
32+
333
describe('GCM', () => {
434
it('can initialize', (done) => {
535
var args = {
@@ -15,6 +45,16 @@ describe('GCM', () => {
1545
expect(function() {
1646
new GCM(args);
1747
}).toThrow();
48+
args = {
49+
apisKey: 'apiKey'
50+
};
51+
expect(function() {
52+
new GCM(args);
53+
}).toThrow();
54+
args = undefined;
55+
expect(function() {
56+
new GCM(args);
57+
}).toThrow();
1858
done();
1959
});
2060

@@ -194,19 +234,77 @@ describe('GCM', () => {
194234
deviceToken: 'token4'
195235
}
196236
];
197-
237+
mockSender(gcm);
198238
gcm.send(data, devices).then((response) => {
199239
expect(Array.isArray(response)).toBe(true);
200240
expect(response.length).toEqual(devices.length);
201241
expect(response.length).toEqual(4);
202242
response.forEach((res, index) => {
203-
expect(res.transmitted).toEqual(false);
243+
expect(res.transmitted).toEqual(true);
204244
expect(res.device).toEqual(devices[index]);
205245
})
206246
done();
207247
})
208248
});
209249

250+
it('can send GCM request with slices', (done) => {
251+
let originalMax = GCM.GCMRegistrationTokensMax;
252+
GCM.GCMRegistrationTokensMax = 2;
253+
var gcm = new GCM({
254+
apiKey: 'apiKey'
255+
});
256+
// Mock data
257+
var expirationTime = 2454538822113;
258+
var data = {
259+
'expiration_time': expirationTime,
260+
'data': {
261+
'alert': 'alert'
262+
}
263+
}
264+
// Mock devices
265+
var devices = [
266+
{
267+
deviceToken: 'token'
268+
},
269+
{
270+
deviceToken: 'token2'
271+
},
272+
{
273+
deviceToken: 'token3'
274+
},
275+
{
276+
deviceToken: 'token4'
277+
},
278+
{
279+
deviceToken: 'token5'
280+
},
281+
{
282+
deviceToken: 'token6'
283+
},
284+
{
285+
deviceToken: 'token7'
286+
},
287+
{
288+
deviceToken: 'token8'
289+
}
290+
];
291+
spyOn(gcm, 'send').and.callThrough();
292+
gcm.send(data, devices).then((response) => {
293+
expect(Array.isArray(response)).toBe(true);
294+
expect(response.length).toEqual(devices.length);
295+
expect(response.length).toEqual(8);
296+
response.forEach((res, index) => {
297+
expect(res.transmitted).toEqual(false);
298+
expect(res.device).toEqual(devices[index]);
299+
});
300+
// 1 original call
301+
// 4 calls (1 per slice of 2)
302+
expect(gcm.send.calls.count()).toBe(1+4);
303+
GCM.GCMRegistrationTokensMax = originalMax;
304+
done();
305+
})
306+
});
307+
210308
it('can slice devices', (done) => {
211309
// Mock devices
212310
var devices = [makeDevice(1), makeDevice(2), makeDevice(3), makeDevice(4)];

spec/MockAPNConnection.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,16 @@ module.exports = function (args) {
44
let emitter = new EventEmitter();
55
emitter.options = args;
66
emitter.pushNotification = function(push, devices) {
7+
if (!Array.isArray(devices)) {
8+
devices = [devices];
9+
}
710
devices.forEach((device) => {
811
process.nextTick(() => {
9-
emitter.emit('transmitted', push, device);
12+
if (args.shouldFailTransmissions) {
13+
emitter.emit('transmissionError', -1, push, device);
14+
} else {
15+
emitter.emit('transmitted', push, device);
16+
}
1017
});
1118
});
1219
};

spec/ParsePushAdapter.spec.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,99 @@ describe('ParsePushAdapter', () => {
344344
})
345345
});
346346

347+
it('reports properly failures when all transmissions have failed', (done) => {
348+
var pushConfig = {
349+
ios: [
350+
{
351+
cert: 'cert.cer',
352+
key: 'key.pem',
353+
production: false,
354+
shouldFailTransmissions: true,
355+
bundleId: 'iosbundleId'
356+
}
357+
]
358+
};
359+
var installations = [
360+
{
361+
deviceType: 'ios',
362+
deviceToken: '0d72a1baa92a2febd9a254cbd6584f750c70b2350af5fc9052d1d12584b738e6',
363+
appIdentifier: 'iosbundleId'
364+
}
365+
];
366+
367+
var parsePushAdapter = new ParsePushAdapter(pushConfig);
368+
parsePushAdapter.send({data: {alert: 'some'}}, installations).then((results) => {
369+
expect(Array.isArray(results)).toBe(true);
370+
371+
// 2x iOS, 1x android, 1x osx, 1x tvos
372+
expect(results.length).toBe(1);
373+
const result = results[0];
374+
expect(typeof result.device).toBe('object');
375+
if (!result.device) {
376+
fail('result should have device');
377+
return;
378+
}
379+
const device = result.device;
380+
expect(typeof device.deviceType).toBe('string');
381+
expect(typeof device.deviceToken).toBe('string');
382+
expect(result.transmitted).toBe(false);
383+
expect(result.response.error.indexOf('APNS can not find vaild connection for ')).toBe(0);
384+
done();
385+
}).catch((err) => {
386+
fail('Should not fail');
387+
done();
388+
})
389+
});
390+
391+
it('reports properly select connection', (done) => {
392+
var pushConfig = {
393+
ios: [
394+
{
395+
cert: 'cert.cer',
396+
key: 'key.pem',
397+
production: false,
398+
shouldFailTransmissions: true,
399+
bundleId: 'iosbundleId'
400+
},
401+
{
402+
cert: 'cert.cer',
403+
key: 'key.pem',
404+
production: false,
405+
bundleId: 'iosbundleId'
406+
}
407+
]
408+
};
409+
var installations = [
410+
{
411+
deviceType: 'ios',
412+
deviceToken: '0d72a1baa92a2febd9a254cbd6584f750c70b2350af5fc9052d1d12584b738e6',
413+
appIdentifier: 'iosbundleId'
414+
}
415+
];
416+
417+
var parsePushAdapter = new ParsePushAdapter(pushConfig);
418+
parsePushAdapter.send({data: {alert: 'some'}}, installations).then((results) => {
419+
expect(Array.isArray(results)).toBe(true);
420+
421+
// 2x iOS, 1x android, 1x osx, 1x tvos
422+
expect(results.length).toBe(1);
423+
const result = results[0];
424+
expect(typeof result.device).toBe('object');
425+
if (!result.device) {
426+
fail('result should have device');
427+
return;
428+
}
429+
const device = result.device;
430+
expect(typeof device.deviceType).toBe('string');
431+
expect(typeof device.deviceToken).toBe('string');
432+
expect(result.transmitted).toBe(true);
433+
done();
434+
}).catch((err) => {
435+
fail('Should not fail');
436+
done();
437+
})
438+
});
439+
347440
it('properly marks not transmitter when sender is missing', (done) => {
348441
var pushConfig = {
349442
android: {

src/APNS.js

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,14 @@ function APNS(args) {
7171
});
7272

7373
conn.on('transmitted', function(notification, device) {
74-
if (device.callback) {
75-
device.callback({
76-
notification: notification,
77-
transmitted: true,
78-
device: {
79-
deviceType: device.deviceType,
80-
deviceToken: device.token.toString('hex')
81-
}
82-
});
83-
}
74+
device.callback({
75+
notification: notification,
76+
transmitted: true,
77+
device: {
78+
deviceType: device.deviceType,
79+
deviceToken: device.token.toString('hex')
80+
}
81+
});
8482
log.verbose(LOG_PREFIX, 'APNS Connection %d Notification transmitted to %s', conn.index, device.token.toString('hex'));
8583
});
8684

@@ -126,6 +124,7 @@ APNS.prototype.send = function(data, devices) {
126124
let apnDevice = new apn.Device(device.deviceToken);
127125
apnDevice.deviceType = device.deviceType;
128126
apnDevice.connIndex = qualifiedConnIndexs[0];
127+
/* istanbul ignore else */
129128
if (device.appIdentifier) {
130129
apnDevice.appIdentifier = device.appIdentifier;
131130
}
@@ -173,18 +172,16 @@ function handleTransmissionError(conns, errCode, notification, apnDevice) {
173172
}
174173
// There is no more available conns, we give up in this case
175174
if (newConnIndex < 0 || newConnIndex >= conns.length) {
176-
if (apnDevice.callback) {
177-
log.error(LOG_PREFIX, `cannot find vaild connection for ${apnDevice.token.toString('hex')}`);
178-
apnDevice.callback({
179-
response: {error: `APNS can not find vaild connection for ${apnDevice.token.toString('hex')}`, code: errCode},
180-
status: errCode,
181-
transmitted: false,
182-
device: {
183-
deviceType: apnDevice.deviceType,
184-
deviceToken: apnDevice.token.toString('hex')
185-
}
186-
});
187-
}
175+
log.error(LOG_PREFIX, `cannot find vaild connection for ${apnDevice.token.toString('hex')}`);
176+
apnDevice.callback({
177+
response: {error: `APNS can not find vaild connection for ${apnDevice.token.toString('hex')}`, code: errCode},
178+
status: errCode,
179+
transmitted: false,
180+
device: {
181+
deviceType: apnDevice.deviceType,
182+
deviceToken: apnDevice.token.toString('hex')
183+
}
184+
});
188185
return;
189186
}
190187

@@ -258,6 +255,7 @@ function generateNotification(coreData, expirationTime) {
258255

259256
APNS.generateNotification = generateNotification;
260257

258+
/* istanbul ignore else */
261259
if (process.env.TESTING) {
262260
APNS.chooseConns = chooseConns;
263261
APNS.handleTransmissionError = handleTransmissionError;

0 commit comments

Comments
 (0)