Skip to content

Housekeeping #69

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 18, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions spec/APNS.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ describe('APNS', () => {
fail('should not be reached');
});

it('fails to initialize with no options', (done) => {
try {
new APNS();
} catch(e) {
expect(e.code).toBe(Parse.Error.PUSH_MISCONFIGURED);
done();
return;
}
fail('should not be reached');
});

it('fails to initialize without a bundleID', (done) => {
const apnsArgs = {
production: true,
Expand Down Expand Up @@ -431,4 +442,35 @@ describe('APNS', () => {
});
done();
});

it('reports proper error when no conn is available', (done) => {
var args = [{
cert: 'prodCert.pem',
key: 'prodKey.pem',
production: true,
bundleId: 'bundleId'
}];
var data = {
'data': {
'alert': 'alert'
}
}
var devices = [
{
deviceToken: '112233',
appIdentifier: 'invalidBundleId'
},
]
var apns = new APNS(args);
apns.send(data, devices).then((results) => {
expect(results.length).toBe(1);
let result = results[0];
expect(result.transmitted).toBe(false);
expect(result.result.error).toBe('No connection available');
done();
}, (err) => {
fail('should not fail');
done();
})
})
});
102 changes: 100 additions & 2 deletions spec/GCM.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
var GCM = require('../src/GCM');

function mockSender(gcm) {
return spyOn(gcm.sender, 'send').and.callFake(function(message, options, timeout, cb) {
/*{ "multicast_id":7680139367771848000,
"success":0,
"failure":4,
"canonical_ids":0,
"results":[ {"error":"InvalidRegistration"},
{"error":"InvalidRegistration"},
{"error":"InvalidRegistration"},
{"error":"InvalidRegistration"}] }*/

let tokens = options.registrationTokens;
const response = {
multicast_id: 7680139367771848000,
success: tokens.length,
failure: 0,
cannonical_ids: 0,
results: tokens.map((token, index) => {
return {
message_id: 7680139367771848000+''+index,
registration_id: token
}
})
}
process.nextTick(() => {
cb(null, response);
});
});
}

describe('GCM', () => {
it('can initialize', (done) => {
var args = {
Expand All @@ -15,6 +45,16 @@ describe('GCM', () => {
expect(function() {
new GCM(args);
}).toThrow();
args = {
apisKey: 'apiKey'
};
expect(function() {
new GCM(args);
}).toThrow();
args = undefined;
expect(function() {
new GCM(args);
}).toThrow();
done();
});

Expand Down Expand Up @@ -194,19 +234,77 @@ describe('GCM', () => {
deviceToken: 'token4'
}
];

mockSender(gcm);
gcm.send(data, devices).then((response) => {
expect(Array.isArray(response)).toBe(true);
expect(response.length).toEqual(devices.length);
expect(response.length).toEqual(4);
response.forEach((res, index) => {
expect(res.transmitted).toEqual(false);
expect(res.transmitted).toEqual(true);
expect(res.device).toEqual(devices[index]);
})
done();
})
});

it('can send GCM request with slices', (done) => {
let originalMax = GCM.GCMRegistrationTokensMax;
GCM.GCMRegistrationTokensMax = 2;
var gcm = new GCM({
apiKey: 'apiKey'
});
// Mock data
var expirationTime = 2454538822113;
var data = {
'expiration_time': expirationTime,
'data': {
'alert': 'alert'
}
}
// Mock devices
var devices = [
{
deviceToken: 'token'
},
{
deviceToken: 'token2'
},
{
deviceToken: 'token3'
},
{
deviceToken: 'token4'
},
{
deviceToken: 'token5'
},
{
deviceToken: 'token6'
},
{
deviceToken: 'token7'
},
{
deviceToken: 'token8'
}
];
spyOn(gcm, 'send').and.callThrough();
gcm.send(data, devices).then((response) => {
expect(Array.isArray(response)).toBe(true);
expect(response.length).toEqual(devices.length);
expect(response.length).toEqual(8);
response.forEach((res, index) => {
expect(res.transmitted).toEqual(false);
expect(res.device).toEqual(devices[index]);
});
// 1 original call
// 4 calls (1 per slice of 2)
expect(gcm.send.calls.count()).toBe(1+4);
GCM.GCMRegistrationTokensMax = originalMax;
done();
})
});

it('can slice devices', (done) => {
// Mock devices
var devices = [makeDevice(1), makeDevice(2), makeDevice(3), makeDevice(4)];
Expand Down
9 changes: 8 additions & 1 deletion spec/MockAPNConnection.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@ module.exports = function (args) {
let emitter = new EventEmitter();
emitter.options = args;
emitter.pushNotification = function(push, devices) {
if (!Array.isArray(devices)) {
devices = [devices];
}
devices.forEach((device) => {
process.nextTick(() => {
emitter.emit('transmitted', push, device);
if (args.shouldFailTransmissions) {
emitter.emit('transmissionError', -1, push, device);
} else {
emitter.emit('transmitted', push, device);
}
});
});
};
Expand Down
93 changes: 93 additions & 0 deletions spec/ParsePushAdapter.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,99 @@ describe('ParsePushAdapter', () => {
})
});

it('reports properly failures when all transmissions have failed', (done) => {
var pushConfig = {
ios: [
{
cert: 'cert.cer',
key: 'key.pem',
production: false,
shouldFailTransmissions: true,
bundleId: 'iosbundleId'
}
]
};
var installations = [
{
deviceType: 'ios',
deviceToken: '0d72a1baa92a2febd9a254cbd6584f750c70b2350af5fc9052d1d12584b738e6',
appIdentifier: 'iosbundleId'
}
];

var parsePushAdapter = new ParsePushAdapter(pushConfig);
parsePushAdapter.send({data: {alert: 'some'}}, installations).then((results) => {
expect(Array.isArray(results)).toBe(true);

// 2x iOS, 1x android, 1x osx, 1x tvos
expect(results.length).toBe(1);
const result = results[0];
expect(typeof result.device).toBe('object');
if (!result.device) {
fail('result should have device');
return;
}
const device = result.device;
expect(typeof device.deviceType).toBe('string');
expect(typeof device.deviceToken).toBe('string');
expect(result.transmitted).toBe(false);
expect(result.response.error.indexOf('APNS can not find vaild connection for ')).toBe(0);
done();
}).catch((err) => {
fail('Should not fail');
done();
})
});

it('reports properly select connection', (done) => {
var pushConfig = {
ios: [
{
cert: 'cert.cer',
key: 'key.pem',
production: false,
shouldFailTransmissions: true,
bundleId: 'iosbundleId'
},
{
cert: 'cert.cer',
key: 'key.pem',
production: false,
bundleId: 'iosbundleId'
}
]
};
var installations = [
{
deviceType: 'ios',
deviceToken: '0d72a1baa92a2febd9a254cbd6584f750c70b2350af5fc9052d1d12584b738e6',
appIdentifier: 'iosbundleId'
}
];

var parsePushAdapter = new ParsePushAdapter(pushConfig);
parsePushAdapter.send({data: {alert: 'some'}}, installations).then((results) => {
expect(Array.isArray(results)).toBe(true);

// 2x iOS, 1x android, 1x osx, 1x tvos
expect(results.length).toBe(1);
const result = results[0];
expect(typeof result.device).toBe('object');
if (!result.device) {
fail('result should have device');
return;
}
const device = result.device;
expect(typeof device.deviceType).toBe('string');
expect(typeof device.deviceToken).toBe('string');
expect(result.transmitted).toBe(true);
done();
}).catch((err) => {
fail('Should not fail');
done();
})
});

it('properly marks not transmitter when sender is missing', (done) => {
var pushConfig = {
android: {
Expand Down
42 changes: 20 additions & 22 deletions src/APNS.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,14 @@ function APNS(args) {
});

conn.on('transmitted', function(notification, device) {
if (device.callback) {
device.callback({
notification: notification,
transmitted: true,
device: {
deviceType: device.deviceType,
deviceToken: device.token.toString('hex')
}
});
}
device.callback({
notification: notification,
transmitted: true,
device: {
deviceType: device.deviceType,
deviceToken: device.token.toString('hex')
}
});
log.verbose(LOG_PREFIX, 'APNS Connection %d Notification transmitted to %s', conn.index, device.token.toString('hex'));
});

Expand Down Expand Up @@ -126,6 +124,7 @@ APNS.prototype.send = function(data, devices) {
let apnDevice = new apn.Device(device.deviceToken);
apnDevice.deviceType = device.deviceType;
apnDevice.connIndex = qualifiedConnIndexs[0];
/* istanbul ignore else */
if (device.appIdentifier) {
apnDevice.appIdentifier = device.appIdentifier;
}
Expand Down Expand Up @@ -173,18 +172,16 @@ function handleTransmissionError(conns, errCode, notification, apnDevice) {
}
// There is no more available conns, we give up in this case
if (newConnIndex < 0 || newConnIndex >= conns.length) {
if (apnDevice.callback) {
log.error(LOG_PREFIX, `cannot find vaild connection for ${apnDevice.token.toString('hex')}`);
apnDevice.callback({
response: {error: `APNS can not find vaild connection for ${apnDevice.token.toString('hex')}`, code: errCode},
status: errCode,
transmitted: false,
device: {
deviceType: apnDevice.deviceType,
deviceToken: apnDevice.token.toString('hex')
}
});
}
log.error(LOG_PREFIX, `cannot find vaild connection for ${apnDevice.token.toString('hex')}`);
apnDevice.callback({
response: {error: `APNS can not find vaild connection for ${apnDevice.token.toString('hex')}`, code: errCode},
status: errCode,
transmitted: false,
device: {
deviceType: apnDevice.deviceType,
deviceToken: apnDevice.token.toString('hex')
}
});
return;
}

Expand Down Expand Up @@ -258,6 +255,7 @@ function generateNotification(coreData, expirationTime) {

APNS.generateNotification = generateNotification;

/* istanbul ignore else */
if (process.env.TESTING) {
APNS.chooseConns = chooseConns;
APNS.handleTransmissionError = handleTransmissionError;
Expand Down
Loading