UNPKG

fastify

Version:

Fast and low overhead web framework, for Node.js

400 lines (355 loc) 10.6 kB
'use strict' const os = require('os') const path = require('path') const fs = require('fs') const { test, before } = require('tap') const dns = require('dns').promises const dnsCb = require('dns') const sget = require('simple-get').concat const Fastify = require('..') let localhost let localhostForURL before(async function () { const lookup = await dns.lookup('localhost') localhost = lookup.address if (lookup.family === 6) { localhostForURL = `[${lookup.address}]` } else { localhostForURL = localhost } }) test('listen works without arguments', async t => { process.on('warning', () => { t.fail('should not be deprecated') }) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) await fastify.listen() const address = fastify.server.address() t.equal(address.address, localhost) t.ok(address.port > 0) }) test('Async/await listen with arguments', async t => { process.on('warning', () => { t.fail('should not be deprecated') }) t.plan(1) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) const addr = await fastify.listen({ port: 0, host: '0.0.0.0' }) const address = fastify.server.address() t.equal(addr, `http://${address.address}:${address.port}`) }) test('Promise listen with arguments', t => { process.on('warning', () => { t.fail('should not be deprecated') }) t.plan(1) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) fastify.listen({ port: 0, host: '0.0.0.0' }).then(addr => { const address = fastify.server.address() t.equal(addr, `http://${address.address}:${address.port}`) }) }) test('listen accepts a callback', t => { process.on('warning', () => { t.fail('should not be deprecated') }) t.plan(2) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) fastify.listen({ port: 0 }, (err) => { t.equal(fastify.server.address().address, localhost) t.error(err) }) }) test('listen accepts options and a callback', t => { process.on('warning', () => { t.fail('should not be deprecated') }) t.plan(1) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) fastify.listen({ port: 0, host: 'localhost', backlog: 511, exclusive: false, readableAll: false, writableAll: false, ipv6Only: false }, (err) => { t.error(err) }) }) test('listen after Promise.resolve()', t => { t.plan(2) const f = Fastify() t.teardown(f.close.bind(f)) Promise.resolve() .then(() => { f.listen({ port: 0 }, (err, address) => { f.server.unref() t.equal(address, `http://${localhostForURL}:${f.server.address().port}`) t.error(err) }) }) }) test('register after listen using Promise.resolve()', t => { t.plan(1) const f = Fastify() const handler = (req, res) => res.send({}) Promise.resolve() .then(() => { f.get('/', handler) f.register((f2, options, done) => { f2.get('/plugin', handler) done() }) return f.ready() }) .catch(t.error) .then(() => t.pass('resolved')) }) test('double listen errors', t => { t.plan(3) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) fastify.listen({ port: 0 }, (err) => { t.error(err) fastify.listen({ port: fastify.server.address().port }, (err, address) => { t.equal(address, null) t.ok(err) }) }) }) test('double listen errors callback with (err, address)', t => { t.plan(4) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) fastify.listen({ port: 0 }, (err1, address1) => { t.equal(address1, `http://${localhostForURL}:${fastify.server.address().port}`) t.error(err1) fastify.listen({ port: fastify.server.address().port }, (err2, address2) => { t.equal(address2, null) t.ok(err2) }) }) }) test('listen twice on the same port', t => { t.plan(4) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) fastify.listen({ port: 0 }, (err1, address1) => { t.equal(address1, `http://${localhostForURL}:${fastify.server.address().port}`) t.error(err1) const s2 = Fastify() t.teardown(s2.close.bind(s2)) s2.listen({ port: fastify.server.address().port }, (err2, address2) => { t.equal(address2, null) t.ok(err2) }) }) }) test('listen twice on the same port callback with (err, address)', t => { t.plan(4) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) fastify.listen({ port: 0 }, (err1, address1) => { const _port = fastify.server.address().port t.equal(address1, `http://${localhostForURL}:${_port}`) t.error(err1) const s2 = Fastify() t.teardown(s2.close.bind(s2)) s2.listen({ port: _port }, (err2, address2) => { t.equal(address2, null) t.ok(err2) }) }) }) // https://nodejs.org/api/net.html#net_ipc_support if (os.platform() !== 'win32') { test('listen on socket', t => { t.plan(3) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) const sockFile = path.join(os.tmpdir(), `${(Math.random().toString(16) + '0000000').substr(2, 8)}-server.sock`) try { fs.unlinkSync(sockFile) } catch (e) { } fastify.listen({ path: sockFile }, (err, address) => { t.error(err) t.equal(sockFile, fastify.server.address()) t.equal(address, sockFile) }) }) } test('listen without callback with (address)', t => { t.plan(1) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) fastify.listen({ port: 0 }) .then(address => { t.equal(address, `http://${localhostForURL}:${fastify.server.address().port}`) }) }) test('double listen without callback rejects', t => { t.plan(1) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) fastify.listen({ port: 0 }) .then(() => { fastify.listen({ port: 0 }) .catch(err => { t.ok(err) }) }) .catch(err => t.error(err)) }) test('double listen without callback with (address)', t => { t.plan(2) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) fastify.listen({ port: 0 }) .then(address => { t.equal(address, `http://${localhostForURL}:${fastify.server.address().port}`) fastify.listen({ port: 0 }) .catch(err => { t.ok(err) }) }) .catch(err => t.error(err)) }) test('listen twice on the same port without callback rejects', t => { t.plan(1) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) fastify.listen({ port: 0 }) .then(() => { const s2 = Fastify() t.teardown(s2.close.bind(s2)) s2.listen({ port: fastify.server.address().port }) .catch(err => { t.ok(err) }) }) .catch(err => t.error(err)) }) test('listen twice on the same port without callback rejects with (address)', t => { t.plan(2) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) fastify.listen({ port: 0 }) .then(address => { const s2 = Fastify() t.teardown(s2.close.bind(s2)) t.equal(address, `http://${localhostForURL}:${fastify.server.address().port}`) s2.listen({ port: fastify.server.address().port }) .catch(err => { t.ok(err) }) }) .catch(err => t.error(err)) }) test('listen on invalid port without callback rejects', t => { const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) return fastify.listen({ port: -1 }) .catch(err => { t.ok(err) return true }) }) test('listen logs the port as info', t => { t.plan(1) const fastify = Fastify() t.teardown(fastify.close.bind(fastify)) const msgs = [] fastify.log.info = function (msg) { msgs.push(msg) } fastify.listen({ port: 0 }) .then(() => { t.ok(/http:\/\//.test(msgs[0])) }) }) test('listen on localhost binds IPv4 and IPv6 - promise interface', async t => { const lookups = await dns.lookup('localhost', { all: true }) t.plan(2 * lookups.length) const app = Fastify() app.get('/', async () => 'hello localhost') t.teardown(app.close.bind(app)) await app.listen({ port: 0, host: 'localhost' }) for (const lookup of lookups) { await new Promise((resolve, reject) => { sget({ method: 'GET', url: getUrl(app, lookup) }, (err, response, body) => { if (err) { return reject(err) } t.equal(response.statusCode, 200) t.same(body.toString(), 'hello localhost') resolve() }) }) } }) test('listen on localhost binds to all interfaces (both IPv4 and IPv6 if present) - callback interface', t => { dnsCb.lookup('localhost', { all: true }, (err, lookups) => { t.plan(2 + (3 * lookups.length)) t.error(err) const app = Fastify() app.get('/', async () => 'hello localhost') app.listen({ port: 0, host: 'localhost' }, (err) => { t.error(err) t.teardown(app.close.bind(app)) for (const lookup of lookups) { sget({ method: 'GET', url: getUrl(app, lookup) }, (err, response, body) => { t.error(err) t.equal(response.statusCode, 200) t.same(body.toString(), 'hello localhost') }) } }) }) }) test('addresses getter', async t => { t.plan(4) const app = Fastify() app.get('/', async () => 'hello localhost') t.same(app.addresses(), [], 'before ready') await app.ready() t.same(app.addresses(), [], 'after ready') await app.listen({ port: 0, host: 'localhost' }) const { port } = app.server.address() const localAddresses = await dns.lookup('localhost', { all: true }) for (const address of localAddresses) { address.port = port if (typeof address.family === 'number') { address.family = 'IPv' + address.family } } const appAddresses = app.addresses() for (const address of appAddresses) { if (typeof address.family === 'number') { address.family = 'IPv' + address.family } } localAddresses.sort((a, b) => a.address.localeCompare(b.address)) appAddresses.sort((a, b) => a.address.localeCompare(b.address)) t.same(appAddresses, localAddresses, 'after listen') await app.close() t.same(app.addresses(), [], 'after close') }) function getUrl (fastify, lookup) { const { port } = fastify.server.address() if (lookup.family === 6) { return `http://[${lookup.address}]:${port}/` } else { return `http://${lookup.address}:${port}/` } }