diff --git a/lib/loadtesting.js b/lib/loadtesting.js index 282c818..e825074 100644 --- a/lib/loadtesting.js +++ b/lib/loadtesting.js @@ -48,9 +48,9 @@ var TEST_OPTIONS = { requestGenerator: undefined, // 1. requestGenerator: a function // function(http.Client) -> http.ClientRequest requestLoop: undefined, // 2. requestLoop: is a function - // function(loopFun, http.Client) + // function(finished, http.Client) method: 'GET', // If must call: - path: '/', // loopFun({ + path: '/', // finished({ requestData: undefined, // req: http.ClientRequest, // res: http.ClientResponse}); // after each transaction to finishes to schedule the diff --git a/lib/loop/multiloop.js b/lib/loop/multiloop.js index 0e5d277..e877e81 100644 --- a/lib/loop/multiloop.js +++ b/lib/loop/multiloop.js @@ -83,16 +83,17 @@ MultiLoop.prototype.getProfileValue_ = function(profile, time) { }; /** Given a profile in the format [[time, value], [time, value], ...], and the current time, return the -number of milliseconds before the profile value will change by 1. */ -MultiLoop.prototype.getProfileNextTimeout_ = function(profile, time) { +time (rounded up to the nearest whole unit) before the profile value will change by 1. */ +MultiLoop.prototype.getProfileTimeToNextValue_ = function(profile, time) { + if (!profile || profile.length === 0) { return Infinity; } if (time < 0) { return -time; } - var MIN_TIMEOUT = 1000, lastval = [0,0]; + var MIN_TIMEOUT = 1, lastval = [0,0]; for (var i = 0; i < profile.length; i++) { if (profile[i][0] > time) { - var dt = profile[i][0]-lastval[0], - millisecondsPerUnitChange = dt / (profile[i][1]-lastval[1]) * 1000; - return Math.max(MIN_TIMEOUT, Math.min(dt, millisecondsPerUnitChange)); + var dt = (profile[i][0]-time), + timePerUnitChange = dt / Math.abs(profile[i][1]-lastval[1]); + return Math.ceil(Math.max(MIN_TIMEOUT, Math.min(dt, timePerUnitChange))); } lastval = profile[i]; } @@ -103,7 +104,9 @@ MultiLoop.prototype.update_ = function() { var i, now = Math.floor((new Date() - this.startTime) / 1000), concurrency = this.getProfileValue_(this.concurrencyProfile, now), rps = this.getProfileValue_(this.rpsProfile, now), - timeout = Math.min(this.getProfileNextTimeout_(this.concurrencyProfile, now), this.getProfileNextTimeout_(this.rpsProfile, now)); + timeout = Math.min( + this.getProfileTimeToNextValue_(this.concurrencyProfile, now), + this.getProfileTimeToNextValue_(this.rpsProfile, now)) * 1000; if (concurrency < this.concurrency) { var removed = this.loops.splice(concurrency); diff --git a/test/loop.test.js b/test/loop.test.js index 419fcfb..601dfe8 100644 --- a/test/loop.test.js +++ b/test/loop.test.js @@ -151,5 +151,60 @@ module.exports = { assert.equal(getProfileValue(profile, 31), 250); assert.equal(getProfileValue(profile, 32), 0); assert.equal(getProfileValue(profile, 35), 0); + }, + 'test MultiLoop.getProfileTimeToNextValue_ works': function() { + var getProfileTimeToNextValue = loop.MultiLoop.prototype.getProfileTimeToNextValue_; + assert.equal(getProfileTimeToNextValue(null, 10), Infinity); + assert.equal(getProfileTimeToNextValue([], 10), Infinity); + + assert.equal(getProfileTimeToNextValue([[0,10]], 0), Infinity); + assert.equal(getProfileTimeToNextValue([[0,0],[10,0]], 0), 10); + assert.equal(getProfileTimeToNextValue([[0,0],[10,100]], 0), 1); + assert.equal(getProfileTimeToNextValue([[0,0],[10,0]], 4), 6); + assert.equal(getProfileTimeToNextValue([[0,0],[10,5]], 4), 2); + assert.equal(getProfileTimeToNextValue([[0,0],[10,5]], 4.5), 2); // should round up to nearest whole number + assert.equal(getProfileTimeToNextValue([[0,0],[10,5]], 5), 1); + assert.equal(getProfileTimeToNextValue([[0,0],[10,0]], 10), Infinity); + + var profile = [[0,0],[10,100],[15,100],[22,1],[30,0]]; + assert.equal(getProfileTimeToNextValue(profile, -1), 1); + assert.equal(getProfileTimeToNextValue(profile, 0), 1); + assert.equal(getProfileTimeToNextValue(profile, 1), 1); + assert.equal(getProfileTimeToNextValue(profile, 1.5), 1); + assert.equal(getProfileTimeToNextValue(profile, 10), 5); + assert.equal(getProfileTimeToNextValue(profile, 13.5), 2); + assert.equal(getProfileTimeToNextValue(profile, 15), 1); + assert.equal(getProfileTimeToNextValue(profile, 21), 1); + assert.equal(getProfileTimeToNextValue(profile, 22), 8); + assert.equal(getProfileTimeToNextValue(profile, 28.5), 2); + assert.equal(getProfileTimeToNextValue(profile, 29.5), 1); + assert.equal(getProfileTimeToNextValue(profile, 30), Infinity); + }, + 'test MultiLoop.getProfileValue_ and MultiLoop.getProfileTimeToNextValue_ coordination': function() { + var getProfileValue = loop.MultiLoop.prototype.getProfileValue_; + var getProfileTimeToNextValue = loop.MultiLoop.prototype.getProfileTimeToNextValue_; + var profile = [[0,0],[10,100],[15,100],[22,500],[30,500],[32,0]]; + assert.equal(getProfileValue(profile, 0), 0); + assert.equal(getProfileTimeToNextValue(profile, 0), 1); + assert.equal(getProfileValue(profile, 1), 10); + assert.equal(getProfileTimeToNextValue(profile, 1), 1); + assert.equal(getProfileValue(profile, 9), 90); + assert.equal(getProfileTimeToNextValue(profile, 9), 1); + assert.equal(getProfileValue(profile, 10), 100); + assert.equal(getProfileTimeToNextValue(profile, 10), 5); + assert.equal(getProfileValue(profile, 15), 100); + assert.equal(getProfileTimeToNextValue(profile, 15), 1); + assert.equal(getProfileValue(profile, 16), 157); + assert.equal(getProfileTimeToNextValue(profile, 16), 1); + assert.equal(getProfileValue(profile, 21), 442); + assert.equal(getProfileTimeToNextValue(profile, 21), 1); + assert.equal(getProfileValue(profile, 22), 500); + assert.equal(getProfileTimeToNextValue(profile, 22), 8); + assert.equal(getProfileValue(profile, 30), 500); + assert.equal(getProfileTimeToNextValue(profile, 30), 1); + assert.equal(getProfileValue(profile, 31), 250); + assert.equal(getProfileTimeToNextValue(profile, 31), 1); + assert.equal(getProfileValue(profile, 32), 0); + assert.equal(getProfileTimeToNextValue(profile, 32), Infinity); } }; \ No newline at end of file