775ac7b58c
you must login with an BTP account in order to see the app
284 lines
8.7 KiB
JavaScript
284 lines
8.7 KiB
JavaScript
'use strict'
|
|
|
|
var http = require('http')
|
|
var test = require('tape')
|
|
var EventEmitter = require('events').EventEmitter
|
|
var requestStats = require('./index')
|
|
var Request = require('./lib/request')
|
|
var StatsEmitter = require('./lib/stats_emitter')
|
|
var KeepAliveAgent = require('keep-alive-agent')
|
|
|
|
var assertStatsCommon = function (t, stats) {
|
|
t.ok(stats.req.bytes > 0, 'stats.req.bytes > 0') // different headers will result in different results
|
|
t.equal(typeof stats.req.headers.connection, 'string')
|
|
t.equal(stats.req.method, 'PUT')
|
|
t.equal(stats.req.path, '/')
|
|
t.equal(stats.res.status, 200)
|
|
}
|
|
|
|
// assertion helper for validating stats from HTTP requests that finished correctly
|
|
var assertStatsFinished = function (t, stats) {
|
|
t.ok(stats.ok, 'stats.ok should be truthy')
|
|
t.ok(stats.time >= 9, 'stats.time >= 9') // The reason we don't just do >= 10, is because setTimeout is not that precise
|
|
t.ok(stats.res.bytes > 0, 'stats.res.bytes > 0') // different headers will result in different results
|
|
t.equal(typeof stats.res.headers.connection, 'string')
|
|
assertStatsCommon(t, stats)
|
|
}
|
|
|
|
// assertion helper for validating stats from HTTP requests that are closed before finishing
|
|
var assertStatsClosed = function (t, stats) {
|
|
t.ok(!stats.ok)
|
|
t.ok(stats.time >= 0)
|
|
t.equal(stats.res.bytes, 0)
|
|
t.deepEqual(stats.res.headers, {})
|
|
assertStatsCommon(t, stats)
|
|
}
|
|
|
|
var _start = function (server, errorHandler) {
|
|
server.listen(0, function () {
|
|
var options = {
|
|
port: server.address().port,
|
|
method: 'PUT'
|
|
}
|
|
|
|
var req = http.request(options, function (res) {
|
|
res.resume()
|
|
res.once('end', function () {
|
|
server.close()
|
|
})
|
|
})
|
|
|
|
if (errorHandler) req.on('error', errorHandler)
|
|
|
|
req.end('42')
|
|
})
|
|
}
|
|
|
|
var _respond = function (req, res) {
|
|
req.on('end', function () {
|
|
setTimeout(function () {
|
|
res.end('Answer to the Ultimate Question of Life, The Universe, and Everything')
|
|
}, 10)
|
|
})
|
|
req.resume()
|
|
}
|
|
|
|
test('StatsEmitter', function (t) {
|
|
var statsEmitter = requestStats()
|
|
t.ok(statsEmitter instanceof StatsEmitter, 'should be returned from requestStats()')
|
|
t.ok(statsEmitter instanceof EventEmitter, 'should be an instance of EventEmitter')
|
|
|
|
t.test('should emit a "request" event', function (t) {
|
|
var server = http.createServer(_respond)
|
|
requestStats(server).on('request', function () {
|
|
t.end()
|
|
})
|
|
_start(server)
|
|
})
|
|
|
|
t.test('should emit a "complete" event', function (t) {
|
|
var server = http.createServer(_respond)
|
|
requestStats(server).on('complete', function () {
|
|
t.end()
|
|
})
|
|
_start(server)
|
|
})
|
|
})
|
|
|
|
test('requestStats(server, onStats)', function (t) {
|
|
t.test('should call the stats-listener on request end', function (t) {
|
|
var server = http.createServer(_respond)
|
|
requestStats(server, function (stats) {
|
|
assertStatsFinished(t, stats)
|
|
t.end()
|
|
})
|
|
_start(server)
|
|
})
|
|
|
|
t.test('should call the stats-listener when the request is destroyed', function (t) {
|
|
var server = http.createServer(function (req, res) {
|
|
req.destroy()
|
|
})
|
|
requestStats(server, function (stats) {
|
|
assertStatsClosed(t, stats)
|
|
})
|
|
_start(server, function (err) {
|
|
t.ok(err instanceof Error)
|
|
t.end()
|
|
})
|
|
})
|
|
|
|
t.test('should calculate correct bytes read/written on keep-alive connections', function (t) {
|
|
var agent = new http.Agent()
|
|
agent.maxSockets = 1 // force connection reuse for every connection
|
|
|
|
var server = http.createServer(function (req, res) {
|
|
req.on('end', function () {
|
|
res.end()
|
|
})
|
|
req.resume()
|
|
})
|
|
|
|
server.once('connection', function () {
|
|
server.once('connection', function () {
|
|
t.fail('Expected the TCP connection to be reused')
|
|
})
|
|
})
|
|
|
|
requestStats(server, function (stats) {
|
|
// assert req.bytes are around 1 million (we cannot know exactly since
|
|
// request headers will vary depending on the host system)
|
|
t.ok(stats.req.bytes > 1000000, 'req body size should be above 1MB')
|
|
t.ok(stats.req.bytes < 1000300, 'req body size should not be to much above 1MB')
|
|
})
|
|
|
|
var performRequest = function (port, callback) {
|
|
var req = http.request({ port: port, method: 'PUT', agent: agent }, function (res) {
|
|
res.on('end', callback)
|
|
res.resume()
|
|
})
|
|
for (var n = 0, s = ''; n < 100000; n++) s += '1234567890' // 1 million
|
|
req.end(s)
|
|
}
|
|
|
|
server.listen(0, function () {
|
|
var port = server.address().port
|
|
performRequest(port, function () {
|
|
performRequest(port, function () {
|
|
server.close()
|
|
t.end()
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
test('requestStats(req, res).once(...)', function (t) {
|
|
t.test('should call the stats-listener on request end', function (t) {
|
|
_start(http.createServer(function (req, res) {
|
|
requestStats(req, res).once('complete', function (stats) {
|
|
assertStatsFinished(t, stats)
|
|
t.end()
|
|
})
|
|
_respond(req, res)
|
|
}))
|
|
})
|
|
})
|
|
|
|
test('requestStats(server).once(...)', function (t) {
|
|
t.test('should call the stats-listener on request end', function (t) {
|
|
var server = http.createServer(_respond)
|
|
requestStats(server).once('complete', function (stats) {
|
|
assertStatsFinished(t, stats)
|
|
t.end()
|
|
})
|
|
_start(server)
|
|
})
|
|
})
|
|
|
|
test('requestStats(req, res, onStats)', function (t) {
|
|
t.test('should call the stats-listener on request end', function (t) {
|
|
_start(http.createServer(function (req, res) {
|
|
requestStats(req, res, function (stats) {
|
|
assertStatsFinished(t, stats)
|
|
t.end()
|
|
})
|
|
_respond(req, res)
|
|
}))
|
|
})
|
|
})
|
|
|
|
test('Request instance', function (t) {
|
|
t.test('should expose a .progress() function', function (t) {
|
|
_start(http.createServer(function (req, res) {
|
|
var request = new Request(req, res)
|
|
t.ok(typeof request.progress === 'function')
|
|
t.end()
|
|
}))
|
|
})
|
|
|
|
t.test('should be emitted on the "request" event', function (t) {
|
|
var server = http.createServer(_respond)
|
|
var statsEmitter = requestStats(server)
|
|
var request
|
|
statsEmitter.on('request', function (obj) {
|
|
request = obj
|
|
})
|
|
statsEmitter.on('complete', function (stats) {
|
|
t.ok(request instanceof Request)
|
|
t.end()
|
|
})
|
|
_start(server)
|
|
})
|
|
})
|
|
|
|
test('request.progress()', function (t) {
|
|
t.test('should return a progress object', function (t) {
|
|
var server = http.createServer(_respond)
|
|
var statsEmitter = requestStats(server)
|
|
statsEmitter.on('request', function (request) {
|
|
var progress = request.progress()
|
|
t.equal(progress.completed, false, 'should be completed')
|
|
t.ok(progress.time >= 0, 'progress.time >= 0')
|
|
t.ok(progress.timeDelta >= 0, 'progress.timeDelta >= 0')
|
|
t.ok(progress.req.bytes > 0, 'progress.req.bytes > 0')
|
|
t.ok(progress.req.bytesDelta > 0, 'progress.req.bytesDelta > 0')
|
|
t.ok(progress.req.speed > 0, 'progress.req.speed > 0')
|
|
t.equal(progress.res.bytes, 0, 'progress.res.bytes === 0')
|
|
t.equal(progress.res.bytesDelta, 0, 'progress.res.bytesDelta === 0')
|
|
t.equal(progress.res.speed, 0, 'progress.res.speed === 0')
|
|
t.end()
|
|
})
|
|
_start(server)
|
|
})
|
|
|
|
t.test('should not mix progress from two request', function (t) {
|
|
var server = http.createServer(_respond)
|
|
var statsEmitter = requestStats(server)
|
|
var requests = []
|
|
var progress = []
|
|
|
|
statsEmitter.on('request', function (request) {
|
|
requests.push(request)
|
|
t.equal(typeof request._connection, 'object')
|
|
})
|
|
|
|
statsEmitter.on('complete', function (stats) {
|
|
progress.push(requests[requests.length - 1].progress())
|
|
if (requests.length < 2) return
|
|
t.equal(requests[0]._connection, requests[1]._connection, 'should re-use the http connection')
|
|
t.equal(progress[0].req.bytes, progress[1].req.bytes, 'should receive the same amount of data')
|
|
t.equal(progress[0].res.bytes, progress[1].res.bytes, 'should send the same amount of data')
|
|
t.equal(progress[0].req.bytes + progress[1].req.bytes, requests[0]._connection.bytesRead, 'should not accumulate received data')
|
|
t.equal(progress[0].res.bytes + progress[1].res.bytes, requests[0]._connection.bytesWritten, 'should not accumulate sent data')
|
|
t.end()
|
|
})
|
|
|
|
server.listen(0, function () {
|
|
var options = {
|
|
port: server.address().port,
|
|
method: 'PUT',
|
|
headers: { Connection: 'keep-alive' },
|
|
agent: new KeepAliveAgent()
|
|
}
|
|
|
|
http.request(options, function (res) {
|
|
res.resume()
|
|
}).end('42')
|
|
|
|
setTimeout(function () {
|
|
http.request(options, function (res) {
|
|
res.resume()
|
|
res.once('end', function () {
|
|
server.close()
|
|
})
|
|
}).end('42')
|
|
}, 100)
|
|
})
|
|
})
|
|
})
|
|
|
|
test('end', function (t) {
|
|
t.end()
|
|
process.exit()
|
|
})
|