You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
332 lines
7.1 KiB
332 lines
7.1 KiB
'use strict'
|
|
|
|
const net = require('net')
|
|
const t = require('tap')
|
|
const test = t.test
|
|
const Fastify = require('..')
|
|
const { Client } = require('undici')
|
|
|
|
test('close callback', t => {
|
|
t.plan(4)
|
|
const fastify = Fastify()
|
|
fastify.addHook('onClose', onClose)
|
|
function onClose (instance, done) {
|
|
t.type(fastify, instance)
|
|
done()
|
|
}
|
|
|
|
fastify.listen(0, err => {
|
|
t.error(err)
|
|
|
|
fastify.close((err) => {
|
|
t.error(err)
|
|
t.ok('close callback')
|
|
})
|
|
})
|
|
})
|
|
|
|
test('inside register', t => {
|
|
t.plan(5)
|
|
const fastify = Fastify()
|
|
fastify.register(function (f, opts, done) {
|
|
f.addHook('onClose', onClose)
|
|
function onClose (instance, done) {
|
|
t.ok(instance.prototype === fastify.prototype)
|
|
t.equal(instance, f)
|
|
done()
|
|
}
|
|
|
|
done()
|
|
})
|
|
|
|
fastify.listen(0, err => {
|
|
t.error(err)
|
|
|
|
fastify.close((err) => {
|
|
t.error(err)
|
|
t.ok('close callback')
|
|
})
|
|
})
|
|
})
|
|
|
|
test('close order', t => {
|
|
t.plan(5)
|
|
const fastify = Fastify()
|
|
const order = [1, 2, 3]
|
|
|
|
fastify.register(function (f, opts, done) {
|
|
f.addHook('onClose', (instance, done) => {
|
|
t.equal(order.shift(), 1)
|
|
done()
|
|
})
|
|
|
|
done()
|
|
})
|
|
|
|
fastify.addHook('onClose', (instance, done) => {
|
|
t.equal(order.shift(), 2)
|
|
done()
|
|
})
|
|
|
|
fastify.listen(0, err => {
|
|
t.error(err)
|
|
|
|
fastify.close((err) => {
|
|
t.error(err)
|
|
t.equal(order.shift(), 3)
|
|
})
|
|
})
|
|
})
|
|
|
|
test('close order - async', async t => {
|
|
t.plan(3)
|
|
const fastify = Fastify()
|
|
const order = [1, 2, 3]
|
|
|
|
fastify.register(function (f, opts, done) {
|
|
f.addHook('onClose', async instance => {
|
|
t.equal(order.shift(), 1)
|
|
})
|
|
|
|
done()
|
|
})
|
|
|
|
fastify.addHook('onClose', () => {
|
|
t.equal(order.shift(), 2)
|
|
})
|
|
|
|
await fastify.listen(0)
|
|
await fastify.close()
|
|
|
|
t.equal(order.shift(), 3)
|
|
})
|
|
|
|
test('should not throw an error if the server is not listening', t => {
|
|
t.plan(2)
|
|
const fastify = Fastify()
|
|
fastify.addHook('onClose', onClose)
|
|
function onClose (instance, done) {
|
|
t.type(fastify, instance)
|
|
done()
|
|
}
|
|
|
|
fastify.close((err) => {
|
|
t.error(err)
|
|
})
|
|
})
|
|
|
|
test('onClose should keep the context', t => {
|
|
t.plan(4)
|
|
const fastify = Fastify()
|
|
fastify.register(plugin)
|
|
|
|
function plugin (instance, opts, done) {
|
|
instance.decorate('test', true)
|
|
instance.addHook('onClose', onClose)
|
|
t.ok(instance.prototype === fastify.prototype)
|
|
|
|
function onClose (i, done) {
|
|
t.ok(i.test)
|
|
t.equal(i, instance)
|
|
done()
|
|
}
|
|
|
|
done()
|
|
}
|
|
|
|
fastify.close((err) => {
|
|
t.error(err)
|
|
})
|
|
})
|
|
|
|
test('Should return error while closing (promise) - injection', t => {
|
|
t.plan(4)
|
|
const fastify = Fastify()
|
|
|
|
fastify.addHook('onClose', (instance, done) => { done() })
|
|
|
|
fastify.get('/', (req, reply) => {
|
|
reply.send({ hello: 'world' })
|
|
})
|
|
|
|
fastify.inject({
|
|
method: 'GET',
|
|
url: '/'
|
|
}, (err, res) => {
|
|
t.error(err)
|
|
t.equal(res.statusCode, 200)
|
|
fastify.close()
|
|
|
|
process.nextTick(() => {
|
|
fastify.inject({
|
|
method: 'GET',
|
|
url: '/'
|
|
}).catch(err => {
|
|
t.ok(err)
|
|
t.equal(err.message, 'Server is closed')
|
|
})
|
|
}, 100)
|
|
})
|
|
})
|
|
|
|
test('Should return error while closing (callback) - injection', t => {
|
|
t.plan(4)
|
|
const fastify = Fastify()
|
|
|
|
fastify.addHook('onClose', (instance, done) => {
|
|
setTimeout(done, 150)
|
|
})
|
|
|
|
fastify.get('/', (req, reply) => {
|
|
reply.send({ hello: 'world' })
|
|
})
|
|
|
|
fastify.inject({
|
|
method: 'GET',
|
|
url: '/'
|
|
}, (err, res) => {
|
|
t.error(err)
|
|
t.equal(res.statusCode, 200)
|
|
fastify.close()
|
|
|
|
setTimeout(() => {
|
|
fastify.inject({
|
|
method: 'GET',
|
|
url: '/'
|
|
}, (err, res) => {
|
|
t.ok(err)
|
|
t.equal(err.message, 'Server is closed')
|
|
})
|
|
}, 100)
|
|
})
|
|
})
|
|
|
|
t.test('Current opened connection should continue to work after closing and return "connection: close" header - return503OnClosing: false', t => {
|
|
const fastify = Fastify({
|
|
return503OnClosing: false
|
|
})
|
|
|
|
fastify.get('/', (req, reply) => {
|
|
fastify.close()
|
|
reply.send({ hello: 'world' })
|
|
})
|
|
|
|
fastify.listen(0, err => {
|
|
t.error(err)
|
|
|
|
const port = fastify.server.address().port
|
|
const client = net.createConnection({ port }, () => {
|
|
client.write('GET / HTTP/1.1\r\n\r\n')
|
|
|
|
client.once('data', data => {
|
|
t.match(data.toString(), /Connection:\s*keep-alive/i)
|
|
t.match(data.toString(), /200 OK/i)
|
|
|
|
client.write('GET / HTTP/1.1\r\n\r\n')
|
|
|
|
client.once('data', data => {
|
|
t.match(data.toString(), /Connection:\s*close/i)
|
|
t.match(data.toString(), /200 OK/i)
|
|
|
|
// Test that fastify closes the TCP connection
|
|
client.once('close', () => {
|
|
t.end()
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
t.test('Current opened connection should not accept new incoming connections', t => {
|
|
t.plan(3)
|
|
const fastify = Fastify()
|
|
fastify.get('/', (req, reply) => {
|
|
fastify.close()
|
|
setTimeout(() => {
|
|
reply.send({ hello: 'world' })
|
|
}, 250)
|
|
})
|
|
|
|
fastify.listen(0, err => {
|
|
t.error(err)
|
|
const instance = new Client('http://localhost:' + fastify.server.address().port)
|
|
instance.request({ path: '/', method: 'GET' }).then(data => {
|
|
t.equal(data.statusCode, 200)
|
|
})
|
|
instance.request({ path: '/', method: 'GET' }).then(data => {
|
|
t.equal(data.statusCode, 503)
|
|
})
|
|
})
|
|
})
|
|
|
|
test('Cannot be reopened the closed server without listen callback', async t => {
|
|
t.plan(2)
|
|
const fastify = Fastify()
|
|
|
|
await fastify.listen(0)
|
|
await fastify.close()
|
|
|
|
try {
|
|
await fastify.listen(0)
|
|
} catch (err) {
|
|
t.ok(err)
|
|
t.equal(err.code, 'FST_ERR_REOPENED_CLOSE_SERVER')
|
|
}
|
|
})
|
|
|
|
test('Cannot be reopened the closed server has listen callback', async t => {
|
|
t.plan(2)
|
|
const fastify = Fastify()
|
|
|
|
await fastify.listen(0)
|
|
await fastify.close()
|
|
|
|
await new Promise((resolve, reject) => {
|
|
fastify.listen(0, err => {
|
|
reject(err)
|
|
})
|
|
}).catch(err => {
|
|
t.equal(err.code, 'FST_ERR_REOPENED_CLOSE_SERVER')
|
|
t.ok(err)
|
|
})
|
|
})
|
|
|
|
test('shutsdown while keep-alive connections are active (non-async)', t => {
|
|
t.plan(5)
|
|
|
|
const timeoutTime = 2 * 60 * 1000
|
|
const fastify = Fastify({ forceCloseConnections: true })
|
|
|
|
fastify.server.setTimeout(timeoutTime)
|
|
fastify.server.keepAliveTimeout = timeoutTime
|
|
|
|
fastify.get('/', (req, reply) => {
|
|
reply.send({ hello: 'world' })
|
|
})
|
|
|
|
fastify.listen(0, (err, address) => {
|
|
t.error(err)
|
|
|
|
const client = new Client(
|
|
'http://localhost:' + fastify.server.address().port,
|
|
{ keepAliveTimeout: 1 * 60 * 1000 }
|
|
)
|
|
client.request({ path: '/', method: 'GET' }, (err, response) => {
|
|
t.error(err)
|
|
t.equal(client.closed, false)
|
|
|
|
fastify.close((err) => {
|
|
t.error(err)
|
|
|
|
// Due to the nature of the way we reap these keep-alive connections,
|
|
// there hasn't been enough time before the server fully closed in order
|
|
// for the client to have seen the socket get destroyed. The mere fact
|
|
// that we have reached this callback is enough indication that the
|
|
// feature being tested works as designed.
|
|
t.equal(client.closed, false)
|
|
})
|
|
})
|
|
})
|
|
})
|