Skip to content

Commit

Permalink
update .push to support creation of custom instances
Browse files Browse the repository at this point in the history
  • Loading branch information
evanshortiss committed Sep 15, 2016
1 parent 3f1f96d commit 9af3c03
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 51 deletions.
39 changes: 22 additions & 17 deletions .jshintrc
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
{
"globals": {
"describe": true,
"it": true,
"beforeEach": true
},
"asi" : true,
"camelcase" : false,
"bitwise" : false,
"bitwise" : false,
"unused" : true,
"laxbreak" : true,
"laxcomma" : true,
"curly" : false,
"curly" : false,
"eqeqeq" : true,
"evil" : true,
"forin" : false,
"immed" : true,
"latedef" : false,
"newcap" : false,
"noarg" : true,
"evil" : true,
"expr" : true,
"forin" : false,
"immed" : true,
"latedef" : false,
"newcap" : false,
"noarg" : true,
"noempty" : true,
"nonew" : true,
"plusplus" : false,
"regexp" : true,
"undef" : false,
"strict" : false,
"plusplus" : false,
"regexp" : true,
"undef" : false,
"strict" : false,
"sub" : true,
"trailing" : true,
"node" : true,
"maxerr" : 100,
"indent" : 2
"trailing" : true,
"node" : true,
"maxerr" : 100,
"indent" : 2
}

3 changes: 2 additions & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ module.exports = function(grunt) {
/*'./test/test_web.js',*/
'./test/test_fhauth.js',
'./test/test_init.js',
'./test/test_log.js'
'./test/test_log.js',
'./test/test_fhpush.js'
];
var unit_args = _.map(tests, makeTestArgs);
var test_runner = '_mocha';
Expand Down
13 changes: 11 additions & 2 deletions lib/fhutils.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,18 @@ var assert = require('assert');

module.exports = function (cfg) {
assert.ok(cfg, 'cfg is undefined');
this.addAppApiKeyHeader = function (header) {

/**
* Injects an RHMAP API Key into a provided Object "headers" Object.
*
* By default this will use the API Key for the running node process, but
* passing a custom "value" is also supported.
* @param {Object} headers
* @param {String} [value]
*/
this.addAppApiKeyHeader = function (headers, value) {
if (cfg.fhapi && cfg.fhapi.appapikey && cfg.fhapi.appapikey.length > 0) {
header[cfg.APP_API_KEY_HEADER] = cfg.fhapi.appapikey;
headers[cfg.APP_API_KEY_HEADER] = value || cfg.fhapi.appapikey;
}
};

Expand Down
94 changes: 64 additions & 30 deletions lib/push.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,76 @@
var assert = require('assert'),
futils = require('./fhutils'),
aeroGearLoaded = false;
xtend = require('xtend'),
AeroGear = require('unifiedpush-node-sender');

module.exports = function (cfg) {
assert.ok(cfg, 'cfg is undefined');

var fhutils = new futils(cfg);
var millicoreProps = fhutils.getMillicoreProps();
var defaultPushSettings = getPushSettings(millicoreProps);

var props = fhutils.getMillicoreProps();
var headers = {
'X-Project-Id': props.widget,
'X-App-Id': props.instance
};
fhutils.addAppApiKeyHeader(headers);
var settings = {
url: 'https://' + props.millicore + ':' + props.port + '/box/api/unifiedpush/mbaas/',
applicationId: "fake", // we have to use fake ID, it will be added by supercore
masterSecret: "fake", // we have to use fake secret, it will be added by supercore
headers: headers
};
/**
* Generates settings to the used when creating an AeroGear.sender.
* @param {Object} opts [description]
* @return {Object}
*/
function getPushSettings (opts) {
assert.ok(opts, 'opts is undefined');

var headers = {
'X-Project-Id': opts.widget,
'X-App-Id': opts.instance
};

fhutils.addAppApiKeyHeader(headers, opts.appapikey);

return {
url: 'https://' + opts.millicore + ':' + opts.port + '/box/api/unifiedpush/mbaas/',
applicationId: "fake", // we have to use fake ID, it will be added by supercore
masterSecret: "fake", // we have to use fake secret, it will be added by supercore
headers: headers
};
}


/**
* Creates a push client (aka the $fh.push API)
* @param {Object} settings
* @return {Function}
*/
function getPushClient (settings) {
var sender = AeroGear.Sender(settings);

return function push(message, options, callback) {
if (!message) return callback(new Error("Missing required 'message' parameter"));
if (!options) return callback(new Error("Missing required 'options' parameter"));
if (!options.broadcast) {
if (!options.apps) return callback(new Error("Missing required 'options.apps' parameter while 'options.broadcast' not specified" + JSON.stringify(options)));
}

// $fh.push
var sender;
return function push(message, options, callback) {
if (!aeroGearLoaded) {
var AeroGear = require("unifiedpush-node-sender");
sender = AeroGear.Sender(settings);
aeroGearLoaded = true;
}

if (!message) return callback(new Error("Missing required 'message' parameter"));
if (!options) return callback(new Error("Missing required 'options' parameter"));
if (!options.broadcast) {
if (!options.apps) return callback(new Error("Missing required 'options.apps' parameter while 'options.broadcast' not specified" + JSON.stringify(options)));
}
if (sender){
sender.send(message, options, callback);
}
};
}
};

// $fh.push
var push = getPushClient(defaultPushSettings);

/**
* Allows developers to get a custom $fh.push instance that targets a
* specific project. Useful if this app is an MBaaS Service.
* @param {Object} overrides
* @return {Function}
*/
push.getPushClient = function (overrides) {
// Create settings for a new push client, but add in overrides such as using
// a custom widget and instance (project and cloud app id)
var settings = getPushSettings(
xtend(millicoreProps, overrides)
);

return getPushClient(settings);
};

return push;
};
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@
"stack-trace": "0.0.9",
"underscore": "1.7.0",
"unifiedpush-node-sender": "0.12.0",
"winston": "0.8.0"
"winston": "0.8.0",
"xtend": "4.0.1"
},
"devDependencies": {
"chai": "^3.5.0",
"clear-require": "1.0.1",
"express": "3.3.4",
"grunt": "^0.4.5",
"grunt-fh-build": "^0.5.0",
Expand All @@ -38,6 +40,7 @@
"nock": "0.22.1",
"plato": "^1.0.1",
"proxyquire": "1.4.0",
"sinon": "^1.17.5",
"valid-url": "1.0.9"
},
"scripts": {
Expand Down
143 changes: 143 additions & 0 deletions test/test_fhpush.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
'use strict';

var proxyquire = require('proxyquire')
, expect = require('chai').expect
, sinon = require('sinon');

describe('$fh.push', function () {

var mod, stubs, validCfg, senderStub, utilStubs;

var STUB_MAP = {
FHUTIL: './fhutils',
UPS: 'unifiedpush-node-sender'
};

beforeEach(function () {
// Each test should start with fresh copies of deps
require('clear-require').all();

senderStub = {
send: sinon.stub()
};

validCfg = {
fhapi: {
widget: 'a',
instance: 'b',
millicore: 'fake-domain.feedhenry.com',
port: 4567
}
};

utilStubs = {
getMillicoreProps: sinon.stub().returns(validCfg.fhapi),
addAppApiKeyHeader: sinon.stub()
};

stubs = {};

stubs[STUB_MAP.UPS] = {
Sender: sinon.stub().returns(senderStub)
};

stubs[STUB_MAP.FHUTIL] = sinon.stub().returns(utilStubs);

mod = proxyquire('lib/push', stubs);
});

describe('#push', function () {
it('should return a function', function () {
expect(mod(validCfg)).to.be.a('function');
expect(utilStubs.getMillicoreProps.callCount).to.equal(1);
expect(utilStubs.addAppApiKeyHeader.callCount).to.equal(1);
expect(stubs[STUB_MAP.UPS].Sender.callCount).to.equal(1);
});

it('should return an error - missing "messsage"', function (done) {
mod(validCfg)(null, null, function (err) {
expect(err).to.exist;
expect(err.toString()).to.contain(
'Missing required \'message\' parameter'
);

done();
});
});

it('should return an error - missing "options"', function (done) {
mod(validCfg)({ alert: 'fáilte!' }, null, function (err) {
expect(err).to.exist;
expect(err.toString()).to.contain(
'Missing required \'options\' parameter'
);

done();
});
});

it('should return an error - missing "options.app"', function (done) {
mod(validCfg)({ alert: 'slán' }, {}, function (err) {
expect(err).to.exist;
expect(err.toString()).to.contain(
'Missing required \'options.apps\' parameter'
);

done();
});
});

it('should send a push payload to the AeroGear.Sender', function (done) {
senderStub.send.yields(null);

var message = { alert: 'go raibh maith agat' };
var options = { broadcast: true };

mod(validCfg)(message, options, function (err) {
expect(err).to.not.exist;
expect(senderStub.send.getCall(0).args[0]).to.deep.equal(message);
expect(senderStub.send.getCall(0).args[1]).to.deep.equal(options);

done();
});
});
});

describe('#getPushClient', function () {
it('should return a push function using custom options', function () {
var fhpush = mod(validCfg);

var customOpts = {
widget: '123',
instance: '321',
appapikey: 'abc'
};

var customPush = fhpush.getPushClient(customOpts);

expect(customPush).to.be.a('function');
expect(customPush).to.not.equal(fhpush); // should be a new instance

// This should only ever be called on the first creation
expect(utilStubs.getMillicoreProps.callCount).to.equal(1);

// Should have called all of these twice, once for the default $fh.push
// and a second time for our custom setup
expect(utilStubs.addAppApiKeyHeader.callCount).to.equal(2);
expect(stubs[STUB_MAP.UPS].Sender.callCount).to.equal(2);

// Verify our custom options are being used
var senderSettings = stubs[STUB_MAP.UPS].Sender.getCall(1).args[0];
expect(senderSettings).to.deep.equal({
url: 'https://fake-domain.feedhenry.com:4567/box/api/unifiedpush/mbaas/',
applicationId: 'fake',
masterSecret: 'fake',
headers: {
'X-Project-Id': customOpts.widget,
'X-App-Id': customOpts.instance
}
});

});
});
});
Loading

0 comments on commit 9af3c03

Please sign in to comment.