1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22'use strict'; 23 24// This test requires the program 'wrk'. 25const common = require('../common'); 26 27const child_process = require('child_process'); 28const result = child_process.spawnSync('wrk', ['-h']); 29if (result.error && result.error.code === 'ENOENT') 30 common.skip('test requires `wrk` to be installed first'); 31 32const assert = require('assert'); 33const http = require('http'); 34const url = require('url'); 35 36const body = 'hello world\n'; 37const server = http.createServer((req, res) => { 38 res.writeHead(200, { 39 'Content-Length': body.length, 40 'Content-Type': 'text/plain', 41 }); 42 res.write(body); 43 res.end(); 44}); 45 46let keepAliveReqSec = 0; 47let normalReqSec = 0; 48 49 50const runAb = (opts, callback) => { 51 const args = [ 52 '-c', opts.concurrent || 50, 53 '-t', opts.threads || 2, 54 '-d', opts.duration || '5s', 55 ]; 56 57 if (!opts.keepalive) { 58 args.push('-H'); 59 args.push('Connection: close'); 60 } 61 62 args.push(url.format({ hostname: '127.0.0.1', 63 port: opts.port, protocol: 'http' })); 64 65 const child = child_process.spawn('wrk', args); 66 child.stderr.pipe(process.stderr); 67 child.stdout.setEncoding('utf8'); 68 69 let stdout; 70 71 child.stdout.on('data', (data) => stdout += data); 72 73 child.on('close', (code, signal) => { 74 if (code) { 75 console.error(code, signal); 76 process.exit(code); 77 return; 78 } 79 80 let matches = /Requests\/sec:\s*(\d+)\./i.exec(stdout); 81 const reqSec = parseInt(matches[1]); 82 83 matches = /Keep-Alive requests:\s*(\d+)/i.exec(stdout); 84 let keepAliveRequests; 85 if (matches) { 86 keepAliveRequests = parseInt(matches[1]); 87 } else { 88 keepAliveRequests = 0; 89 } 90 91 callback(reqSec, keepAliveRequests); 92 }); 93}; 94 95server.listen(0, () => { 96 const port = server.address().port; 97 runAb({ keepalive: true, port: port }, (reqSec) => { 98 keepAliveReqSec = reqSec; 99 100 runAb({ keepalive: false, port: port }, (reqSec) => { 101 normalReqSec = reqSec; 102 server.close(); 103 }); 104 }); 105}); 106 107process.on('exit', () => { 108 assert.strictEqual( 109 normalReqSec > 50, 110 true, 111 `normalReqSec should be greater than 50, but got ${normalReqSec}`, 112 ); 113 assert.strictEqual( 114 keepAliveReqSec > 50, 115 true, 116 `keepAliveReqSec should be greater than 50, but got ${keepAliveReqSec}`, 117 ); 118 assert.strictEqual( 119 normalReqSec < keepAliveReqSec, 120 true, 121 'normalReqSec should be less than keepAliveReqSec, ' + 122 `but ${normalReqSec} is greater than ${keepAliveReqSec}`, 123 ); 124}); 125