@parse/node-apn
Version:
An interface to the Apple Push Notification service for Node.js
359 lines (295 loc) • 12.2 kB
JavaScript
const sinon = require('sinon');
describe('config', function () {
let config, fakes;
beforeEach(function () {
fakes = {
logger: sinon.spy(),
prepareCertificate: sinon.stub(),
prepareToken: sinon.stub(),
prepareCA: sinon.stub(),
};
config = require('../lib/config')(fakes);
});
it('supplies sensible defaults', function () {
expect(config()).to.deep.equal({
token: null,
cert: 'cert.pem',
key: 'key.pem',
ca: null,
pfx: null,
passphrase: null,
production: false,
address: 'api.sandbox.push.apple.com',
port: 443,
manageChannelsAddress: 'api-manage-broadcast.sandbox.push.apple.com',
manageChannelsPort: 2195,
proxy: null,
manageChannelsProxy: null,
rejectUnauthorized: true,
connectionRetryLimit: 3,
heartBeat: 60000,
requestTimeout: 5000,
});
});
describe('address configuration', function () {
let originalEnv;
before(function () {
originalEnv = process.env.NODE_ENV;
});
after(function () {
process.env.NODE_ENV = originalEnv;
});
beforeEach(function () {
process.env.NODE_ENV = '';
});
it('should use api.sandbox.push.apple.com as the default connection address', function () {
expect(config()).to.have.property('address', 'api.sandbox.push.apple.com');
});
it('should use api.push.apple.com when NODE_ENV=production', function () {
process.env.NODE_ENV = 'production';
expect(config()).to.have.property('address', 'api.push.apple.com');
});
it('should give precedence to production flag over NODE_ENV=production', function () {
process.env.NODE_ENV = 'production';
expect(config({ production: false })).to.have.property(
'address',
'api.sandbox.push.apple.com'
);
});
it('should use api.push.apple.com when production:true', function () {
expect(config({ production: true })).to.have.property('address', 'api.push.apple.com');
});
it('should use a custom address when passed', function () {
expect(config({ address: 'testaddress' })).to.have.property('address', 'testaddress');
});
describe('address is passed', function () {
it('sets production to true when using production address', function () {
expect(config({ address: 'api.push.apple.com' })).to.have.property('production', true);
});
it('sets production to false when using sandbox address', function () {
process.env.NODE_ENV = 'production';
expect(config({ address: 'api.sandbox.push.apple.com' })).to.have.property(
'production',
false
);
});
});
});
describe('manageChannelsAddress configuration', function () {
let originalEnv;
before(function () {
originalEnv = process.env.NODE_ENV;
});
after(function () {
process.env.NODE_ENV = originalEnv;
});
beforeEach(function () {
process.env.NODE_ENV = '';
});
it('should use api-manage-broadcast.sandbox.push.apple.com as the default connection address', function () {
const testConfig = config();
expect(testConfig).to.have.property(
'manageChannelsAddress',
'api-manage-broadcast.sandbox.push.apple.com'
);
expect(testConfig).to.have.property('manageChannelsPort', 2195);
});
it('should use api-manage-broadcast.push.apple.com when NODE_ENV=production', function () {
process.env.NODE_ENV = 'production';
const testConfig = config();
expect(testConfig).to.have.property(
'manageChannelsAddress',
'api-manage-broadcast.push.apple.com'
);
expect(testConfig).to.have.property('manageChannelsPort', 2196);
});
it('should give precedence to production flag over NODE_ENV=production', function () {
process.env.NODE_ENV = 'production';
const testConfig = config({ production: false });
expect(testConfig).to.have.property(
'manageChannelsAddress',
'api-manage-broadcast.sandbox.push.apple.com'
);
expect(testConfig).to.have.property('manageChannelsPort', 2195);
});
it('should use api-manage-broadcast.push.apple.com when production:true', function () {
const testConfig = config({ production: true });
expect(testConfig).to.have.property(
'manageChannelsAddress',
'api-manage-broadcast.push.apple.com'
);
expect(testConfig).to.have.property('manageChannelsPort', 2196);
});
it('should use a custom address and default port when passed', function () {
const testAddress = 'testaddress';
const testPort = 2195;
const testConfig = config({ manageChannelsAddress: testAddress });
expect(testConfig).to.have.property('manageChannelsAddress', testAddress);
expect(testConfig).to.have.property('manageChannelsPort', testPort);
});
it('should use a custom address and port when passed', function () {
const testAddress = 'testaddress';
const testPort = 445;
const testConfig = config({
manageChannelsAddress: testAddress,
manageChannelsPort: testPort,
});
expect(testConfig).to.have.property('manageChannelsAddress', testAddress);
expect(testConfig).to.have.property('manageChannelsPort', testPort);
});
});
describe('credentials', function () {
context('`token` not supplied, use certificate', function () {
describe('passphrase', function () {
it('throws an error when supplied passphrase is not a string', function () {
expect(() => config({ passphrase: 123 })).to.throw('Passphrase must be a string');
});
it('does not throw when passphrase is a string', function () {
expect(() => config({ passphrase: 'seekrit' })).to.not.throw();
});
it('does not throw when passphrase is not supplied', function () {
expect(() => config({})).to.not.throw();
});
});
context('pfx value is supplied without cert and key', function () {
it('includes the value of `pfx`', function () {
expect(config({ pfx: 'apn.pfx' })).to.have.property('pfx', 'apn.pfx');
});
it('does not include a value for `cert`', function () {
expect(config({ pfx: 'apn.pfx' }).cert).to.be.undefined;
});
it('does not include a value for `key`', function () {
expect(config({ pfx: 'apn.pfx' }).key).to.be.undefined;
});
});
context('pfx value is supplied along with a cert and key', function () {
it('includes the value of `pfx`', function () {
expect(config({ pfx: 'apn.pfx', cert: 'cert.pem', key: 'key.pem' })).to.have.property(
'pfx',
'apn.pfx'
);
});
it('does not include a value for `cert`', function () {
expect(config({ pfx: 'apn.pfx', cert: 'cert.pem', key: 'key.pem' })).to.have.property(
'cert',
'cert.pem'
);
});
it('does not include a value for `key`', function () {
expect(config({ pfx: 'apn.pfx', cert: 'cert.pem', key: 'key.pem' })).to.have.property(
'key',
'key.pem'
);
});
});
context('pfxData value is supplied without cert and key', function () {
it('includes the value of `pfxData`', function () {
expect(config({ pfxData: 'apnData' })).to.have.property('pfxData', 'apnData');
});
it('does not include a value for `cert`', function () {
expect(config({ pfxData: 'apnData' }).cert).to.be.undefined;
});
it('does not include a value for `key`', function () {
expect(config({ pfxData: 'apnData' }).key).to.be.undefined;
});
});
context('pfxData value is supplied along with a cert and key', function () {
it('includes the value of `pfxData`', function () {
expect(config({ pfxData: 'apnData', cert: 'cert.pem', key: 'key.pem' })).to.have.property(
'pfxData',
'apnData'
);
});
it('does not include a value for `cert`', function () {
expect(config({ pfxData: 'apnData', cert: 'cert.pem', key: 'key.pem' })).to.have.property(
'cert',
'cert.pem'
);
});
it('does not include a value for `key`', function () {
expect(config({ pfxData: 'apnData', cert: 'cert.pem', key: 'key.pem' })).to.have.property(
'key',
'key.pem'
);
});
});
it('loads and validates the TLS credentials', function () {
fakes.prepareCertificate.returns({ cert: 'certData', key: 'keyData', pfx: 'pfxData' });
const configuration = config({});
expect(configuration).to.have.property('cert', 'certData');
expect(configuration).to.have.property('key', 'keyData');
expect(configuration).to.have.property('pfx', 'pfxData');
});
it('prepares the CA certificates', function () {
fakes.prepareCA.returns({ ca: 'certificate1' });
const configuration = config({});
expect(configuration).to.have.property('ca', 'certificate1');
});
});
context('`token` supplied', function () {
const key = 'testKey';
const keyId = 'abckeyId';
const teamId = 'teamId123';
// Clear these to ensure tls.Socket doesn't attempt to do client-auth
it('clears the `pfx` property', function () {
expect(config({ token: { key, keyId, teamId } })).to.not.have.property('pfx');
});
it('clears the `key` property', function () {
expect(config({ token: { key, keyId, teamId } })).to.not.have.property('key');
});
it('clears the `cert` property', function () {
expect(config({ token: { key, keyId, teamId } })).to.not.have.property('cert');
});
describe('token', function () {
it('throws an error if keyId is missing', function () {
expect(() => config({ token: { key, teamId } })).to.throw(/token\.keyId is missing/);
});
it('throws an error if keyId is not a string', function () {
expect(() => config({ token: { key, teamId, keyId: 123 } })).to.throw(
/token\.keyId must be a string/
);
});
it('throws an error if teamId is missing', function () {
expect(() => config({ token: { key, keyId } })).to.throw(/token\.teamId is missing/);
});
it('throws an error if teamId is not a string', function () {
expect(() => config({ token: { key, keyId, teamId: 123 } })).to.throw(
/token\.teamId must be a string/
);
});
});
it('does not invoke prepareCertificate', function () {
config({ token: { key, keyId, teamId } });
expect(fakes.prepareCertificate).to.have.not.been.called;
});
it('prepares a token generator', function () {
const testConfig = { key, keyId, teamId };
fakes.prepareToken.withArgs(sinon.match(testConfig)).returns(() => 'fake-token');
const configuration = config({ token: testConfig });
expect(fakes.prepareToken).to.have.been.called;
expect(configuration.token()).to.equal('fake-token');
});
it('prepares the CA certificates', function () {
fakes.prepareCA.returns({ ca: 'certificate1' });
const configuration = config({});
expect(configuration).to.have.property('ca', 'certificate1');
});
});
});
context('a null config value is passed', function () {
it('should log a message with `debug`', function () {
config({ address: null });
expect(fakes.logger).to.be.calledWith(
'Option [address] is null. This may cause unexpected behaviour.'
);
});
});
context('a config value is undefined', function () {
it('should log a message with `debug`', function () {
config({ anOption: undefined });
expect(fakes.logger).to.be.calledWith(
'Option [anOption] is undefined. This may cause unexpected behaviour.'
);
});
});
});