[
  {
    "path": ".gitignore",
    "content": "lib-cov\n*.seed\n*.log\n*.csv\n*.dat\n*.out\n*.pid\n*.gz\n\npids\nlogs\nresults\nnode_modules\n\nnpm-debug.log\n"
  },
  {
    "path": "LICENSE-MIT",
    "content": "Copyright (c) 2013 \"Bruce Dou\" <doubaokun@gmail.com>\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "README.md",
    "content": "## Node ab testing\n\nAutomatically benchmarking the performance of HTTP services.\n\n![node-ab](https://raw.githubusercontent.com/doubaokun/node-ab/master/node-ab.gif)\n\n## How it works\nAb testing tool to check the performance of an HTTP service. 100 more GET request will be increased per second. It will not increase more request if there are more than 10 request not returned. It will stop when there are less than 99% request return successful.\n\nThe requests number per increase round and the time of each round can be changed by user.\n \n## Installation:\n\n    sudo npm install node-ab -g \n\n## Usage:\n\n    nab [URL] [--increase 100] [--milliseconds 1] [--help] [--verbose]\n\n\n    nab --help\n    Usage: nab <URL> [--increase 100] [--milliseconds 1] [--help] [--verbose]\n\n    Samples:\n        nab http://192.168.1.66\n        nab http://localhost\n        nab http://localhost:4000 --increase 200\n        nab http://localhost:4000 -i 200\n        nab http://localhost:4000 --milliseconds 1500\n        nab http://localhost:4000 --milliseconds 1500 --verbose\n        nab http://localhost:4000 -m 1500\n        nab http://localhost:4000 -m 1500 -v\n        nab --help\n        nab -h\n\n## Example:\n\n    nab http://localhost:4000/test\n    Request number: 200 Return number: 200 QPS: 66 Traffic: 32KB per second\n    Request number: 800 Return number: 800 QPS: 133 Traffic: 65KB per second\n    Request number: 1700 Return number: 1700 QPS: 188 Traffic: 92KB per second\n    Request number: 2900 Return number: 2900 QPS: 241 Traffic: 117KB per second\n    Request number: 4400 Return number: 4400 QPS: 293 Traffic: 143KB per second\n    Request number: 6200 Return number: 6200 QPS: 344 Traffic: 168KB per second\n    Request number: 8300 Return number: 8300 QPS: 394 Traffic: 192KB per second\n    Request number: 10700 Return number: 10700 QPS: 445 Traffic: 217KB per second\n    Request number: 13400 Return number: 13400 QPS: 495 Traffic: 242KB per second\n    Request number: 16400 Return number: 16366 QPS: 545 Traffic: 266KB per second\n    Request number: 16400 Return number: 16366 QPS: 495 Traffic: 241KB per second\n    Request number: 16400 Return number: 16366 QPS: 454 Traffic: 221KB per second\n    Request number: 16400 Return number: 16366 QPS: 419 Traffic: 204KB per second\n    Request number: 16400 Return number: 16366 QPS: 389 Traffic: 190KB per second\n    Request number: 18400 Return number: 18268 QPS: 405 Traffic: 198KB per second\n    Request number: 21400 Return number: 21009 QPS: 437 Traffic: 213KB per second\n\n## Development\n\n    git clone git@github.com:doubaokun/node-ab.git\n    npm install -d\n\n### Start a sample http service at http://127.0.0.1:4000/test\n    node sample/app.js\n\n### Start testing the sample http service\n    ./bin/nab http://localhost:81/test\n\n\n"
  },
  {
    "path": "bin/nab",
    "content": "#!/usr/bin/env node\nrequire(\"../lib/ab.js\")"
  },
  {
    "path": "lib/ab.js",
    "content": "var httpLib = require('http'),\n    url = require('url'),\n    colors = require('colors'),\n    argv = require('optimist').argv;\n\nvar stats = {\n  'conn_num': 0,\n  'req_num': 0,\n  'success_num': 0,\n  'traffic_ps': 0\n};\nif(argv.help || argv.h){\n    console.log(\"Usage: nab <URL> [--increase 100] [--milliseconds 1] [--help] [--verbose]\".green);\n    console.log(\"\");\n    console.log(\"Samples:\".blue);\n    console.log(\"\\tnab http://192.168.1.66\");\n    console.log(\"\\tnab http://localhost\");\n    console.log(\"\\tnab http://localhost:4000 --increase 200\");\n    console.log(\"\\tnab http://localhost:4000 -i 200\");\n    console.log(\"\\tnab http://localhost:4000 --milliseconds 1500\");\n    console.log(\"\\tnab http://localhost:4000 --milliseconds 1500 --verbose\");\n    console.log(\"\\tnab http://localhost:4000 -m 1500\");\n    console.log(\"\\tnab http://localhost:4000 -m 1500 -v\");\n    console.log(\"\\tnab --help\");\n    console.log(\"\\tnab -h\");\n    return console.log(\"\");\n}\nif(!process.argv[2]) {\n  return console.log(\"Usage: nab <URL> [--increase 100] [--milliseconds 1] [--help] [--verbose]\".red);\n}\nvar uri = process.argv[2];\nvar user_option = url.parse(uri);\nif(!user_option.hostname || !user_option.path) {\n  return console.log(\"Not validate [URL]\".red);\n}\n\nvar useHTTPS = (user_option.protocol === 'https:');\n\nif (useHTTPS) {\n  httpLib = require('https');\n}\n\nvar force = (argv.increase || argv.i) || 100; // increase request number per second\nif(argv.v || argv.verbose) console.log((\"Increase \" + (force) + \" requests per round\").green);\n\nvar pre_qps = 0;\nvar traffic = 0;\nvar start = new Date().getTime();\n\nprocess.on('uncaughtException', function (err) {\n  // continue running\n  //console.error(err.stack);\n  if(argv.v || argv.verbose) console.log((\"Ending connection\").red);\n});\n\nvar bench_intv = function() {\n  // Skip when there are no return requests\n  if(stats.conn_num > 10) return;\n\n  var http_request = function() {\n    var options = {\n      hostname: user_option.hostname,\n      port: user_option.port,\n      path: user_option.path,\n      method: 'GET'\n    };\n\n    if (useHTTPS) {\n      options.rejectUnauthorized = false;\n    }\n\n    var callback = function(res) {\n      if(res.statusCode === 200) {\n        stats.success_num ++;\n      }\n      res.setEncoding('utf8');\n      res.on('data', function (chunk) {\n          if(argv.v || argv.verbose){\n              console.log((\"Data received\").green);\n              console.log((\"\\t\"+chunk).yellow);\n          }\n          traffic += chunk.length;\n      });\n      res.on('end', function() {\n          if(argv.v || argv.verbose)console.log((\"Ending connection\").red);\n        stats.conn_num --;\n      });\n    };\n\n\n    var req = httpLib.request(options, callback);\n    req.setNoDelay(true);\n    //req.setSocketKeepAlive(false);\n    req.end();\n  };\n  for(var i=0; i< force; i++) {\n    stats.req_num ++;\n    stats.conn_num ++;\n    http_request();\n  }\n};\n\nvar milliseconds = (argv.milliseconds || argv.m) || 1000;\nif(argv.v || argv.verbose) console.log((\"Increase requests per \" + milliseconds + \" milliseconds\").green);\nsetInterval(bench_intv, milliseconds );\n\nvar stats_intv = function() {\n  var qps = parseInt(stats.success_num * milliseconds / (new Date().getTime() - start), 10);\n  stats.qps = qps;\n  stats.force = force;\n  var tps = parseInt(traffic * milliseconds / (new Date().getTime() - start), 10);\n  stats.traffic_ps = btraffic(tps);\n  console.log(\"Request number: \" + stats.req_num.toString().green + \" Return number: \" + stats.success_num.toString().green\n   + \" QPS: \" + stats.qps.toString().green + \" Traffic: \" + stats.traffic_ps.green);\n\n  if(stats.req_num - stats.success_num < 10) {\n    force += 100;\n  }\n  if(stats.success_num/stats.req_num < 0.99) {\n    process.exit();\n  }\n  if(stats.qps === pre_qps) {\n    process.exit();\n  }\n  pre_qps = qps;\n};\n\nsetInterval(stats_intv, 3*milliseconds);\n\nfunction btraffic(num) {\n  var m = parseInt(num / 1048576, 10);\n  var k = parseInt((num - m * 1048576) / 1024, 10);\n  var b = parseInt(num - m * 1048576 - k * 1024, 10);\n  var result = '';\n  if(m > 0) {\n    result += m + 'MB ';\n  }\n  if(k > 0 && !result) {\n    result += k + 'KB ';\n  }\n  if(b > 0 && !result) {\n    result += b + 'B ';\n  }\n  if(milliseconds == 1000){\n    result += 'per second';\n  }else{\n      result += 'every ' + (milliseconds) + ' milliseconds';\n  }\n  return result;\n}\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"node-ab\",\n  \"version\": \"0.0.6\",\n  \"description\": \"A command tool to test the performance of HTTP services.\",\n  \"bin\": {\n    \"nab\": \"./bin/nab\"\n  },\n  \"dependencies\": {\n    \"colors\": \"~0.6.0\",\n    \"optimist\": \"^0.6.1\",\n    \"express\": \"*\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git://github.com/doubaokun/node-ab\"\n  },\n  \"keywords\": [\n    \"ab\",\n    \"performance\",\n    \"testing\",\n    \"http\"\n  ],\n  \"author\": \"Bruce Dou <doubaokun@gmail.com>\",\n  \"url\": \"https://github.com/doubaokun/node-ab/blob/master/LICENSE-MIT\"\n}\n"
  },
  {
    "path": "sample/app.js",
    "content": "var cluster = require('cluster');\nvar numCPUs = /*require('os').cups().length*/ 8;\nvar express = require('express');\n\nif(cluster.isMaster) { \n  for(var i = 0; i < numCPUs; i++) {\n    cluster.fork();\n  }\n  console.log(\"Server started http://127.0.0.1:4000/test\");\n} else {\n  var app = express();\n\n  app.get('/test', function(req, res) {\n    var body = '';\n    for(var i=0;i<100;i++) {\n      body += 'aaaaa';\n    }\n    res.end(body);\n  });\n\n  app.listen(4000);\n\n}\n"
  }
]