From 22a07f31fde4b254eefd33abe90c43abb8b73f06 Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Wed, 1 Jun 2016 22:22:38 +0200 Subject: [PATCH 01/22] Remove sendNoRetry from being exposed --- lib/sender.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/sender.js b/lib/sender.js index 1fd87ed..2f96252 100644 --- a/lib/sender.js +++ b/lib/sender.js @@ -24,12 +24,12 @@ Sender.prototype.send = function(message, recipient, options, callback) { options = cleanOptions(options); if(options.retries == 0) { - return this.sendNoRetry(message, recipient, callback); + return sendNoRetry(this.key, this.options, message, recipient, callback); } var self = this; - this.sendNoRetry(message, recipient, function(err, response, attemptedRegTokens) { + sendNoRetry(this.key, this.options, message, recipient, function(err, response, attemptedRegTokens) { if (err) { if (typeof err === 'number' && err > 399 && err < 500) { debug("Error 4xx -- no use retrying. Something is wrong with the request (probably authentication?)"); @@ -125,7 +125,7 @@ function updateResponseMetaData(response, retriedResponse, unsentRegTokens) { response.failure -= unsentRegTokens.length - retriedResponse.failure; } -Sender.prototype.sendNoRetry = function(message, recipient, callback) { +function sendNoRetry(key, options, message, recipient, callback) { if(!callback) { callback = function() {}; } @@ -139,11 +139,11 @@ Sender.prototype.sendNoRetry = function(message, recipient, callback) { var request_options = defaultsDeep({ method: 'POST', headers: { - 'Authorization': 'key=' + this.key + 'Authorization': 'key=' + key }, uri: Constants.GCM_SEND_URI, json: body - }, this.options, { + }, options, { timeout: Constants.SOCKET_TIMEOUT }); @@ -165,8 +165,8 @@ Sender.prototype.sendNoRetry = function(message, recipient, callback) { } callback(null, resBodyJSON, body.registration_ids || [ body.to ]); }); - }.bind(this)); -}; + }); +} function getRequestBody(message, recipient, callback) { var body = cleanParams(message); From 3d8b4f67787f71fe2d50ab4626e73b3b2b3b5bcc Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Wed, 1 Jun 2016 22:38:56 +0200 Subject: [PATCH 02/22] Rename sendNoRetry -> sendMessage --- lib/sender.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/sender.js b/lib/sender.js index 2f96252..0a4c861 100644 --- a/lib/sender.js +++ b/lib/sender.js @@ -24,12 +24,12 @@ Sender.prototype.send = function(message, recipient, options, callback) { options = cleanOptions(options); if(options.retries == 0) { - return sendNoRetry(this.key, this.options, message, recipient, callback); + return sendMessage(this.key, this.options, message, recipient, callback); } var self = this; - sendNoRetry(this.key, this.options, message, recipient, function(err, response, attemptedRegTokens) { + sendMessage(this.key, this.options, message, recipient, function(err, response, attemptedRegTokens) { if (err) { if (typeof err === 'number' && err > 399 && err < 500) { debug("Error 4xx -- no use retrying. Something is wrong with the request (probably authentication?)"); @@ -125,7 +125,7 @@ function updateResponseMetaData(response, retriedResponse, unsentRegTokens) { response.failure -= unsentRegTokens.length - retriedResponse.failure; } -function sendNoRetry(key, options, message, recipient, callback) { +function sendMessage(key, options, message, recipient, callback) { if(!callback) { callback = function() {}; } From 81c27c3b62fe24393a6b00b530f391e0b8409e11 Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Wed, 1 Jun 2016 22:39:41 +0200 Subject: [PATCH 03/22] Remove unnecessary support for no callback (always called with callback!) --- lib/sender.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/sender.js b/lib/sender.js index 0a4c861..138fb92 100644 --- a/lib/sender.js +++ b/lib/sender.js @@ -126,10 +126,6 @@ function updateResponseMetaData(response, retriedResponse, unsentRegTokens) { } function sendMessage(key, options, message, recipient, callback) { - if(!callback) { - callback = function() {}; - } - getRequestBody(message, recipient, function(err, body) { if(err) { return callback(err); From 3d187693b9ce3b717227cb3a96e6d2e53d82fe81 Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Thu, 2 Jun 2016 11:50:07 +0200 Subject: [PATCH 04/22] Rewrite sendNoRetry tests to use send with retries: 0 --- test/unit/senderSpec.js | 48 ++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/test/unit/senderSpec.js b/test/unit/senderSpec.js index 90312a5..7f03054 100644 --- a/test/unit/senderSpec.js +++ b/test/unit/senderSpec.js @@ -38,7 +38,7 @@ describe('UNIT Sender', function () { }); }); - describe('sendNoRetry()', function () { + describe('send() without retries', function () { function setArgs(err, res, resBody) { args = { err: err, @@ -59,7 +59,7 @@ describe('UNIT Sender', function () { }; var sender = new Sender('mykey', options); var m = { data: {} }; - sender.sendNoRetry(m, '', function () {}); + sender.send(m, '', { retries: 0 }, function () {}); setTimeout(function() { expect(args.options.proxy).to.equal(options.proxy); expect(args.options.maxSockets).to.equal(options.maxSockets); @@ -80,7 +80,7 @@ describe('UNIT Sender', function () { }; var sender = new Sender('mykey', options); var m = { data: {} }; - sender.sendNoRetry(m, '', function () {}); + sender.send(m, '', { retries: 0 }, function () {}); setTimeout(function() { expect(args.options.method).to.not.equal(options.method); expect(args.options.headers).to.not.deep.equal(options.headers); @@ -98,7 +98,7 @@ describe('UNIT Sender', function () { }; var sender = new Sender('mykey', options); var m = { data: {} }; - sender.sendNoRetry(m, '', function () {}); + sender.send(m, '', { retries: 0 }, function () {}); setTimeout(function() { expect(args.options.headers.Authorization).to.not.equal(options.headers.Auhtorization); done(); @@ -113,7 +113,7 @@ describe('UNIT Sender', function () { }; var sender = new Sender('mykey', options); var m = { data: {} }; - sender.sendNoRetry(m, '', function () {}); + sender.send(m, '', { retries: 0 }, function () {}); setTimeout(function() { expect(args.options.headers.Custom).to.deep.equal(options.headers.Custom); done(); @@ -128,7 +128,7 @@ describe('UNIT Sender', function () { }; var sender = new Sender('mykey', options); var m = { data: {} }; - sender.sendNoRetry(m, '', function () {}); + sender.send(m, '', { retries: 0 }, function () {}); setTimeout(function() { expect(args.options.strictSSL).to.be.an('undefined'); done(); @@ -138,7 +138,7 @@ describe('UNIT Sender', function () { it('should set the API key of req object if passed in API key', function (done) { var sender = new Sender('myKey'); var m = { data: {} }; - sender.sendNoRetry(m, '', function () {}); + sender.send(m, '', { retries: 0 }, function () {}); setTimeout(function() { expect(args.options.headers.Authorization).to.equal('key=myKey'); done(); @@ -148,7 +148,7 @@ describe('UNIT Sender', function () { it('should send a JSON object as the body of the request', function (done) { var sender = new Sender('mykey'); var m = { collapseKey: 'Message', data: {} }; - sender.sendNoRetry(m, '', function () {}); + sender.send(m, '', { retries: 0 }, function () {}); setTimeout(function() { expect(args.options.json).to.be.a('object'); done(); @@ -166,7 +166,7 @@ describe('UNIT Sender', function () { } }; var sender = new Sender('mykey'); - sender.sendNoRetry(mess, '', function () {}); + sender.send(mess, '', { retries: 0 }, function () {}); setTimeout(function() { var body = args.options.json; expect(body.delay_while_idle).to.equal(mess.delay_while_idle); @@ -190,7 +190,7 @@ describe('UNIT Sender', function () { unknown_property: "hello" }; var sender = new Sender('mykey'); - sender.sendNoRetry(mess, '', function () {}); + sender.send(mess, '', { retries: 0 }, function () {}); setTimeout(function() { var body = args.options.json; expect(body.delay_while_idle).to.equal(undefined); @@ -206,7 +206,7 @@ describe('UNIT Sender', function () { it('should set the registration_ids to reg tokens implicitly passed in', function (done) { var sender = new Sender('myKey'); var m = { data: {} }; - sender.sendNoRetry(m, ["registration token 1", "registration token 2"], function () {}); + sender.send(m, ["registration token 1", "registration token 2"], { retries: 0 }, function () {}); setTimeout(function() { var body = args.options.json; expect(body.registration_ids).to.deep.equal(["registration token 1", "registration token 2"]); @@ -218,7 +218,7 @@ describe('UNIT Sender', function () { var sender = new Sender('myKey'); var m = { data: {} }; var regTokens = ["registration token 1", "registration token 2"]; - sender.sendNoRetry(m, { registrationIds: regTokens }, function () {}); + sender.send(m, { registrationIds: regTokens }, { retries: 0 }, function () {}); setTimeout(function() { var body = args.options.json; expect(body.registration_ids).to.deep.equal(regTokens); @@ -230,7 +230,7 @@ describe('UNIT Sender', function () { var sender = new Sender('myKey'); var m = { data: {} }; var regTokens = ["registration token 1", "registration token 2"]; - sender.sendNoRetry(m, { registrationTokens: regTokens }, function () {}); + sender.send(m, { registrationTokens: regTokens }, { retries: 0 }, function () {}); setTimeout(function() { var body = args.options.json; expect(body.registration_ids).to.deep.equal(regTokens); @@ -241,7 +241,7 @@ describe('UNIT Sender', function () { it('should set the to field if a single reg (or other) token is passed in', function(done) { var sender = new Sender('myKey'); var m = { data: {} }; - sender.sendNoRetry(m, "registration token 1", function () {}); + sender.send(m, "registration token 1", { retries: 0 }, function () {}); setTimeout(function() { var body = args.options.json; expect(body.to).to.deep.equal("registration token 1"); @@ -254,7 +254,7 @@ describe('UNIT Sender', function () { var sender = new Sender('myKey'); var m = { data: {} }; var token = "registration token 1"; - sender.sendNoRetry(m, token, function () {}); + sender.send(m, token, { retries: 0 }, function () {}); setTimeout(function() { var body = args.options.json; expect(body.to).to.deep.equal(token); @@ -267,7 +267,7 @@ describe('UNIT Sender', function () { var sender = new Sender('myKey'); var m = { data: {} }; var token = "registration token 1"; - sender.sendNoRetry(m, [ token ], function () {}); + sender.send(m, [ token ], { retries: 0 }, function () {}); setTimeout(function() { var body = args.options.json; expect(body.registration_ids).to.deep.equal([ token ]); @@ -279,7 +279,7 @@ describe('UNIT Sender', function () { it('should pass an error into callback if recipient is an empty object', function (done) { var callback = sinon.spy(); var sender = new Sender('myKey'); - sender.sendNoRetry({}, {}, callback); + sender.send({}, {}, { retries: 0 }, callback); setTimeout(function() { expect(callback.calledOnce).to.be.ok; expect(callback.args[0][0]).to.be.a('object'); @@ -290,7 +290,7 @@ describe('UNIT Sender', function () { it('should pass an error into callback if no recipient provided', function (done) { var callback = sinon.spy(); var sender = new Sender('myKey'); - sender.sendNoRetry({}, [], callback); + sender.send({}, [], { retries: 0 }, callback); setTimeout(function() { expect(callback.calledOnce).to.be.ok; expect(callback.args[0][0]).to.be.a('object'); @@ -303,7 +303,7 @@ describe('UNIT Sender', function () { sender = new Sender('myKey'); setArgs('an error', {}, {}); var m = { data: {} }; - sender.sendNoRetry(m, '', callback); + sender.send(m, '', { retries: 0 }, callback); setTimeout(function() { expect(callback.calledOnce).to.be.ok; expect(callback.calledWith('an error')).to.be.ok; @@ -316,7 +316,7 @@ describe('UNIT Sender', function () { sender = new Sender('myKey'); setArgs(null, { statusCode: 500 }, {}); var m = { data: {} }; - sender.sendNoRetry(m, '', callback); + sender.send(m, '', { retries: 0 }, callback); setTimeout(function() { expect(callback.calledOnce).to.be.ok; expect(callback.args[0][0]).to.equal(500); @@ -329,7 +329,7 @@ describe('UNIT Sender', function () { sender = new Sender('myKey'); setArgs(null, { statusCode: 401 }, {}); var m = { data: {} }; - sender.sendNoRetry(m, '', callback); + sender.send(m, '', { retries: 0 }, callback); setTimeout(function() { expect(callback.calledOnce).to.be.ok; expect(callback.args[0][0]).to.equal(401); @@ -342,7 +342,7 @@ describe('UNIT Sender', function () { sender = new Sender('myKey'); setArgs(null, { statusCode: 400 }, {}); var m = { data: {} }; - sender.sendNoRetry(m, '', callback); + sender.send(m, '', { retries: 0 }, callback); setTimeout(function() { expect(callback.calledOnce).to.be.ok; expect(callback.args[0][0]).to.equal(400); @@ -356,7 +356,7 @@ describe('UNIT Sender', function () { parseError = {error: 'Failed to parse JSON'}; setArgs(parseError, null, null); var m = { data: {} }; - sender.sendNoRetry(m, '', callback); + sender.send(m, '', { retries: 0 }, callback); setTimeout(function() { expect(callback.calledOnce).to.be.ok; expect(callback.args[0][0]).to.deep.equal(parseError); @@ -373,7 +373,7 @@ describe('UNIT Sender', function () { var sender = new Sender('myKey'); setArgs(null, { statusCode: 200 }, resBody); var m = { data: {} }; - sender.sendNoRetry(m, '', callback); + sender.send(m, '', { retries: 0 }, callback); setTimeout(function() { expect(callback.calledOnce).to.be.ok; expect(callback.args[0][1]).to.deep.equal(resBody); From 0e6d133c4016d05fda81b50b2efb3289e83085e0 Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Thu, 2 Jun 2016 12:00:46 +0200 Subject: [PATCH 05/22] Extract sendMessageWithRetries function --- lib/sender.js | 60 ++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/lib/sender.js b/lib/sender.js index 138fb92..c359c74 100644 --- a/lib/sender.js +++ b/lib/sender.js @@ -27,15 +27,42 @@ Sender.prototype.send = function(message, recipient, options, callback) { return sendMessage(this.key, this.options, message, recipient, callback); } - var self = this; + sendMessageWithRetries(this, this.key, this.options, message, recipient, options, callback); +}; + +function cleanOptions(options) { + if(!options || typeof options != "object") { + var retries = 5; + if(typeof options == "number") { + retries = options; + } + return { + retries: retries, + backoff: Constants.BACKOFF_INITIAL_DELAY + }; + } + + if(typeof options.retries != "number") { + options.retries = 5; + } + if(typeof options.backoff != "number") { + options.backoff = Constants.BACKOFF_INITIAL_DELAY; + } + if (options.backoff > Constants.MAX_BACKOFF_DELAY) { + options.backoff = Constants.MAX_BACKOFF_DELAY; + } + + return options; +} - sendMessage(this.key, this.options, message, recipient, function(err, response, attemptedRegTokens) { +function sendMessageWithRetries(self, key, senderOptions, message, recipient, messageOptions, callback) { + sendMessage(key, senderOptions, message, recipient, function(err, response, attemptedRegTokens) { if (err) { if (typeof err === 'number' && err > 399 && err < 500) { debug("Error 4xx -- no use retrying. Something is wrong with the request (probably authentication?)"); return callback(err); } - return retry(self, message, recipient, options, callback); + return retry(self, message, recipient, messageOptions, callback); } if(!response.results) { return callback(null, response); @@ -50,7 +77,7 @@ Sender.prototype.send = function(message, recipient, options, callback) { debug("Retrying " + unsentRegTokens.length + " unsent registration tokens"); - retry(self, message, unsentRegTokens, options, function(err, retriedResponse) { + retry(self, message, unsentRegTokens, messageOptions, function(err, retriedResponse) { if(err) { return callback(null, response); } @@ -59,31 +86,6 @@ Sender.prototype.send = function(message, recipient, options, callback) { }); }); }); -}; - -function cleanOptions(options) { - if(!options || typeof options != "object") { - var retries = 5; - if(typeof options == "number") { - retries = options; - } - return { - retries: retries, - backoff: Constants.BACKOFF_INITIAL_DELAY - }; - } - - if(typeof options.retries != "number") { - options.retries = 5; - } - if(typeof options.backoff != "number") { - options.backoff = Constants.BACKOFF_INITIAL_DELAY; - } - if (options.backoff > Constants.MAX_BACKOFF_DELAY) { - options.backoff = Constants.MAX_BACKOFF_DELAY; - } - - return options; } function retry(self, message, recipient, options, callback) { From 008e2fda1e8ee2f3a48cfeebfba963612b4466b9 Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Thu, 2 Jun 2016 12:05:22 +0200 Subject: [PATCH 06/22] Modify retry to use sendMessageWithRetries --- lib/sender.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/sender.js b/lib/sender.js index c359c74..bd195f0 100644 --- a/lib/sender.js +++ b/lib/sender.js @@ -62,7 +62,7 @@ function sendMessageWithRetries(self, key, senderOptions, message, recipient, me debug("Error 4xx -- no use retrying. Something is wrong with the request (probably authentication?)"); return callback(err); } - return retry(self, message, recipient, messageOptions, callback); + return retry(self, key, senderOptions, message, recipient, messageOptions, callback); } if(!response.results) { return callback(null, response); @@ -77,7 +77,7 @@ function sendMessageWithRetries(self, key, senderOptions, message, recipient, me debug("Retrying " + unsentRegTokens.length + " unsent registration tokens"); - retry(self, message, unsentRegTokens, messageOptions, function(err, retriedResponse) { + retry(self, key, senderOptions, message, unsentRegTokens, messageOptions, function(err, retriedResponse) { if(err) { return callback(null, response); } @@ -88,13 +88,13 @@ function sendMessageWithRetries(self, key, senderOptions, message, recipient, me }); } -function retry(self, message, recipient, options, callback) { +function retry(self, key, senderOptions, message, recipient, messageOptions, callback) { return setTimeout(function() { - self.send(message, recipient, { - retries: options.retries - 1, - backoff: options.backoff * 2 + sendMessageWithRetries(self, key, senderOptions, message, recipient, { + retries: messageOptions.retries - 1, + backoff: messageOptions.backoff * 2 }, callback); - }, options.backoff); + }, messageOptions.backoff); } function checkForBadTokens(results, originalRecipients, callback) { From cf7b494cb52d90bddbfbcabd24812f001e441774 Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Thu, 2 Jun 2016 12:05:43 +0200 Subject: [PATCH 07/22] Added a note about a case that seems odd --- lib/sender.js | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/sender.js b/lib/sender.js index bd195f0..0d88ad9 100644 --- a/lib/sender.js +++ b/lib/sender.js @@ -64,6 +64,7 @@ function sendMessageWithRetries(self, key, senderOptions, message, recipient, me } return retry(self, key, senderOptions, message, recipient, messageOptions, callback); } + //TODO: Figure out why this case exists -- should it be removed? if(!response.results) { return callback(null, response); } From 0236fbf0ec3835a39fd8a4bb3bacbde95ba3a176 Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Thu, 2 Jun 2016 12:07:24 +0200 Subject: [PATCH 08/22] Remove self argument from retry and sendMessageWithRetries --- lib/sender.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/sender.js b/lib/sender.js index 0d88ad9..bff0af2 100644 --- a/lib/sender.js +++ b/lib/sender.js @@ -27,7 +27,7 @@ Sender.prototype.send = function(message, recipient, options, callback) { return sendMessage(this.key, this.options, message, recipient, callback); } - sendMessageWithRetries(this, this.key, this.options, message, recipient, options, callback); + sendMessageWithRetries(this.key, this.options, message, recipient, options, callback); }; function cleanOptions(options) { @@ -55,14 +55,14 @@ function cleanOptions(options) { return options; } -function sendMessageWithRetries(self, key, senderOptions, message, recipient, messageOptions, callback) { +function sendMessageWithRetries(key, senderOptions, message, recipient, messageOptions, callback) { sendMessage(key, senderOptions, message, recipient, function(err, response, attemptedRegTokens) { if (err) { if (typeof err === 'number' && err > 399 && err < 500) { debug("Error 4xx -- no use retrying. Something is wrong with the request (probably authentication?)"); return callback(err); } - return retry(self, key, senderOptions, message, recipient, messageOptions, callback); + return retry(key, senderOptions, message, recipient, messageOptions, callback); } //TODO: Figure out why this case exists -- should it be removed? if(!response.results) { @@ -78,7 +78,7 @@ function sendMessageWithRetries(self, key, senderOptions, message, recipient, me debug("Retrying " + unsentRegTokens.length + " unsent registration tokens"); - retry(self, key, senderOptions, message, unsentRegTokens, messageOptions, function(err, retriedResponse) { + retry(key, senderOptions, message, unsentRegTokens, messageOptions, function(err, retriedResponse) { if(err) { return callback(null, response); } @@ -89,9 +89,9 @@ function sendMessageWithRetries(self, key, senderOptions, message, recipient, me }); } -function retry(self, key, senderOptions, message, recipient, messageOptions, callback) { +function retry(key, senderOptions, message, recipient, messageOptions, callback) { return setTimeout(function() { - sendMessageWithRetries(self, key, senderOptions, message, recipient, { + sendMessageWithRetries(key, senderOptions, message, recipient, { retries: messageOptions.retries - 1, backoff: messageOptions.backoff * 2 }, callback); From d125924554f695cae19c7d4b1ce20444c12668fc Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Thu, 2 Jun 2016 12:14:56 +0200 Subject: [PATCH 09/22] Get request body early on, simply pass it through --- lib/sender.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/sender.js b/lib/sender.js index bff0af2..72d6f48 100644 --- a/lib/sender.js +++ b/lib/sender.js @@ -23,11 +23,16 @@ Sender.prototype.send = function(message, recipient, options, callback) { } options = cleanOptions(options); + getRequestBody(message, recipient, function(err, body) { + if(err) { + return callback(err); + } if(options.retries == 0) { - return sendMessage(this.key, this.options, message, recipient, callback); + return sendMessage(this.key, this.options, body, callback); } - sendMessageWithRetries(this.key, this.options, message, recipient, options, callback); + sendMessageWithRetries(this.key, this.options, body, options, callback); + }.bind(this)); }; function cleanOptions(options) { @@ -55,14 +60,14 @@ function cleanOptions(options) { return options; } -function sendMessageWithRetries(key, senderOptions, message, recipient, messageOptions, callback) { - sendMessage(key, senderOptions, message, recipient, function(err, response, attemptedRegTokens) { +function sendMessageWithRetries(key, senderOptions, body, messageOptions, callback) { + sendMessage(key, senderOptions, body, function(err, response, attemptedRegTokens) { if (err) { if (typeof err === 'number' && err > 399 && err < 500) { debug("Error 4xx -- no use retrying. Something is wrong with the request (probably authentication?)"); return callback(err); } - return retry(key, senderOptions, message, recipient, messageOptions, callback); + return retry(key, senderOptions, body, messageOptions, callback); } //TODO: Figure out why this case exists -- should it be removed? if(!response.results) { @@ -78,7 +83,8 @@ function sendMessageWithRetries(key, senderOptions, message, recipient, messageO debug("Retrying " + unsentRegTokens.length + " unsent registration tokens"); - retry(key, senderOptions, message, unsentRegTokens, messageOptions, function(err, retriedResponse) { + body.registration_ids = unsentRegTokens; + retry(key, senderOptions, body, messageOptions, function(err, retriedResponse) { if(err) { return callback(null, response); } @@ -89,9 +95,9 @@ function sendMessageWithRetries(key, senderOptions, message, recipient, messageO }); } -function retry(key, senderOptions, message, recipient, messageOptions, callback) { +function retry(key, senderOptions, body, messageOptions, callback) { return setTimeout(function() { - sendMessageWithRetries(key, senderOptions, message, recipient, { + sendMessageWithRetries(key, senderOptions, body, { retries: messageOptions.retries - 1, backoff: messageOptions.backoff * 2 }, callback); @@ -128,12 +134,7 @@ function updateResponseMetaData(response, retriedResponse, unsentRegTokens) { response.failure -= unsentRegTokens.length - retriedResponse.failure; } -function sendMessage(key, options, message, recipient, callback) { - getRequestBody(message, recipient, function(err, body) { - if(err) { - return callback(err); - } - +function sendMessage(key, options, body, callback) { //Build request options, allowing some to be overridden var request_options = defaultsDeep({ method: 'POST', @@ -164,7 +165,6 @@ function sendMessage(key, options, message, recipient, callback) { } callback(null, resBodyJSON, body.registration_ids || [ body.to ]); }); - }); } function getRequestBody(message, recipient, callback) { From d4eec160882a219f17ee9962699767e944ba43d5 Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Thu, 2 Jun 2016 12:15:46 +0200 Subject: [PATCH 10/22] fix indentation --- lib/sender.js | 67 +++++++++++++++++++++++++-------------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/lib/sender.js b/lib/sender.js index 72d6f48..d1f21cf 100644 --- a/lib/sender.js +++ b/lib/sender.js @@ -27,11 +27,10 @@ Sender.prototype.send = function(message, recipient, options, callback) { if(err) { return callback(err); } - if(options.retries == 0) { - return sendMessage(this.key, this.options, body, callback); - } - - sendMessageWithRetries(this.key, this.options, body, options, callback); + if(options.retries == 0) { + return sendMessage(this.key, this.options, body, callback); + } + sendMessageWithRetries(this.key, this.options, body, options, callback); }.bind(this)); }; @@ -135,36 +134,36 @@ function updateResponseMetaData(response, retriedResponse, unsentRegTokens) { } function sendMessage(key, options, body, callback) { - //Build request options, allowing some to be overridden - var request_options = defaultsDeep({ - method: 'POST', - headers: { - 'Authorization': 'key=' + key - }, - uri: Constants.GCM_SEND_URI, - json: body - }, options, { - timeout: Constants.SOCKET_TIMEOUT - }); + //Build request options, allowing some to be overridden + var request_options = defaultsDeep({ + method: 'POST', + headers: { + 'Authorization': 'key=' + key + }, + uri: Constants.GCM_SEND_URI, + json: body + }, options, { + timeout: Constants.SOCKET_TIMEOUT + }); - request(request_options, function (err, res, resBodyJSON) { - if (err) { - return callback(err); - } - if (res.statusCode >= 500) { - debug('GCM service is unavailable (500)'); - return callback(res.statusCode); - } - if (res.statusCode === 401) { - debug('Unauthorized (401). Check that your API token is correct.'); - return callback(res.statusCode); - } - if (res.statusCode !== 200) { - debug('Invalid request (' + res.statusCode + '): ' + resBodyJSON); - return callback(res.statusCode); - } - callback(null, resBodyJSON, body.registration_ids || [ body.to ]); - }); + request(request_options, function (err, res, resBodyJSON) { + if (err) { + return callback(err); + } + if (res.statusCode >= 500) { + debug('GCM service is unavailable (500)'); + return callback(res.statusCode); + } + if (res.statusCode === 401) { + debug('Unauthorized (401). Check that your API token is correct.'); + return callback(res.statusCode); + } + if (res.statusCode !== 200) { + debug('Invalid request (' + res.statusCode + '): ' + resBodyJSON); + return callback(res.statusCode); + } + callback(null, resBodyJSON, body.registration_ids || [ body.to ]); + }); } function getRequestBody(message, recipient, callback) { From d174ce752ecaeaed849207dd3eb6a03dc0a09997 Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Thu, 2 Jun 2016 12:29:23 +0200 Subject: [PATCH 11/22] Build requestOptions early and pass around (instead of building for each request! --- lib/sender.js | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/lib/sender.js b/lib/sender.js index d1f21cf..387e459 100644 --- a/lib/sender.js +++ b/lib/sender.js @@ -9,8 +9,15 @@ function Sender(key, options) { return new Sender(key, options); } - this.key = key; - this.options = options || {}; + this.requestOptions = defaultsDeep({ + method: 'POST', + headers: { + 'Authorization': 'key=' + key + }, + uri: Constants.GCM_SEND_URI + }, options, { + timeout: Constants.SOCKET_TIMEOUT + }); } Sender.prototype.send = function(message, recipient, options, callback) { @@ -28,9 +35,9 @@ Sender.prototype.send = function(message, recipient, options, callback) { return callback(err); } if(options.retries == 0) { - return sendMessage(this.key, this.options, body, callback); + return sendMessage(this.requestOptions, body, callback); } - sendMessageWithRetries(this.key, this.options, body, options, callback); + sendMessageWithRetries(this.requestOptions, body, options, callback); }.bind(this)); }; @@ -59,14 +66,14 @@ function cleanOptions(options) { return options; } -function sendMessageWithRetries(key, senderOptions, body, messageOptions, callback) { - sendMessage(key, senderOptions, body, function(err, response, attemptedRegTokens) { +function sendMessageWithRetries(requestOptions, body, messageOptions, callback) { + sendMessage(requestOptions, body, function(err, response, attemptedRegTokens) { if (err) { if (typeof err === 'number' && err > 399 && err < 500) { debug("Error 4xx -- no use retrying. Something is wrong with the request (probably authentication?)"); return callback(err); } - return retry(key, senderOptions, body, messageOptions, callback); + return retry(requestOptions, body, messageOptions, callback); } //TODO: Figure out why this case exists -- should it be removed? if(!response.results) { @@ -83,7 +90,7 @@ function sendMessageWithRetries(key, senderOptions, body, messageOptions, callba debug("Retrying " + unsentRegTokens.length + " unsent registration tokens"); body.registration_ids = unsentRegTokens; - retry(key, senderOptions, body, messageOptions, function(err, retriedResponse) { + retry(requestOptions, body, messageOptions, function(err, retriedResponse) { if(err) { return callback(null, response); } @@ -94,9 +101,9 @@ function sendMessageWithRetries(key, senderOptions, body, messageOptions, callba }); } -function retry(key, senderOptions, body, messageOptions, callback) { +function retry(requestOptions, body, messageOptions, callback) { return setTimeout(function() { - sendMessageWithRetries(key, senderOptions, body, { + sendMessageWithRetries(requestOptions, body, { retries: messageOptions.retries - 1, backoff: messageOptions.backoff * 2 }, callback); @@ -133,20 +140,9 @@ function updateResponseMetaData(response, retriedResponse, unsentRegTokens) { response.failure -= unsentRegTokens.length - retriedResponse.failure; } -function sendMessage(key, options, body, callback) { - //Build request options, allowing some to be overridden - var request_options = defaultsDeep({ - method: 'POST', - headers: { - 'Authorization': 'key=' + key - }, - uri: Constants.GCM_SEND_URI, - json: body - }, options, { - timeout: Constants.SOCKET_TIMEOUT - }); - - request(request_options, function (err, res, resBodyJSON) { +function sendMessage(requestOptions, body, callback) { + requestOptions.json = body; + request(requestOptions, function (err, res, resBodyJSON) { if (err) { return callback(err); } From e177346a8c2eeadf143de4c967066f1d66b02be7 Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Thu, 2 Jun 2016 12:30:42 +0200 Subject: [PATCH 12/22] Reorder functions --- lib/sender.js | 78 +++++++++++++++++++++++++-------------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/lib/sender.js b/lib/sender.js index 387e459..17f6445 100644 --- a/lib/sender.js +++ b/lib/sender.js @@ -66,6 +66,45 @@ function cleanOptions(options) { return options; } +function getRequestBody(message, recipient, callback) { + var body = cleanParams(message); + + if(typeof recipient == "string") { + body.to = recipient; + return nextTick(callback, null, body); + } + if(Array.isArray(recipient)) { + if(recipient.length < 1) { + return nextTick(callback, new Error('Empty recipient array passed!')); + } + body.registration_ids = recipient; + return nextTick(callback, null, body); + } + return nextTick(callback, new Error('Invalid recipient (' + recipient + ', type ' + typeof recipient + ') provided (must be array or string)!')); +} + +function cleanParams(raw) { + var params = {}; + Object.keys(raw).forEach(function(param) { + var paramOptions = messageOptions[param]; + if(!paramOptions) { + return console.warn("node-gcm ignored unknown message parameter " + param); + } + if(paramOptions.__argType != typeof raw[param]) { + return console.warn("node-gcm ignored wrongly typed message parameter " + param + " (was " + typeof raw[param] + ", expected " + paramOptions.__argType + ")"); + } + params[param] = raw[param]; + }); + return params; +} + +function nextTick(func) { + var args = Array.prototype.slice.call(arguments, 1); + process.nextTick(function() { + func.apply(this, args); + }.bind(this)); +} + function sendMessageWithRetries(requestOptions, body, messageOptions, callback) { sendMessage(requestOptions, body, function(err, response, attemptedRegTokens) { if (err) { @@ -162,43 +201,4 @@ function sendMessage(requestOptions, body, callback) { }); } -function getRequestBody(message, recipient, callback) { - var body = cleanParams(message); - - if(typeof recipient == "string") { - body.to = recipient; - return nextTick(callback, null, body); - } - if(Array.isArray(recipient)) { - if(recipient.length < 1) { - return nextTick(callback, new Error('Empty recipient array passed!')); - } - body.registration_ids = recipient; - return nextTick(callback, null, body); - } - return nextTick(callback, new Error('Invalid recipient (' + recipient + ', type ' + typeof recipient + ') provided (must be array or string)!')); -} - -function cleanParams(raw) { - var params = {}; - Object.keys(raw).forEach(function(param) { - var paramOptions = messageOptions[param]; - if(!paramOptions) { - return console.warn("node-gcm ignored unknown message parameter " + param); - } - if(paramOptions.__argType != typeof raw[param]) { - return console.warn("node-gcm ignored wrongly typed message parameter " + param + " (was " + typeof raw[param] + ", expected " + paramOptions.__argType + ")"); - } - params[param] = raw[param]; - }); - return params; -} - -function nextTick(func) { - var args = Array.prototype.slice.call(arguments, 1); - process.nextTick(function() { - func.apply(this, args); - }.bind(this)); -} - module.exports = Sender; From c558a7cf093f818085273121c8799d098e31f4b6 Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Thu, 2 Jun 2016 23:16:53 +0200 Subject: [PATCH 13/22] Remove an irrelevant return --- lib/sender.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sender.js b/lib/sender.js index 17f6445..df24c74 100644 --- a/lib/sender.js +++ b/lib/sender.js @@ -141,7 +141,7 @@ function sendMessageWithRetries(requestOptions, body, messageOptions, callback) } function retry(requestOptions, body, messageOptions, callback) { - return setTimeout(function() { + setTimeout(function() { sendMessageWithRetries(requestOptions, body, { retries: messageOptions.retries - 1, backoff: messageOptions.backoff * 2 From 7a0e08e9f491b2eb8c25465fb61b4165d1a31720 Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Thu, 2 Jun 2016 23:24:33 +0200 Subject: [PATCH 14/22] Removed redundant tests (now covered by send with retries: 0) --- test/unit/senderSpec.js | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/test/unit/senderSpec.js b/test/unit/senderSpec.js index 7f03054..8b033e9 100644 --- a/test/unit/senderSpec.js +++ b/test/unit/senderSpec.js @@ -422,36 +422,6 @@ describe('UNIT Sender', function () { Sender.prototype.sendNoRetry = restore.sendNoRetry; }); - it('should pass reg tokens to sendNoRetry, even if it is an empty array', function (done) { - var emptyRegTokenArray = []; - var callback = function(error) { - expect(args.reg_tokens).to.equal(emptyRegTokenArray); - done(); - }; - var sender = new Sender('myKey'); - sender.send({}, emptyRegTokenArray, 0, callback); - }); - - it('should pass reg tokens to sendNoRetry, even if it is an empty object', function (done) { - var emptyRegTokenObject = {}; - var callback = function(error) { - expect(args.reg_tokens).to.equal(emptyRegTokenObject); - done(); - }; - var sender = new Sender('myKey'); - sender.send({}, emptyRegTokenObject, 0, callback); - }); - - it('should pass reg tokens to sendNoRetry, even if some keys are invalid', function (done) { - var invalidRegTokenObject = { invalid: ['regToken'] }; - var callback = function(error) { - expect(args.reg_tokens).to.equal(invalidRegTokenObject); - done(); - }; - var sender = new Sender('myKey'); - sender.send({}, invalidRegTokenObject, 0, callback); - }); - it('should pass the message and the regToken to sendNoRetry on call', function () { var sender = new Sender('myKey'), message = { data: {} }, From e0a6969d013af110b4452e3ac791c2491902f5bd Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Thu, 2 Jun 2016 23:27:12 +0200 Subject: [PATCH 15/22] Dont try to mock sendNoRetry --- test/unit/senderSpec.js | 41 +++++++---------------------------------- 1 file changed, 7 insertions(+), 34 deletions(-) diff --git a/test/unit/senderSpec.js b/test/unit/senderSpec.js index 8b033e9..ce7667c 100644 --- a/test/unit/senderSpec.js +++ b/test/unit/senderSpec.js @@ -45,7 +45,7 @@ describe('UNIT Sender', function () { res: res, resBody: resBody }; - }; + } before(function() { setArgs(null, { statusCode: 200 }, {}); }); @@ -383,43 +383,16 @@ describe('UNIT Sender', function () { }); describe('send()', function () { - var restore = {}; - // Set args passed into sendNoRetry - function setArgs(err, response) { + function setArgs(err, res, resBody) { args = { err: err, - response: response, - tries: 0 - }; - }; - - before( function () { - restore.sendNoRetry = Sender.prototype.sendNoRetry; - Sender.prototype.sendNoRetry = function (message, reg_tokens, callback) { - args.message = message; - args.reg_tokens = reg_tokens; - args.tries++; - var nextResponse; - if(!args.response) { - nextResponse = args.response; - } - else if(args.response.length > 1) { - nextResponse = args.response.slice(0,1)[0]; - args.response = args.response.slice(1,args.response.length); - } - else if(args.response.length == 1) { - args.response = args.response[0]; - nextResponse = args.response; - } - else { - nextResponse = args.response; - } - callback( args.err, nextResponse, args.reg_tokens ); + res: res, + resBody: resBody }; - }); + } - after( function () { - Sender.prototype.sendNoRetry = restore.sendNoRetry; + before(function() { + setArgs(null, { statusCode: 200 }, {}); }); it('should pass the message and the regToken to sendNoRetry on call', function () { From e8dd0ffbccf01cc1c0feee6338cba0e036f0099f Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Thu, 2 Jun 2016 23:27:51 +0200 Subject: [PATCH 16/22] Removed some more redundant tests --- test/unit/senderSpec.js | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/test/unit/senderSpec.js b/test/unit/senderSpec.js index ce7667c..51c94ad 100644 --- a/test/unit/senderSpec.js +++ b/test/unit/senderSpec.js @@ -395,28 +395,6 @@ describe('UNIT Sender', function () { setArgs(null, { statusCode: 200 }, {}); }); - it('should pass the message and the regToken to sendNoRetry on call', function () { - var sender = new Sender('myKey'), - message = { data: {} }, - regToken = [24]; - setArgs(null, {}); - sender.send(message, regToken, 0, function () {}); - expect(args.message).to.equal(message); - expect(args.reg_tokens).to.equal(regToken); - expect(args.tries).to.equal(1); - }); - - it('should pass the message and the regTokens to sendNoRetry on call', function () { - var sender = new Sender('myKey'), - message = { data: {} }, - regTokens = [24, 34, 44]; - setArgs(null, {}); - sender.send(message, regTokens, 0, function () {}); - expect(args.message).to.equal(message); - expect(args.reg_tokens).to.equal(regTokens); - expect(args.tries).to.equal(1); - }); - it('should pass the response into callback if successful for token', function () { var callback = sinon.spy(), response = { success: true }, From 9c32fb2cfdcddc4aef7c9f9d780dfe2ce298b99d Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Thu, 2 Jun 2016 23:30:29 +0200 Subject: [PATCH 17/22] Make all send specs async --- test/unit/senderSpec.js | 44 ++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/test/unit/senderSpec.js b/test/unit/senderSpec.js index 51c94ad..6546254 100644 --- a/test/unit/senderSpec.js +++ b/test/unit/senderSpec.js @@ -395,48 +395,60 @@ describe('UNIT Sender', function () { setArgs(null, { statusCode: 200 }, {}); }); - it('should pass the response into callback if successful for token', function () { + it('should pass the response into callback if successful for token', function (done) { var callback = sinon.spy(), response = { success: true }, sender = new Sender('myKey'); setArgs(null, response); sender.send({}, [1], 0, callback); - expect(callback.calledOnce).to.be.ok; - expect(callback.args[0][1]).to.equal(response); - expect(args.tries).to.equal(1); + setTimeout(function() { + expect(callback.calledOnce).to.be.ok; + expect(callback.args[0][1]).to.equal(response); + expect(args.tries).to.equal(1); + done(); + }, 10); }); - it('should pass the response into callback if successful for tokens', function () { + it('should pass the response into callback if successful for tokens', function (done) { var callback = sinon.spy(), response = { success: true }, sender = new Sender('myKey'); setArgs(null, response); sender.send({}, [1, 2, 3], 0, callback); - expect(callback.calledOnce).to.be.ok; - expect(callback.args[0][1]).to.equal(response); - expect(args.tries).to.equal(1); + setTimeout(function() { + expect(callback.calledOnce).to.be.ok; + expect(callback.args[0][1]).to.equal(response); + expect(args.tries).to.equal(1); + done(); + }, 10); }); - it('should pass the error into callback if failure and no retry for token', function () { + it('should pass the error into callback if failure and no retry for token', function (done) { var callback = sinon.spy(), error = 'my error', sender = new Sender('myKey'); setArgs(error); sender.send({}, [1], 0, callback); - expect(callback.calledOnce).to.be.ok; - expect(callback.args[0][0]).to.equal(error); - expect(args.tries).to.equal(1); + setTimeout(function() { + expect(callback.calledOnce).to.be.ok; + expect(callback.args[0][0]).to.equal(error); + expect(args.tries).to.equal(1); + done(); + }, 10); }); - it('should pass the error into callback if failure and no retry for tokens', function () { + it('should pass the error into callback if failure and no retry for tokens', function (done) { var callback = sinon.spy(), error = 'my error', sender = new Sender('myKey'); setArgs(error); sender.send({}, [1, 2, 3], 0, callback); - expect(callback.calledOnce).to.be.ok; - expect(callback.args[0][0]).to.equal(error); - expect(args.tries).to.equal(1); + setTimeout(function() { + expect(callback.calledOnce).to.be.ok; + expect(callback.args[0][0]).to.equal(error); + expect(args.tries).to.equal(1); + done(); + }, 10); }); it('should retry number of times passed into call and do exponential backoff', function (done) { From 79873f8ee848329d27a3e553558dbb880e9c614c Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Wed, 8 Jun 2016 19:37:10 +0200 Subject: [PATCH 18/22] Break out of retry if there are no retries left! --- lib/sender.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/sender.js b/lib/sender.js index df24c74..ebce102 100644 --- a/lib/sender.js +++ b/lib/sender.js @@ -142,6 +142,9 @@ function sendMessageWithRetries(requestOptions, body, messageOptions, callback) function retry(requestOptions, body, messageOptions, callback) { setTimeout(function() { + if(messageOptions.retries <= 1) { + return sendMessage(requestOptions, body, callback); + } sendMessageWithRetries(requestOptions, body, { retries: messageOptions.retries - 1, backoff: messageOptions.backoff * 2 From 20fad62ada352e8cdc787f88cab1621d7e323deb Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Wed, 8 Jun 2016 19:37:40 +0200 Subject: [PATCH 19/22] Remove this one weird case that is good for naught --- lib/sender.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/sender.js b/lib/sender.js index ebce102..7a4c24f 100644 --- a/lib/sender.js +++ b/lib/sender.js @@ -114,10 +114,6 @@ function sendMessageWithRetries(requestOptions, body, messageOptions, callback) } return retry(requestOptions, body, messageOptions, callback); } - //TODO: Figure out why this case exists -- should it be removed? - if(!response.results) { - return callback(null, response); - } checkForBadTokens(response.results, attemptedRegTokens, function(err, unsentRegTokens, regTokenPositionMap) { if(err) { return callback(err); From 41b2d94a9631fff9a5742895b4c5ebdc89240560 Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Wed, 8 Jun 2016 19:40:22 +0200 Subject: [PATCH 20/22] Make send() tests work. This required some major changes to how the tests are structured, as I didnt want to be listening on what used to be "sendNoRetry". requestStub is now a sinon spy. it is reset before EVERY test (woops, before we only cleared state before each test CATEGORY) and how we expect some things has changed as a result of these structural changes --- test/unit/senderSpec.js | 85 ++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/test/unit/senderSpec.js b/test/unit/senderSpec.js index 6546254..d5bcbc0 100644 --- a/test/unit/senderSpec.js +++ b/test/unit/senderSpec.js @@ -9,10 +9,15 @@ var chai = require('chai'), describe('UNIT Sender', function () { // Use object to set arguments passed into callback var args = {}; - var requestStub = function (options, callback) { + var requestStub = sinon.spy(function (options, callback) { args.options = options; - return callback( args.err, args.res, args.resBody ); - }; + var resBody = args.resBody; + if(Array.isArray(args.resBody)) { + resBody = args.resBody[0]; + args.resBody = args.resBody.slice(1); + } + return callback( args.err, args.res, resBody ); + }); var Sender = proxyquire(senderPath, { 'request': requestStub }); describe('constructor', function () { @@ -46,7 +51,8 @@ describe('UNIT Sender', function () { resBody: resBody }; } - before(function() { + beforeEach(function() { + requestStub.reset(); setArgs(null, { statusCode: 200 }, {}); }); @@ -391,39 +397,52 @@ describe('UNIT Sender', function () { }; } - before(function() { + beforeEach(function() { + requestStub.reset(); setArgs(null, { statusCode: 200 }, {}); }); it('should pass the response into callback if successful for token', function (done) { var callback = sinon.spy(), - response = { success: true }, + response = { + success: 1, + failure: 0, + results: [ + { message_id: "something" } + ] + }, sender = new Sender('myKey'); - setArgs(null, response); - sender.send({}, [1], 0, callback); + setArgs(null, { statusCode: 200 }, response); + sender.send({}, [1], callback); setTimeout(function() { expect(callback.calledOnce).to.be.ok; expect(callback.args[0][1]).to.equal(response); - expect(args.tries).to.equal(1); + expect(requestStub.args.length).to.equal(1); done(); }, 10); }); it('should pass the response into callback if successful for tokens', function (done) { var callback = sinon.spy(), - response = { success: true }, + response = { + success: 1, + failure: 0, + results: [ + { message_id: "something" } + ] + }, sender = new Sender('myKey'); - setArgs(null, response); - sender.send({}, [1, 2, 3], 0, callback); + setArgs(null, { statusCode: 200 }, response); + sender.send({}, [1, 2, 3], callback); setTimeout(function() { expect(callback.calledOnce).to.be.ok; expect(callback.args[0][1]).to.equal(response); - expect(args.tries).to.equal(1); + expect(requestStub.args.length).to.equal(1); done(); }, 10); }); - it('should pass the error into callback if failure and no retry for token', function (done) { + it('should pass the error into callback if failure for token', function (done) { var callback = sinon.spy(), error = 'my error', sender = new Sender('myKey'); @@ -432,12 +451,12 @@ describe('UNIT Sender', function () { setTimeout(function() { expect(callback.calledOnce).to.be.ok; expect(callback.args[0][0]).to.equal(error); - expect(args.tries).to.equal(1); + expect(requestStub.args.length).to.equal(1); done(); }, 10); }); - it('should pass the error into callback if failure and no retry for tokens', function (done) { + it('should pass the error into callback if failure for tokens', function (done) { var callback = sinon.spy(), error = 'my error', sender = new Sender('myKey'); @@ -446,7 +465,7 @@ describe('UNIT Sender', function () { setTimeout(function() { expect(callback.calledOnce).to.be.ok; expect(callback.args[0][0]).to.equal(error); - expect(args.tries).to.equal(1); + expect(requestStub.args.length).to.equal(1); done(); }, 10); }); @@ -454,25 +473,28 @@ describe('UNIT Sender', function () { it('should retry number of times passed into call and do exponential backoff', function (done) { var start = new Date(); var callback = function () { - expect(args.tries).to.equal(2); - expect(new Date() - start).to.be.gte(1000); + expect(requestStub.args.length).to.equal(2); + expect(new Date() - start).to.be.gte(200); done(); }; var sender = new Sender('myKey'); - setArgs('my error'); - sender.send({ data: {}}, [1], 1, callback); + setArgs(null, { statusCode: 500 }); + sender.send({ data: {}}, [1], { + retries: 1, + backoff: 200 + }, callback); }); it('should retry if not all regTokens were successfully sent', function (done) { var callback = function () { - expect(args.tries).to.equal(3); - // Last call of sendNoRetry should be for only failed regTokens - expect(args.reg_tokens.length).to.equal(1); - expect(args.reg_tokens[0]).to.equal(3); + expect(requestStub.args.length).to.equal(3); + var requestOptions = requestStub.args[2][0]; + expect(requestOptions.json.registration_ids.length).to.equal(1); + expect(requestOptions.json.registration_ids[0]).to.equal(3); done(); }; var sender = new Sender('myKey'); - setArgs(null, [{ results: [{}, { error: 'Unavailable' }, { error: 'Unavailable' }]}, { results: [ {}, { error: 'Unavailable' } ] }, { results: [ {} ] } ]); + setArgs(null, { statusCode: 200}, [{ results: [{}, { error: 'Unavailable' }, { error: 'Unavailable' }]}, { results: [ {}, { error: 'Unavailable' } ] }, { results: [ {} ] } ]); sender.send({ data: {}}, [1,2,3], { retries: 5, backoff: 100 @@ -482,8 +504,9 @@ describe('UNIT Sender', function () { it('should retry all regTokens in event of an error', function (done) { var start = new Date(); var callback = function () { - expect(args.tries).to.equal(2); - expect(args.reg_tokens.length).to.equal(3); + expect(requestStub.args.length).to.equal(2); + var requestOptions = requestStub.args[1][0]; + expect(requestOptions.json.registration_ids.length).to.equal(3); done(); }; var sender = new Sender('myKey'); @@ -500,7 +523,7 @@ describe('UNIT Sender', function () { done(); }; var sender = new Sender('myKey'); - setArgs(null, [ + setArgs(null, { statusCode: 200 }, [ { success: 1, failure: 2, canonical_ids: 0, results: [ {}, { error: 'Unavailable' }, { error: 'Unavailable' } ] }, { success: 1, canonical_ids: 1, failure: 0, results: [ {}, {} ] } ]); @@ -516,13 +539,13 @@ describe('UNIT Sender', function () { done(); }; var sender = new Sender('myKey'); - setArgs(null, [ + setArgs(null, { statusCode: 200 }, [ { success: 0, failure: 3, canonical_ids: 0, results: [ { error: 'Unavailable' }, { error: 'Unavailable' }, { error: 'Unavailable' } ] }, { success: 1, canonical_ids: 0, failure: 2, results: [ { error: 'Unavailable' }, { error: 'Unavailable' }, {} ] }, { success: 0, canonical_ids: 0, failure: 2, results: [ { error: 'Unavailable' }, { error: 'Unavailable' } ] } ]); sender.send({ data: {}}, [1,2,3], { - retries: 3, + retries: 2, backoff: 100 }, callback); }); From a1343eb1410d75199f415e7f4e04304be9ebec0a Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Wed, 8 Jun 2016 19:43:13 +0200 Subject: [PATCH 21/22] merge two tests, so the same on now tests sender options and auth key --- test/unit/senderSpec.js | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/test/unit/senderSpec.js b/test/unit/senderSpec.js index d5bcbc0..a15ef2b 100644 --- a/test/unit/senderSpec.js +++ b/test/unit/senderSpec.js @@ -28,19 +28,6 @@ describe('UNIT Sender', function () { expect(sender).to.not.be.undefined; expect(sender).to.be.instanceOf(gcm); }); - - it('should create a Sender with key and options passed in', function () { - var options = { - proxy: 'http://myproxy.com', - maxSockets: 100, - timeout: 100 - }; - var key = 'myAPIKey', - sender = new gcm(key, options); - expect(sender).to.be.instanceOf(gcm); - expect(sender.key).to.equal(key); - expect(sender.options).to.deep.equal(options); - }); }); describe('send() without retries', function () { @@ -56,7 +43,7 @@ describe('UNIT Sender', function () { setArgs(null, { statusCode: 200 }, {}); }); - it('should set proxy, maxSockets, timeout and/or strictSSL of req object if passed into constructor', function (done) { + it('should set key, proxy, maxSockets, timeout and/or strictSSL of req object if passed into constructor', function (done) { var options = { proxy: 'http://myproxy.com', maxSockets: 100, @@ -67,6 +54,7 @@ describe('UNIT Sender', function () { var m = { data: {} }; sender.send(m, '', { retries: 0 }, function () {}); setTimeout(function() { + expect(args.options.headers["Authorization"]).to.equal("key=mykey"); expect(args.options.proxy).to.equal(options.proxy); expect(args.options.maxSockets).to.equal(options.maxSockets); expect(args.options.timeout).to.equal(options.timeout); From 7e556990ac9be287819be290fef57264dc7078e9 Mon Sep 17 00:00:00 2001 From: Niels Abildgaard Date: Wed, 8 Jun 2016 19:45:05 +0200 Subject: [PATCH 22/22] Remove two tests that no longer pass (and shouldnt!) They used the registration_ids key, which we will no longer support. They passed because state was NOT reset before every test (fixed this in earlier commit) --- test/unit/senderSpec.js | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/test/unit/senderSpec.js b/test/unit/senderSpec.js index a15ef2b..0670b20 100644 --- a/test/unit/senderSpec.js +++ b/test/unit/senderSpec.js @@ -208,30 +208,6 @@ describe('UNIT Sender', function () { }, 10); }); - it('should set the registration_ids to reg tokens explicitly passed in', function (done) { - var sender = new Sender('myKey'); - var m = { data: {} }; - var regTokens = ["registration token 1", "registration token 2"]; - sender.send(m, { registrationIds: regTokens }, { retries: 0 }, function () {}); - setTimeout(function() { - var body = args.options.json; - expect(body.registration_ids).to.deep.equal(regTokens); - done(); - }, 10); - }); - - it('should set the registration_ids to reg tokens explicitly passed in', function (done) { - var sender = new Sender('myKey'); - var m = { data: {} }; - var regTokens = ["registration token 1", "registration token 2"]; - sender.send(m, { registrationTokens: regTokens }, { retries: 0 }, function () {}); - setTimeout(function() { - var body = args.options.json; - expect(body.registration_ids).to.deep.equal(regTokens); - done(); - }, 10); - }); - it('should set the to field if a single reg (or other) token is passed in', function(done) { var sender = new Sender('myKey'); var m = { data: {} };