diff --git a/README.md b/README.md
index 4f3ec99..213e54c 100644
--- a/README.md
+++ b/README.md
@@ -141,7 +141,7 @@ apiBenchmark.measure(service, routes, function(err, results){
(String, default 'get'): Http verb.
#### route
- (String): the route to benchmark
+ (String): the route to benchmark. In case of function (that has to return an string) it will be evaulated for each request.
#### headers
(Object): the headers to send. In case of function (that has to return an object) it will be evaulated for each request.
diff --git a/lib/request-agent.js b/lib/request-agent.js
index 596410d..525a901 100644
--- a/lib/request-agent.js
+++ b/lib/request-agent.js
@@ -1,6 +1,7 @@
'use strict';
var _ = require('underscore');
+var url = require('url');
module.exports = function(agent){
this.agent = agent;
@@ -12,13 +13,16 @@ module.exports = function(agent){
this.make = function(options, callback){
var data = evalIfFunction(options.data) || {},
query = evalIfFunction(options.query) || {},
+ route = evalIfFunction(options.route) || '',
headers = evalIfFunction(options.headers) || {},
method = options.method === 'delete' ? 'del' : options.method,
- request = this.agent[method](options.url);
+ service = options.service || '',
+ requestUrl = url.resolve(service, route),
+ request = this.agent[method](requestUrl);
if(!_.isEmpty(data)) {
request.send(data);
- }
+ }
if(!_.isEmpty(query)) {
request.query(query);
diff --git a/lib/request-handler.js b/lib/request-handler.js
index 75cfec4..a0673f2 100644
--- a/lib/request-handler.js
+++ b/lib/request-handler.js
@@ -3,6 +3,7 @@
var format = require('./format');
var settings = require('./settings');
var _ = require('underscore');
+var url = require('url');
module.exports = {
make: function(req, suite, suiteName, requestAgent, callback){
@@ -34,9 +35,9 @@ module.exports = {
}
});
},
- setup: function(suiteName, suiteHref, suite, requestAgent){
+ setup: function(suiteName, service, suite, requestAgent){
var self = this,
- req = _.extend(_.clone(suite.endpoint), { url: suiteHref }),
+ req = _.extend(_.clone(suite.endpoint), { service: service }),
suiteOptions = {
expectedStatusCode: suite.endpoint.expectedStatusCode,
maxMean: suite.endpoint.maxMean,
@@ -45,6 +46,10 @@ module.exports = {
},
suiteRequest = {};
+ if(!!suite.endpoint.route){
+ suiteRequest.route = _.isFunction(suite.endpoint.route) ? 'Dynamic route on ' + service : url.resolve(service, suite.endpoint.route);
+ }
+
if(!!suite.endpoint.headers){
suiteRequest.headers = _.isFunction(suite.endpoint.headers) ? 'Dynamic headers' : suite.endpoint.headers;
}
@@ -57,7 +62,7 @@ module.exports = {
suiteRequest.query = _.isFunction(suite.endpoint.query) ? 'Dynamic query' : suite.endpoint.query;
}
- suite.runner.add(suiteName, suiteHref, suiteOptions, suiteRequest, function(done){
+ suite.runner.add(suiteName, suiteRequest.route, suiteOptions, suiteRequest, function(done){
self.make(req, suite, suiteName, requestAgent, done);
});
}
diff --git a/lib/suites-manager.js b/lib/suites-manager.js
index 3068cda..6030fcb 100644
--- a/lib/suites-manager.js
+++ b/lib/suites-manager.js
@@ -7,7 +7,7 @@ var ResultsHandler = require('./results-handler');
var Runner = require('./runner');
var sanitise = require('./sanitise');
var settings = require('./settings');
-var url = require('url');
+
var validator = require('./validator');
var _ = require('underscore');
@@ -45,11 +45,10 @@ module.exports = function(agent, debugHelper){
_.forEach(this.services, function(service, serviceName){
_.forEach(this.routes, function(route){
- var routeHref = url.resolve(service, route.endpoint.route),
- routeName = serviceName + '/' + route.name,
+ var routeName = serviceName + '/' + route.name,
self = this;
- requestHandler.setup(routeName, routeHref, route, self.requestAgent);
+ requestHandler.setup(routeName, service, route, self.requestAgent);
}, this);
}, this);
diff --git a/templates/report.html b/templates/report.html
index de8b969..c5de509 100644
--- a/templates/report.html
+++ b/templates/report.html
@@ -224,9 +224,15 @@
'
99% Percentile: ' + fixNumber(routeData.stats.p99, 6) + '' +
'99.9% Percentile: ' + fixNumber(routeData.stats.p999, 6) + '' +
'Request: ' + routeData.options.method.toUpperCase() +
- '
' +
- routeData.href + 'Concurrency level: ' + routeData.options.concurrencyLevel + '
';
+ '
Request: ' + routeData.options.method.toUpperCase() + ' ';
+
+ if (routeData.href.indexOf('Dynamic route') > -1) {
+ template += routeData.href;
+ } else {
+ template += '
' + routeData.href + '';
+ }
+
+ template += '
Concurrency level: ' + routeData.options.concurrencyLevel + '
';
if(routeData.options.delay)
template += 'Delay between bench cycles: ' + routeData.options.delay + '
';
diff --git a/test/fixtures/test-agent.js b/test/fixtures/test-agent.js
index 1b32916..6745b94 100644
--- a/test/fixtures/test-agent.js
+++ b/test/fixtures/test-agent.js
@@ -1,20 +1,23 @@
'use strict';
-module.exports.FakeAgent = function(){
+module.exports.FakeAgent = function(){
this.end = function(callback){
callback(null, {
+ url: this.url,
data: this.data,
headers: this.headers,
query: this.queryData
});
};
- this.get = function(request){
+ this.get = function(url){
+ this.url = url;
return this;
};
- this.post = function(request){
+ this.post = function(url){
+ this.url = url;
return this;
};
diff --git a/test/unit/request-agent.js b/test/unit/request-agent.js
index 82a36f2..72cb32a 100644
--- a/test/unit/request-agent.js
+++ b/test/unit/request-agent.js
@@ -18,6 +18,7 @@ describe('requestAgent.make function', function(){
it('should correctly handle null data', function(done){
requestAgent.make({
+ service: 'http://service/',
route: '/post',
method: 'post',
data: null
@@ -29,6 +30,7 @@ describe('requestAgent.make function', function(){
it('should correctly handle undefined data', function(done){
requestAgent.make({
+ service: 'http://service/',
route: '/post',
method: 'post',
data: undefined
@@ -38,6 +40,30 @@ describe('requestAgent.make function', function(){
});
});
+ it('should correctly handle route as a function', function(done){
+
+ var i = 0;
+
+ var routeFunc = function(){
+ i++;
+ return '/endpoint'+i;
+ };
+
+ var request = {
+ service: 'http://service/',
+ route: routeFunc,
+ method: 'post'
+ };
+
+ requestAgent.make(request, function(err, fakeResults){
+ fakeResults.url.should.be.eql('http://service/endpoint1');
+ requestAgent.make(request, function(err, fakeResults){
+ fakeResults.url.should.be.eql('http://service/endpoint2');
+ done();
+ });
+ });
+ });
+
it('should correctly handle data as a function', function(done){
var i = 0;
@@ -48,6 +74,7 @@ describe('requestAgent.make function', function(){
};
var request = {
+ service: 'http://service/',
route: '/post',
method: 'post',
data: dataFunc
@@ -72,6 +99,7 @@ describe('requestAgent.make function', function(){
};
var request = {
+ service: 'http://service/',
route: '/get',
method: 'get',
query: queryFunc
@@ -88,6 +116,7 @@ describe('requestAgent.make function', function(){
it('should correctly handle cookies', function(done){
requestAgent.make({
+ service: 'http://service/',
route: '/get',
method: 'get',
headers: {
@@ -101,6 +130,7 @@ describe('requestAgent.make function', function(){
it('should correctly handle headers', function(done){
requestAgent.make({
+ service: 'http://service/',
route: '/get',
method: 'get',
headers: {
@@ -124,6 +154,7 @@ describe('requestAgent.make function', function(){
};
var request = {
+ service: 'http://service/',
route: '/get',
method: 'get',
headers: headersFunc
diff --git a/test/unit/request-handler.js b/test/unit/request-handler.js
index 1e3815a..b13b906 100644
--- a/test/unit/request-handler.js
+++ b/test/unit/request-handler.js
@@ -17,7 +17,8 @@ describe('requestHandler.setup function', function(){
var suiteObj = {
endpoint: {
- aProperty: 'value'
+ aProperty: 'value',
+ route: 'someRoute'
},
runner: {
add: function(suiteName, suiteHref, suiteOptions, suiteRequest, callback){
@@ -26,11 +27,47 @@ describe('requestHandler.setup function', function(){
}
};
- requestHandler.setup('suiteName', 'suiteHref', suiteObj, fakeAgent);
+ requestHandler.setup('suiteName', 'serviceRoot', suiteObj, fakeAgent);
var req = fakeAgentStack[0][0];
- req.url.should.be.eql('suiteHref');
+ req.route.should.be.eql('someRoute');
+ req.service.should.be.eql('serviceRoot');
+ req.aProperty.should.be.eql('value');
+
+ done();
+ });
+
+ it('should properly handle dynamic routes', function(done){
+
+ var fakeAgentStack = [];
+
+ var fakeAgent = {
+ make: function(){
+ fakeAgentStack.push(arguments);
+ }
+ };
+
+ var suiteObj = {
+ endpoint: {
+ aProperty: 'value',
+ route: function () {
+ return 'someDynamicRoute';
+ }
+ },
+ runner: {
+ add: function(suiteName, suiteHref, suiteOptions, suiteRequest, callback){
+ suiteRequest.route.should.be.eql('Dynamic route on serviceRoot');
+ callback();
+ }
+ }
+ };
+
+ requestHandler.setup('suiteName', 'serviceRoot', suiteObj, fakeAgent);
+
+ var req = fakeAgentStack[0][0];
+ req.route.should.be.a.Function();
+ req.service.should.be.eql('serviceRoot');
req.aProperty.should.be.eql('value');
done();