First commit
This commit is contained in:
2023
node_modules/fastify/test/404s.test.js
generated
vendored
Normal file
2023
node_modules/fastify/test/404s.test.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
222
node_modules/fastify/test/500s.test.js
generated
vendored
Normal file
222
node_modules/fastify/test/500s.test.js
generated
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('..')
|
||||
const symbols = require('../lib/symbols.js')
|
||||
|
||||
test('default 500', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.get('/', function (req, reply) {
|
||||
reply.send(new Error('kaboom'))
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
t.equal(res.headers['content-type'], 'application/json; charset=utf-8')
|
||||
t.same(JSON.parse(res.payload), {
|
||||
error: 'Internal Server Error',
|
||||
message: 'kaboom',
|
||||
statusCode: 500
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('custom 500', t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify()
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.get('/', function (req, reply) {
|
||||
reply.send(new Error('kaboom'))
|
||||
})
|
||||
|
||||
fastify.setErrorHandler(function (err, request, reply) {
|
||||
t.type(request, 'object')
|
||||
t.type(request, fastify[symbols.kRequest].parent)
|
||||
reply
|
||||
.code(500)
|
||||
.type('text/plain')
|
||||
.send('an error happened: ' + err.message)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
t.equal(res.headers['content-type'], 'text/plain')
|
||||
t.same(res.payload.toString(), 'an error happened: kaboom')
|
||||
})
|
||||
})
|
||||
|
||||
test('encapsulated 500', t => {
|
||||
t.plan(10)
|
||||
|
||||
const fastify = Fastify()
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.get('/', function (req, reply) {
|
||||
reply.send(new Error('kaboom'))
|
||||
})
|
||||
|
||||
fastify.register(function (f, opts, done) {
|
||||
f.get('/', function (req, reply) {
|
||||
reply.send(new Error('kaboom'))
|
||||
})
|
||||
|
||||
f.setErrorHandler(function (err, request, reply) {
|
||||
t.type(request, 'object')
|
||||
t.type(request, fastify[symbols.kRequest].parent)
|
||||
reply
|
||||
.code(500)
|
||||
.type('text/plain')
|
||||
.send('an error happened: ' + err.message)
|
||||
})
|
||||
|
||||
done()
|
||||
}, { prefix: 'test' })
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/test'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
t.equal(res.headers['content-type'], 'text/plain')
|
||||
t.same(res.payload.toString(), 'an error happened: kaboom')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
t.equal(res.headers['content-type'], 'application/json; charset=utf-8')
|
||||
t.same(JSON.parse(res.payload), {
|
||||
error: 'Internal Server Error',
|
||||
message: 'kaboom',
|
||||
statusCode: 500
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('custom 500 with hooks', t => {
|
||||
t.plan(7)
|
||||
|
||||
const fastify = Fastify()
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.get('/', function (req, reply) {
|
||||
reply.send(new Error('kaboom'))
|
||||
})
|
||||
|
||||
fastify.setErrorHandler(function (err, request, reply) {
|
||||
reply
|
||||
.code(500)
|
||||
.type('text/plain')
|
||||
.send('an error happened: ' + err.message)
|
||||
})
|
||||
|
||||
fastify.addHook('onSend', (req, res, payload, done) => {
|
||||
t.ok('called', 'onSend')
|
||||
done()
|
||||
})
|
||||
fastify.addHook('onRequest', (req, res, done) => {
|
||||
t.ok('called', 'onRequest')
|
||||
done()
|
||||
})
|
||||
fastify.addHook('onResponse', (request, reply, done) => {
|
||||
t.ok('called', 'onResponse')
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
t.equal(res.headers['content-type'], 'text/plain')
|
||||
t.same(res.payload.toString(), 'an error happened: kaboom')
|
||||
})
|
||||
})
|
||||
|
||||
test('cannot set errorHandler after binding', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
try {
|
||||
fastify.setErrorHandler(() => { })
|
||||
t.fail()
|
||||
} catch (e) {
|
||||
t.pass()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('cannot set childLoggerFactory after binding', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
try {
|
||||
fastify.setChildLoggerFactory(() => { })
|
||||
t.fail()
|
||||
} catch (e) {
|
||||
t.pass()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('catch synchronous errors', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.setErrorHandler((_, req, reply) => {
|
||||
throw new Error('kaboom2')
|
||||
})
|
||||
|
||||
fastify.post('/', function (req, reply) {
|
||||
reply.send(new Error('kaboom'))
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
payload: JSON.stringify({ hello: 'world' }).substring(0, 5)
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
t.same(res.json(), {
|
||||
error: 'Internal Server Error',
|
||||
message: 'kaboom2',
|
||||
statusCode: 500
|
||||
})
|
||||
})
|
||||
})
|
||||
117
node_modules/fastify/test/allowUnsafeRegex.test.js
generated
vendored
Normal file
117
node_modules/fastify/test/allowUnsafeRegex.test.js
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('..')
|
||||
const sget = require('simple-get').concat
|
||||
|
||||
test('allow unsafe regex', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify({
|
||||
allowUnsafeRegex: false
|
||||
})
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.get('/:foo(^[0-9]*$)', (req, reply) => {
|
||||
reply.send({ foo: req.params.foo })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/1234'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(body), {
|
||||
foo: '1234'
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('allow unsafe regex not match', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify({
|
||||
allowUnsafeRegex: false
|
||||
})
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.get('/:foo(^[0-9]*$)', (req, reply) => {
|
||||
reply.send({ foo: req.params.foo })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/a1234'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 404)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('allow unsafe regex not safe', t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify({
|
||||
allowUnsafeRegex: false
|
||||
})
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
t.throws(() => {
|
||||
fastify.get('/:foo(^([0-9]+){4}$)', (req, reply) => {
|
||||
reply.send({ foo: req.params.foo })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('allow unsafe regex not safe by default', t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
t.throws(() => {
|
||||
fastify.get('/:foo(^([0-9]+){4}$)', (req, reply) => {
|
||||
reply.send({ foo: req.params.foo })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('allow unsafe regex allow unsafe', t => {
|
||||
t.plan(5)
|
||||
|
||||
const fastify = Fastify({
|
||||
allowUnsafeRegex: true
|
||||
})
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
t.doesNotThrow(() => {
|
||||
fastify.get('/:foo(^([0-9]+){4}$)', (req, reply) => {
|
||||
reply.send({ foo: req.params.foo })
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/1234'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(body), {
|
||||
foo: '1234'
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
74
node_modules/fastify/test/als.test.js
generated
vendored
Normal file
74
node_modules/fastify/test/als.test.js
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
'use strict'
|
||||
|
||||
const { AsyncLocalStorage } = require('node:async_hooks')
|
||||
const t = require('tap')
|
||||
const Fastify = require('..')
|
||||
const sget = require('simple-get').concat
|
||||
|
||||
if (!AsyncLocalStorage) {
|
||||
t.skip('AsyncLocalStorage not available, skipping test')
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
const storage = new AsyncLocalStorage()
|
||||
const app = Fastify({ logger: false })
|
||||
|
||||
let counter = 0
|
||||
app.addHook('onRequest', (req, reply, next) => {
|
||||
const id = counter++
|
||||
storage.run({ id }, next)
|
||||
})
|
||||
|
||||
app.get('/', function (request, reply) {
|
||||
t.ok(storage.getStore())
|
||||
const id = storage.getStore().id
|
||||
reply.send({ id })
|
||||
})
|
||||
|
||||
app.post('/', function (request, reply) {
|
||||
t.ok(storage.getStore())
|
||||
const id = storage.getStore().id
|
||||
reply.send({ id })
|
||||
})
|
||||
|
||||
app.listen({ port: 0 }, function (err, address) {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: 'http://localhost:' + app.server.address().port,
|
||||
body: {
|
||||
hello: 'world'
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body, { id: 0 })
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: 'http://localhost:' + app.server.address().port,
|
||||
body: {
|
||||
hello: 'world'
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body, { id: 1 })
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + app.server.address().port,
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body, { id: 2 })
|
||||
app.close()
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
691
node_modules/fastify/test/async-await.test.js
generated
vendored
Normal file
691
node_modules/fastify/test/async-await.test.js
generated
vendored
Normal file
@@ -0,0 +1,691 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const sget = require('simple-get').concat
|
||||
const Fastify = require('..')
|
||||
const split = require('split2')
|
||||
const pino = require('pino')
|
||||
const { sleep } = require('./helper')
|
||||
const statusCodes = require('node:http').STATUS_CODES
|
||||
|
||||
const opts = {
|
||||
schema: {
|
||||
response: {
|
||||
'2xx': {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test('async await', t => {
|
||||
t.plan(11)
|
||||
const fastify = Fastify()
|
||||
try {
|
||||
fastify.get('/', opts, async function awaitMyFunc (req, reply) {
|
||||
await sleep(200)
|
||||
return { hello: 'world' }
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
|
||||
try {
|
||||
fastify.get('/no-await', opts, async function (req, reply) {
|
||||
return { hello: 'world' }
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-length'], '' + body.length)
|
||||
t.same(JSON.parse(body), { hello: 'world' })
|
||||
})
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/no-await'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-length'], '' + body.length)
|
||||
t.same(JSON.parse(body), { hello: 'world' })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('ignore the result of the promise if reply.send is called beforehand (undefined)', t => {
|
||||
t.plan(4)
|
||||
|
||||
const server = Fastify()
|
||||
const payload = { hello: 'world' }
|
||||
|
||||
server.get('/', async function awaitMyFunc (req, reply) {
|
||||
await reply.send(payload)
|
||||
})
|
||||
|
||||
t.teardown(server.close.bind(server))
|
||||
|
||||
server.listen({ port: 0 }, (err) => {
|
||||
t.error(err)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + server.server.address().port + '/'
|
||||
}, (err, res, body) => {
|
||||
t.error(err)
|
||||
t.same(payload, JSON.parse(body))
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('ignore the result of the promise if reply.send is called beforehand (object)', t => {
|
||||
t.plan(4)
|
||||
|
||||
const server = Fastify()
|
||||
const payload = { hello: 'world2' }
|
||||
|
||||
server.get('/', async function awaitMyFunc (req, reply) {
|
||||
await reply.send(payload)
|
||||
return { hello: 'world' }
|
||||
})
|
||||
|
||||
t.teardown(server.close.bind(server))
|
||||
|
||||
server.listen({ port: 0 }, (err) => {
|
||||
t.error(err)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + server.server.address().port + '/'
|
||||
}, (err, res, body) => {
|
||||
t.error(err)
|
||||
t.same(payload, JSON.parse(body))
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('server logs an error if reply.send is called and a value is returned via async/await', t => {
|
||||
const lines = ['incoming request', 'request completed', 'Reply was already sent, did you forget to "return reply" in "/" (GET)?']
|
||||
t.plan(lines.length + 2)
|
||||
|
||||
const splitStream = split(JSON.parse)
|
||||
splitStream.on('data', (line) => {
|
||||
t.equal(line.msg, lines.shift())
|
||||
})
|
||||
|
||||
const logger = pino(splitStream)
|
||||
|
||||
const fastify = Fastify({
|
||||
logger
|
||||
})
|
||||
|
||||
fastify.get('/', async (req, reply) => {
|
||||
await reply.send({ hello: 'world' })
|
||||
return { hello: 'world2' }
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.same(payload, { hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
test('ignore the result of the promise if reply.send is called beforehand (undefined)', t => {
|
||||
t.plan(4)
|
||||
|
||||
const server = Fastify()
|
||||
const payload = { hello: 'world' }
|
||||
|
||||
server.get('/', async function awaitMyFunc (req, reply) {
|
||||
await reply.send(payload)
|
||||
})
|
||||
|
||||
t.teardown(server.close.bind(server))
|
||||
|
||||
server.listen({ port: 0 }, (err) => {
|
||||
t.error(err)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + server.server.address().port + '/'
|
||||
}, (err, res, body) => {
|
||||
t.error(err)
|
||||
t.same(payload, JSON.parse(body))
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('ignore the result of the promise if reply.send is called beforehand (object)', t => {
|
||||
t.plan(4)
|
||||
|
||||
const server = Fastify()
|
||||
const payload = { hello: 'world2' }
|
||||
|
||||
server.get('/', async function awaitMyFunc (req, reply) {
|
||||
await reply.send(payload)
|
||||
return { hello: 'world' }
|
||||
})
|
||||
|
||||
t.teardown(server.close.bind(server))
|
||||
|
||||
server.listen({ port: 0 }, (err) => {
|
||||
t.error(err)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + server.server.address().port + '/'
|
||||
}, (err, res, body) => {
|
||||
t.error(err)
|
||||
t.same(payload, JSON.parse(body))
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('await reply if we will be calling reply.send in the future', t => {
|
||||
const lines = ['incoming request', 'request completed']
|
||||
t.plan(lines.length + 2)
|
||||
|
||||
const splitStream = split(JSON.parse)
|
||||
splitStream.on('data', (line) => {
|
||||
t.equal(line.msg, lines.shift())
|
||||
})
|
||||
|
||||
const server = Fastify({
|
||||
logger: {
|
||||
stream: splitStream
|
||||
}
|
||||
})
|
||||
const payload = { hello: 'world' }
|
||||
|
||||
server.get('/', async function awaitMyFunc (req, reply) {
|
||||
setImmediate(function () {
|
||||
reply.send(payload)
|
||||
})
|
||||
|
||||
await reply
|
||||
})
|
||||
|
||||
server.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.same(payload, { hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
test('await reply if we will be calling reply.send in the future (error case)', t => {
|
||||
const lines = ['incoming request', 'kaboom', 'request completed']
|
||||
t.plan(lines.length + 2)
|
||||
|
||||
const splitStream = split(JSON.parse)
|
||||
splitStream.on('data', (line) => {
|
||||
t.equal(line.msg, lines.shift())
|
||||
})
|
||||
|
||||
const server = Fastify({
|
||||
logger: {
|
||||
stream: splitStream
|
||||
}
|
||||
})
|
||||
|
||||
server.get('/', async function awaitMyFunc (req, reply) {
|
||||
setImmediate(function () {
|
||||
reply.send(new Error('kaboom'))
|
||||
})
|
||||
|
||||
await reply
|
||||
})
|
||||
|
||||
server.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
})
|
||||
})
|
||||
|
||||
test('support reply decorators with await', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.decorateReply('wow', function () {
|
||||
setImmediate(() => {
|
||||
this.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
return this
|
||||
})
|
||||
|
||||
fastify.get('/', async (req, reply) => {
|
||||
await sleep(1)
|
||||
await reply.wow()
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.same(payload, { hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
test('inject async await', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
try {
|
||||
const res = await fastify.inject({ method: 'GET', url: '/' })
|
||||
t.same({ hello: 'world' }, JSON.parse(res.payload))
|
||||
} catch (err) {
|
||||
t.fail(err)
|
||||
}
|
||||
})
|
||||
|
||||
test('inject async await - when the server equal up', async t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
try {
|
||||
const res = await fastify.inject({ method: 'GET', url: '/' })
|
||||
t.same({ hello: 'world' }, JSON.parse(res.payload))
|
||||
} catch (err) {
|
||||
t.fail(err)
|
||||
}
|
||||
|
||||
await sleep(200)
|
||||
|
||||
try {
|
||||
const res2 = await fastify.inject({ method: 'GET', url: '/' })
|
||||
t.same({ hello: 'world' }, JSON.parse(res2.payload))
|
||||
} catch (err) {
|
||||
t.fail(err)
|
||||
}
|
||||
})
|
||||
|
||||
test('async await plugin', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(async (fastify, opts) => {
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await sleep(200)
|
||||
})
|
||||
|
||||
try {
|
||||
const res = await fastify.inject({ method: 'GET', url: '/' })
|
||||
t.same({ hello: 'world' }, JSON.parse(res.payload))
|
||||
} catch (err) {
|
||||
t.fail(err)
|
||||
}
|
||||
})
|
||||
|
||||
test('does not call reply.send() twice if 204 response equal already sent', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/', async (req, reply) => {
|
||||
reply.code(204).send()
|
||||
reply.send = () => {
|
||||
throw new Error('reply.send() was called twice')
|
||||
}
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 204)
|
||||
})
|
||||
})
|
||||
|
||||
test('promise was fulfilled with undefined', t => {
|
||||
t.plan(4)
|
||||
|
||||
let fastify = null
|
||||
const stream = split(JSON.parse)
|
||||
try {
|
||||
fastify = Fastify({
|
||||
logger: {
|
||||
stream,
|
||||
level: 'error'
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.get('/', async (req, reply) => {
|
||||
})
|
||||
|
||||
stream.once('data', line => {
|
||||
t.fail('should not log an error')
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, (err) => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/'
|
||||
}, (err, res, body) => {
|
||||
t.error(err)
|
||||
t.equal(res.body, undefined)
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('promise was fulfilled with undefined using inject', async (t) => {
|
||||
const stream = split(JSON.parse)
|
||||
const fastify = Fastify({
|
||||
logger: {
|
||||
stream,
|
||||
level: 'error'
|
||||
}
|
||||
})
|
||||
|
||||
fastify.get('/', async (req, reply) => {
|
||||
})
|
||||
|
||||
stream.once('data', line => {
|
||||
t.fail('should not log an error')
|
||||
})
|
||||
|
||||
const res = await fastify.inject('/')
|
||||
|
||||
t.equal(res.body, '')
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
|
||||
test('error is not logged because promise was fulfilled with undefined but response was sent before promise resolution', t => {
|
||||
t.plan(4)
|
||||
|
||||
let fastify = null
|
||||
const stream = split(JSON.parse)
|
||||
const payload = { hello: 'world' }
|
||||
try {
|
||||
fastify = Fastify({
|
||||
logger: {
|
||||
stream,
|
||||
level: 'error'
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.get('/', async (req, reply) => {
|
||||
reply.send(payload)
|
||||
})
|
||||
|
||||
stream.once('data', line => {
|
||||
t.fail('should not log an error')
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, (err) => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/'
|
||||
}, (err, res, body) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 200)
|
||||
t.same(
|
||||
payload,
|
||||
JSON.parse(body)
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Thrown Error instance sets HTTP status code', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
const err = new Error('winter is coming')
|
||||
err.statusCode = 418
|
||||
|
||||
fastify.get('/', async (req, reply) => {
|
||||
throw err
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (error, res) => {
|
||||
t.error(error)
|
||||
t.equal(res.statusCode, 418)
|
||||
t.same(
|
||||
{
|
||||
error: statusCodes['418'],
|
||||
message: err.message,
|
||||
statusCode: 418
|
||||
},
|
||||
JSON.parse(res.payload)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test('customErrorHandler support', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/', async (req, reply) => {
|
||||
const error = new Error('ouch')
|
||||
error.statusCode = 400
|
||||
throw error
|
||||
})
|
||||
|
||||
fastify.setErrorHandler(async err => {
|
||||
t.equal(err.message, 'ouch')
|
||||
const error = new Error('kaboom')
|
||||
error.statusCode = 401
|
||||
throw error
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 401)
|
||||
t.same(
|
||||
{
|
||||
error: statusCodes['401'],
|
||||
message: 'kaboom',
|
||||
statusCode: 401
|
||||
},
|
||||
JSON.parse(res.payload)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test('customErrorHandler support without throwing', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/', async (req, reply) => {
|
||||
const error = new Error('ouch')
|
||||
error.statusCode = 400
|
||||
throw error
|
||||
})
|
||||
|
||||
fastify.setErrorHandler(async (err, req, reply) => {
|
||||
t.equal(err.message, 'ouch')
|
||||
await reply.code(401).send('kaboom')
|
||||
reply.send = t.fail.bind(t, 'should not be called')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 401)
|
||||
t.same(
|
||||
'kaboom',
|
||||
res.payload
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
// See https://github.com/fastify/fastify/issues/2653
|
||||
test('customErrorHandler only called if reply not already sent', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/', async (req, reply) => {
|
||||
await reply.send('success')
|
||||
const error = new Error('ouch')
|
||||
error.statusCode = 400
|
||||
throw error
|
||||
})
|
||||
|
||||
fastify.setErrorHandler(t.fail.bind(t, 'should not be called'))
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 200)
|
||||
t.same(
|
||||
'success',
|
||||
res.payload
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
// See https://github.com/fastify/fastify/issues/3209
|
||||
test('setNotFoundHandler should accept return value', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/', async () => ({ hello: 'world' }))
|
||||
|
||||
fastify.setNotFoundHandler((req, reply) => {
|
||||
reply.code(404)
|
||||
return {
|
||||
error: statusCodes['404'],
|
||||
message: 'lost',
|
||||
statusCode: 404
|
||||
}
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/elsewhere'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 404)
|
||||
t.same(
|
||||
{
|
||||
error: statusCodes['404'],
|
||||
message: 'lost',
|
||||
statusCode: 404
|
||||
},
|
||||
JSON.parse(res.payload)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
// See https://github.com/fastify/fastify/issues/3209
|
||||
test('customErrorHandler should accept return value', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/', async (req, reply) => {
|
||||
const error = new Error('ouch')
|
||||
error.statusCode = 400
|
||||
throw error
|
||||
})
|
||||
|
||||
fastify.setErrorHandler((err, req, reply) => {
|
||||
t.equal(err.message, 'ouch')
|
||||
reply.code(401)
|
||||
return {
|
||||
error: statusCodes['401'],
|
||||
message: 'kaboom',
|
||||
statusCode: 401
|
||||
}
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 401)
|
||||
t.same(
|
||||
{
|
||||
error: statusCodes['401'],
|
||||
message: 'kaboom',
|
||||
statusCode: 401
|
||||
},
|
||||
JSON.parse(res.payload)
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test('await self', async t => {
|
||||
const app = Fastify()
|
||||
t.equal(await app, app)
|
||||
})
|
||||
21
node_modules/fastify/test/async-dispose.test.js
generated
vendored
Normal file
21
node_modules/fastify/test/async-dispose.test.js
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const Fastify = require('../fastify')
|
||||
|
||||
// asyncDispose doesn't exist in node <= 16
|
||||
t.test('async dispose should close fastify', { skip: !('asyncDispose' in Symbol) }, async t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
await fastify.listen({ port: 0 })
|
||||
|
||||
t.equal(fastify.server.listening, true)
|
||||
|
||||
// the same as syntax sugar for
|
||||
// await using app = fastify()
|
||||
await fastify[Symbol.asyncDispose]()
|
||||
|
||||
t.equal(fastify.server.listening, false)
|
||||
})
|
||||
69
node_modules/fastify/test/async_hooks.test.js
generated
vendored
Normal file
69
node_modules/fastify/test/async_hooks.test.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
'use strict'
|
||||
|
||||
const { createHook } = require('node:async_hooks')
|
||||
const t = require('tap')
|
||||
const Fastify = require('..')
|
||||
const sget = require('simple-get').concat
|
||||
|
||||
const remainingIds = new Set()
|
||||
|
||||
createHook({
|
||||
init (asyncId, type, triggerAsyncId, resource) {
|
||||
if (type === 'content-type-parser:run') {
|
||||
remainingIds.add(asyncId)
|
||||
}
|
||||
},
|
||||
destroy (asyncId) {
|
||||
remainingIds.delete(asyncId)
|
||||
}
|
||||
})
|
||||
|
||||
const app = Fastify({ logger: false })
|
||||
|
||||
app.get('/', function (request, reply) {
|
||||
reply.send({ id: 42 })
|
||||
})
|
||||
|
||||
app.post('/', function (request, reply) {
|
||||
reply.send({ id: 42 })
|
||||
})
|
||||
|
||||
app.listen({ port: 0 }, function (err, address) {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: 'http://localhost:' + app.server.address().port,
|
||||
body: {
|
||||
hello: 'world'
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: 'http://localhost:' + app.server.address().port,
|
||||
body: {
|
||||
hello: 'world'
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + app.server.address().port,
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
app.close()
|
||||
t.equal(remainingIds.size, 0)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
194
node_modules/fastify/test/bodyLimit.test.js
generated
vendored
Normal file
194
node_modules/fastify/test/bodyLimit.test.js
generated
vendored
Normal file
@@ -0,0 +1,194 @@
|
||||
'use strict'
|
||||
|
||||
const Fastify = require('..')
|
||||
const sget = require('simple-get').concat
|
||||
const zlib = require('node:zlib')
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
|
||||
test('bodyLimit', t => {
|
||||
t.plan(5)
|
||||
|
||||
try {
|
||||
Fastify({ bodyLimit: 1.3 })
|
||||
t.fail('option must be an integer')
|
||||
} catch (err) {
|
||||
t.ok(err)
|
||||
}
|
||||
|
||||
try {
|
||||
Fastify({ bodyLimit: [] })
|
||||
t.fail('option must be an integer')
|
||||
} catch (err) {
|
||||
t.ok(err)
|
||||
}
|
||||
|
||||
const fastify = Fastify({ bodyLimit: 1 })
|
||||
|
||||
fastify.post('/', (request, reply) => {
|
||||
reply.send({ error: 'handler should not be called' })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, function (err) {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: [],
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 413)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('bodyLimit is applied to decoded content', t => {
|
||||
t.plan(9)
|
||||
|
||||
const body = { x: 'x'.repeat(30000) }
|
||||
const json = JSON.stringify(body)
|
||||
const encoded = zlib.gzipSync(json)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addHook('preParsing', async (req, reply, payload) => {
|
||||
t.equal(req.headers['content-length'], `${encoded.length}`)
|
||||
const unzip = zlib.createGunzip()
|
||||
Object.defineProperty(unzip, 'receivedEncodedLength', {
|
||||
get () {
|
||||
return unzip.bytesWritten
|
||||
}
|
||||
})
|
||||
payload.pipe(unzip)
|
||||
return unzip
|
||||
})
|
||||
|
||||
fastify.post('/body-limit-40k', {
|
||||
bodyLimit: 40000,
|
||||
onError: async (req, res, err) => {
|
||||
t.fail('should not be called')
|
||||
}
|
||||
}, (request, reply) => {
|
||||
reply.send({ x: request.body.x })
|
||||
})
|
||||
|
||||
fastify.post('/body-limit-20k', {
|
||||
bodyLimit: 20000,
|
||||
onError: async (req, res, err) => {
|
||||
t.equal(err.code, 'FST_ERR_CTP_BODY_TOO_LARGE')
|
||||
t.equal(err.statusCode, 413)
|
||||
}
|
||||
}, (request, reply) => {
|
||||
reply.send({ x: 'handler should not be called' })
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/body-limit-40k',
|
||||
headers: {
|
||||
'content-encoding': 'gzip',
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
payload: encoded
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 200)
|
||||
t.same(res.json(), body)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/body-limit-20k',
|
||||
headers: {
|
||||
'content-encoding': 'gzip',
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
payload: encoded
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 413)
|
||||
})
|
||||
})
|
||||
|
||||
test('default request.routeOptions.bodyLimit should be 1048576', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
fastify.post('/default-bodylimit', {
|
||||
handler (request, reply) {
|
||||
t.equal(1048576, request.routeOptions.bodyLimit)
|
||||
reply.send({ })
|
||||
}
|
||||
})
|
||||
fastify.listen({ port: 0 }, function (err) {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/default-bodylimit',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: [],
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('request.routeOptions.bodyLimit should be equal to route limit', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify({ bodyLimit: 1 })
|
||||
fastify.post('/route-limit', {
|
||||
bodyLimit: 1000,
|
||||
handler (request, reply) {
|
||||
t.equal(1000, request.routeOptions.bodyLimit)
|
||||
reply.send({})
|
||||
}
|
||||
})
|
||||
fastify.listen({ port: 0 }, function (err) {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/route-limit',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: [],
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('request.routeOptions.bodyLimit should be equal to server limit', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify({ bodyLimit: 100 })
|
||||
fastify.post('/server-limit', {
|
||||
handler (request, reply) {
|
||||
t.equal(100, request.routeOptions.bodyLimit)
|
||||
reply.send({})
|
||||
}
|
||||
})
|
||||
fastify.listen({ port: 0 }, function (err) {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/server-limit',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: [],
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
})
|
||||
53
node_modules/fastify/test/buffer.test.js
generated
vendored
Normal file
53
node_modules/fastify/test/buffer.test.js
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('..')
|
||||
|
||||
test('Buffer test', async t => {
|
||||
const fastify = Fastify()
|
||||
fastify.addContentTypeParser('application/json', { parseAs: 'buffer' }, fastify.getDefaultJsonParser('error', 'ignore'))
|
||||
|
||||
fastify.delete('/', async (request) => {
|
||||
return request.body
|
||||
})
|
||||
|
||||
test('should return 200 if the body is not empty', async t => {
|
||||
t.plan(3)
|
||||
|
||||
const response = await fastify.inject({
|
||||
method: 'DELETE',
|
||||
url: '/',
|
||||
payload: Buffer.from('{"hello":"world"}'),
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
t.error(response.error)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(response.payload.toString(), '{"hello":"world"}')
|
||||
})
|
||||
|
||||
test('should return 400 if the body is empty', async t => {
|
||||
t.plan(3)
|
||||
|
||||
const response = await fastify.inject({
|
||||
method: 'DELETE',
|
||||
url: '/',
|
||||
payload: Buffer.alloc(0),
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
t.error(response.error)
|
||||
t.equal(response.statusCode, 400)
|
||||
t.same(JSON.parse(response.payload.toString()), {
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_CTP_EMPTY_JSON_BODY',
|
||||
message: 'Body cannot be empty when content-type is set to \'application/json\'',
|
||||
statusCode: 400
|
||||
})
|
||||
})
|
||||
})
|
||||
109
node_modules/fastify/test/build-certificate.js
generated
vendored
Normal file
109
node_modules/fastify/test/build-certificate.js
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
'use strict'
|
||||
|
||||
const os = require('os')
|
||||
const forge = require('node-forge')
|
||||
|
||||
// from self-cert module
|
||||
function selfCert (opts) {
|
||||
const options = opts || {}
|
||||
const log = opts.logger || require('abstract-logging')
|
||||
const now = new Date()
|
||||
|
||||
if (!options.attrs) options.attrs = {}
|
||||
if (!options.expires) {
|
||||
options.expires = new Date(
|
||||
now.getFullYear() + 5, now.getMonth() + 1, now.getDate()
|
||||
)
|
||||
}
|
||||
|
||||
log.debug('generating key pair')
|
||||
const keys = forge.pki.rsa.generateKeyPair(options.bits || 2048)
|
||||
log.debug('key pair generated')
|
||||
|
||||
log.debug('generating self-signed certificate')
|
||||
const cert = forge.pki.createCertificate()
|
||||
cert.publicKey = keys.publicKey
|
||||
cert.serialNumber = '01'
|
||||
cert.validity.notBefore = now
|
||||
cert.validity.notAfter = options.expires
|
||||
|
||||
const attrs = [
|
||||
{ name: 'commonName', value: options.attrs.commonName || os.hostname() },
|
||||
{ name: 'countryName', value: options.attrs.countryName || 'US' },
|
||||
{ name: 'stateOrProvinceName', value: options.attrs.stateName || 'Georgia' },
|
||||
{ name: 'localityName', value: options.attrs.locality || 'Atlanta' },
|
||||
{ name: 'organizationName', value: options.attrs.orgName || 'None' },
|
||||
{ shortName: 'OU', value: options.attrs.shortName || 'example' }
|
||||
]
|
||||
cert.setSubject(attrs)
|
||||
cert.setIssuer(attrs)
|
||||
|
||||
cert.setExtensions([
|
||||
{ name: 'basicConstraints', cA: true },
|
||||
{
|
||||
name: 'keyUsage',
|
||||
keyCertSign: true,
|
||||
digitalSignature: true,
|
||||
nonRepudiation: true,
|
||||
keyEncipherment: true,
|
||||
dataEncipherment: true
|
||||
},
|
||||
{
|
||||
name: 'extKeyUsage',
|
||||
serverAuth: true,
|
||||
clientAuth: true,
|
||||
codeSigning: true,
|
||||
emailProtection: true,
|
||||
timeStamping: true
|
||||
},
|
||||
{
|
||||
name: 'nsCertType',
|
||||
client: true,
|
||||
server: true,
|
||||
email: true,
|
||||
objsign: true,
|
||||
sslCA: true,
|
||||
emailCA: true,
|
||||
objCA: true
|
||||
},
|
||||
{ name: 'subjectKeyIdentifier' },
|
||||
{
|
||||
name: 'subjectAltName',
|
||||
altNames: [{ type: 6 /* URI */, value: 'DNS: ' + attrs[0].value }].concat((function () {
|
||||
const interfaces = os.networkInterfaces()
|
||||
|
||||
// fix citgm: skip invalid ips (aix72-ppc64)
|
||||
const ips = Object.values(interfaces).flat()
|
||||
.filter(i => !!forge.util.bytesFromIP(i.address))
|
||||
.map(i => ({ type: 7 /* IP */, ip: i.address }))
|
||||
|
||||
return ips
|
||||
}()))
|
||||
}
|
||||
])
|
||||
|
||||
cert.sign(keys.privateKey)
|
||||
log.debug('certificate generated')
|
||||
return {
|
||||
privateKey: forge.pki.privateKeyToPem(keys.privateKey),
|
||||
publicKey: forge.pki.publicKeyToPem(keys.publicKey),
|
||||
certificate: forge.pki.certificateToPem(cert)
|
||||
}
|
||||
}
|
||||
|
||||
async function buildCertificate () {
|
||||
// "global" is used in here because "t.context" is only supported by "t.beforeEach" and "t.afterEach"
|
||||
// For the test case which execute this code which will be using `t.before` and it can reduce the
|
||||
// number of times executing it.
|
||||
if (!global.context || !global.context.cert || !global.context.key) {
|
||||
const certs = selfCert({
|
||||
expires: new Date(Date.now() + 86400000)
|
||||
})
|
||||
global.context = {
|
||||
cert: certs.certificate,
|
||||
key: certs.privateKey
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { buildCertificate }
|
||||
35
node_modules/fastify/test/build/error-serializer.test.js
generated
vendored
Normal file
35
node_modules/fastify/test/build/error-serializer.test.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
|
||||
const { code } = require('../../build/build-error-serializer')
|
||||
|
||||
function unifyLineBreak (str) {
|
||||
return str.toString().replace(/\r\n/g, '\n')
|
||||
}
|
||||
|
||||
test('check generated code syntax', async (t) => {
|
||||
t.plan(1)
|
||||
|
||||
// standard is a esm, we import it like this
|
||||
const { default: standard } = await import('standard')
|
||||
const result = await standard.lintText(code)
|
||||
|
||||
// if there are any invalid syntax
|
||||
// fatal count will be greater than 0
|
||||
t.equal(result[0].fatalErrorCount, 0)
|
||||
})
|
||||
|
||||
const isPrepublish = !!process.env.PREPUBLISH
|
||||
|
||||
test('ensure the current error serializer is latest', { skip: !isPrepublish }, async (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const current = await fs.promises.readFile(path.resolve('lib/error-serializer.js'))
|
||||
|
||||
// line break should not be a problem depends on system
|
||||
t.equal(unifyLineBreak(current), unifyLineBreak(code))
|
||||
})
|
||||
15
node_modules/fastify/test/build/version.test.js
generated
vendored
Normal file
15
node_modules/fastify/test/build/version.test.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
'use strict'
|
||||
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const fastify = require('../../fastify')()
|
||||
|
||||
test('should be the same as package.json', t => {
|
||||
t.plan(1)
|
||||
|
||||
const json = JSON.parse(fs.readFileSync(path.join(__dirname, '..', '..', 'package.json')).toString('utf8'))
|
||||
|
||||
t.equal(fastify.version, json.version)
|
||||
})
|
||||
29
node_modules/fastify/test/bundler/README.md
generated
vendored
Normal file
29
node_modules/fastify/test/bundler/README.md
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
# Bundlers test stack
|
||||
|
||||
In some cases, developers bundle their apps for several targets such as serverless applications.
|
||||
Even if it's not recommended by Fastify team; we need to ensure we do not break the build process.
|
||||
Please note this might result in features behaving differently, like the version handling check for plugins.
|
||||
|
||||
## Test bundlers
|
||||
|
||||
The bundler test stack has been defined separately from the rest of the Unit testing stack because it's not a
|
||||
part of the fastify lib itself. Note that the tests run in CI only on NodeJs LTS version.
|
||||
Developers do not need to install every bundler to run unit tests.
|
||||
|
||||
To run the bundler tests you will need to install the repository dependencies followed by the bundler
|
||||
stack dependencies. See:
|
||||
|
||||
```bash
|
||||
# path: root of repository /fastify
|
||||
npm i
|
||||
cd test/bundler/webpack
|
||||
npm i
|
||||
npm run test # test command runs bundle before of starting the test
|
||||
```
|
||||
|
||||
## Bundler test development
|
||||
|
||||
To not break the fastify unit testing stack please name test files like this `*-test.js` and not `*.test.js`,
|
||||
otherwise it will be targeted by the regular expression used for unit tests for fastify.
|
||||
Tests need to ensure the build process works and the fastify application can be run,
|
||||
no need to go in deep testing unless an issue is raised.
|
||||
31
node_modules/fastify/test/bundler/esbuild/bundler-test.js
generated
vendored
Normal file
31
node_modules/fastify/test/bundler/esbuild/bundler-test.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const fastifySuccess = require('./dist/success')
|
||||
const fastifyFailPlugin = require('./dist/failPlugin')
|
||||
|
||||
test('Bundled package should work', (t) => {
|
||||
t.plan(4)
|
||||
fastifySuccess.ready((err) => {
|
||||
t.error(err)
|
||||
fastifySuccess.inject(
|
||||
{
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
},
|
||||
(error, res) => {
|
||||
t.error(error)
|
||||
t.equal(res.statusCode, 200)
|
||||
t.same(res.json(), { hello: 'world' })
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test('Bundled package should not work with bad plugin version', (t) => {
|
||||
t.plan(1)
|
||||
fastifyFailPlugin.ready((err) => {
|
||||
t.match(err.message, /expected '9.x' fastify version/i)
|
||||
})
|
||||
})
|
||||
10
node_modules/fastify/test/bundler/esbuild/package.json
generated
vendored
Normal file
10
node_modules/fastify/test/bundler/esbuild/package.json
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"bundle": "esbuild success=src/index.js failPlugin=src/fail-plugin-version.js --bundle --outdir=dist --platform=node",
|
||||
"test": "npm run bundle && node bundler-test.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.14.11"
|
||||
}
|
||||
}
|
||||
14
node_modules/fastify/test/bundler/esbuild/src/fail-plugin-version.js
generated
vendored
Normal file
14
node_modules/fastify/test/bundler/esbuild/src/fail-plugin-version.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict'
|
||||
|
||||
const fp = require('fastify-plugin')
|
||||
const fastify = require('../../../../')()
|
||||
|
||||
fastify.get('/', function (request, reply) {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.register(fp((instance, opts, done) => {
|
||||
done()
|
||||
}, { fastify: '9.x' }))
|
||||
|
||||
module.exports = fastify
|
||||
9
node_modules/fastify/test/bundler/esbuild/src/index.js
generated
vendored
Normal file
9
node_modules/fastify/test/bundler/esbuild/src/index.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
'use strict'
|
||||
|
||||
const fastify = require('../../../../')()
|
||||
// Declare a route
|
||||
fastify.get('/', function (request, reply) {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
module.exports = fastify
|
||||
31
node_modules/fastify/test/bundler/webpack/bundler-test.js
generated
vendored
Normal file
31
node_modules/fastify/test/bundler/webpack/bundler-test.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const fastifySuccess = require('./dist/success')
|
||||
const fastifyFailPlugin = require('./dist/failPlugin')
|
||||
|
||||
test('Bundled package should work', (t) => {
|
||||
t.plan(4)
|
||||
fastifySuccess.ready((err) => {
|
||||
t.error(err)
|
||||
fastifySuccess.inject(
|
||||
{
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
},
|
||||
(error, res) => {
|
||||
t.error(error)
|
||||
t.equal(res.statusCode, 200)
|
||||
t.same(res.json(), { hello: 'world' })
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test('Bundled package should not work with bad plugin version', (t) => {
|
||||
t.plan(1)
|
||||
fastifyFailPlugin.ready((err) => {
|
||||
t.match(err.message, /expected '9.x' fastify version/i)
|
||||
})
|
||||
})
|
||||
11
node_modules/fastify/test/bundler/webpack/package.json
generated
vendored
Normal file
11
node_modules/fastify/test/bundler/webpack/package.json
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"version":"0.0.1",
|
||||
"scripts": {
|
||||
"bundle": "webpack",
|
||||
"test": "npm run bundle && node bundler-test.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"webpack": "^5.49.0",
|
||||
"webpack-cli": "^4.7.2"
|
||||
}
|
||||
}
|
||||
14
node_modules/fastify/test/bundler/webpack/src/fail-plugin-version.js
generated
vendored
Normal file
14
node_modules/fastify/test/bundler/webpack/src/fail-plugin-version.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict'
|
||||
|
||||
const fp = require('fastify-plugin')
|
||||
const fastify = require('../../../../')()
|
||||
|
||||
fastify.get('/', function (request, reply) {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.register(fp((instance, opts, done) => {
|
||||
done()
|
||||
}, { fastify: '9.x' }))
|
||||
|
||||
module.exports = fastify
|
||||
9
node_modules/fastify/test/bundler/webpack/src/index.js
generated
vendored
Normal file
9
node_modules/fastify/test/bundler/webpack/src/index.js
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
'use strict'
|
||||
|
||||
const fastify = require('../../../../')()
|
||||
// Declare a route
|
||||
fastify.get('/', function (request, reply) {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
module.exports = fastify
|
||||
15
node_modules/fastify/test/bundler/webpack/webpack.config.js
generated
vendored
Normal file
15
node_modules/fastify/test/bundler/webpack/webpack.config.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('node:path')
|
||||
|
||||
module.exports = {
|
||||
entry: { success: './src/index.js', failPlugin: './src/fail-plugin-version.js' },
|
||||
target: 'node',
|
||||
output: {
|
||||
path: path.resolve(__dirname, 'dist'),
|
||||
filename: '[name].js',
|
||||
library: {
|
||||
type: 'commonjs2'
|
||||
}
|
||||
}
|
||||
}
|
||||
120
node_modules/fastify/test/case-insensitive.test.js
generated
vendored
Normal file
120
node_modules/fastify/test/case-insensitive.test.js
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('..')
|
||||
const sget = require('simple-get').concat
|
||||
|
||||
test('case insensitive', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify({
|
||||
caseSensitive: false
|
||||
})
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.get('/foo', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/FOO'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(body), {
|
||||
hello: 'world'
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('case insensitive inject', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify({
|
||||
caseSensitive: false
|
||||
})
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.get('/foo', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/FOO'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(response.payload), {
|
||||
hello: 'world'
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('case insensitive (parametric)', t => {
|
||||
t.plan(5)
|
||||
|
||||
const fastify = Fastify({
|
||||
caseSensitive: false
|
||||
})
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.get('/foo/:param', (req, reply) => {
|
||||
t.equal(req.params.param, 'bAr')
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/FoO/bAr'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(body), {
|
||||
hello: 'world'
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('case insensitive (wildcard)', t => {
|
||||
t.plan(5)
|
||||
|
||||
const fastify = Fastify({
|
||||
caseSensitive: false
|
||||
})
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.get('/foo/*', (req, reply) => {
|
||||
t.equal(req.params['*'], 'bAr/baZ')
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/FoO/bAr/baZ'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(body), {
|
||||
hello: 'world'
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
41
node_modules/fastify/test/chainable.test.js
generated
vendored
Normal file
41
node_modules/fastify/test/chainable.test.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const fastify = require('..')()
|
||||
|
||||
const noop = () => {}
|
||||
const opts = {
|
||||
schema: {
|
||||
response: {
|
||||
'2xx': {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test('chainable - get', t => {
|
||||
t.plan(1)
|
||||
t.type(fastify.get('/', opts, noop), fastify)
|
||||
})
|
||||
|
||||
test('chainable - post', t => {
|
||||
t.plan(1)
|
||||
t.type(fastify.post('/', opts, noop), fastify)
|
||||
})
|
||||
|
||||
test('chainable - route', t => {
|
||||
t.plan(1)
|
||||
t.type(fastify.route({
|
||||
method: 'GET',
|
||||
url: '/other',
|
||||
schema: opts.schema,
|
||||
handler: noop
|
||||
}), fastify)
|
||||
})
|
||||
91
node_modules/fastify/test/childLoggerFactory.test.js
generated
vendored
Normal file
91
node_modules/fastify/test/childLoggerFactory.test.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const Fastify = require('..')
|
||||
|
||||
test('Should accept a custom childLoggerFactory function', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.setChildLoggerFactory(function (logger, bindings, opts) {
|
||||
t.ok(bindings.reqId)
|
||||
t.ok(opts)
|
||||
this.log.debug(bindings, 'created child logger')
|
||||
return logger.child(bindings, opts)
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
req.log.info('log message')
|
||||
reply.send()
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('req.log should be the instance returned by the factory', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.setChildLoggerFactory(function (logger, bindings, opts) {
|
||||
this.log.debug('using root logger')
|
||||
return this.log
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.equal(req.log, fastify.log)
|
||||
req.log.info('log message')
|
||||
reply.send()
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('should throw error if invalid logger is returned', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.setChildLoggerFactory(function () {
|
||||
this.log.debug('returning an invalid logger, expect error')
|
||||
return undefined
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send()
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.throws(() => {
|
||||
try {
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port
|
||||
}, (err) => {
|
||||
t.fail('request should have failed but did not')
|
||||
t.error(err)
|
||||
fastify.close()
|
||||
})
|
||||
} finally {
|
||||
fastify.close()
|
||||
}
|
||||
}, { code: 'FST_ERR_LOG_INVALID_LOGGER' })
|
||||
})
|
||||
})
|
||||
38
node_modules/fastify/test/client-timeout.test.js
generated
vendored
Normal file
38
node_modules/fastify/test/client-timeout.test.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const fastify = require('..')({ requestTimeout: 5, http: { connectionsCheckingInterval: 1000 } })
|
||||
const { connect } = require('node:net')
|
||||
|
||||
test('requestTimeout should return 408', t => {
|
||||
t.plan(1)
|
||||
|
||||
t.teardown(() => {
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
fastify.post('/', async function (req, reply) {
|
||||
await new Promise(resolve => setTimeout(resolve, 100))
|
||||
return reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
if (err) {
|
||||
throw err
|
||||
}
|
||||
|
||||
let data = Buffer.alloc(0)
|
||||
const socket = connect(fastify.server.address().port)
|
||||
|
||||
socket.write('POST / HTTP/1.1\r\nHost: example.com\r\nConnection-Length: 1\r\n')
|
||||
|
||||
socket.on('data', c => (data = Buffer.concat([data, c])))
|
||||
socket.on('end', () => {
|
||||
t.equal(
|
||||
data.toString('utf-8'),
|
||||
'HTTP/1.1 408 Request Timeout\r\nContent-Length: 71\r\nContent-Type: application/json\r\n\r\n{"error":"Request Timeout","message":"Client Timeout","statusCode":408}'
|
||||
)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
109
node_modules/fastify/test/close-pipelining.test.js
generated
vendored
Normal file
109
node_modules/fastify/test/close-pipelining.test.js
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('..')
|
||||
const { Client } = require('undici')
|
||||
const semver = require('semver')
|
||||
|
||||
test('Should return 503 while closing - pipelining', async t => {
|
||||
const fastify = Fastify({
|
||||
return503OnClosing: true,
|
||||
forceCloseConnections: false
|
||||
})
|
||||
|
||||
fastify.get('/', async (req, reply) => {
|
||||
fastify.close()
|
||||
return { hello: 'world' }
|
||||
})
|
||||
|
||||
await fastify.listen({ port: 0 })
|
||||
|
||||
const instance = new Client('http://localhost:' + fastify.server.address().port, {
|
||||
pipelining: 2
|
||||
})
|
||||
|
||||
const codes = [200, 200, 503]
|
||||
const responses = await Promise.all([
|
||||
instance.request({ path: '/', method: 'GET' }),
|
||||
instance.request({ path: '/', method: 'GET' }),
|
||||
instance.request({ path: '/', method: 'GET' })
|
||||
])
|
||||
const actual = responses.map(r => r.statusCode)
|
||||
|
||||
t.same(actual, codes)
|
||||
|
||||
await instance.close()
|
||||
})
|
||||
|
||||
// default enable of idle closing idle connection is accidentally backported to 18.19.0 and fixed in 18.20.3
|
||||
// Refs: https://github.com/nodejs/node/releases/tag/v18.20.3
|
||||
const isNodeDefaultClosingIdleConnection =
|
||||
(
|
||||
semver.gte(process.version, '18.19.0') &&
|
||||
semver.lt(process.version, '18.20.3')
|
||||
) ||
|
||||
semver.gte(process.version, '19.0.0')
|
||||
test('Should not return 503 while closing - pipelining - return503OnClosing: false, skip when Node default closing idle connection', { skip: isNodeDefaultClosingIdleConnection }, async t => {
|
||||
const fastify = Fastify({
|
||||
return503OnClosing: false,
|
||||
forceCloseConnections: false
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
fastify.close()
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.listen({ port: 0 })
|
||||
|
||||
const instance = new Client('http://localhost:' + fastify.server.address().port, {
|
||||
pipelining: 2
|
||||
})
|
||||
|
||||
const codes = [200, 200, 200]
|
||||
const responses = await Promise.all([
|
||||
instance.request({ path: '/', method: 'GET' }),
|
||||
instance.request({ path: '/', method: 'GET' }),
|
||||
instance.request({ path: '/', method: 'GET' })
|
||||
])
|
||||
const actual = responses.map(r => r.statusCode)
|
||||
|
||||
t.same(actual, codes)
|
||||
|
||||
await instance.close()
|
||||
})
|
||||
|
||||
test('Should close the socket abruptly - pipelining - return503OnClosing: false, skip when Node not default closing idle connection', { skip: !isNodeDefaultClosingIdleConnection }, async t => {
|
||||
// Since Node v19, we will always invoke server.closeIdleConnections()
|
||||
// therefore our socket will be closed
|
||||
const fastify = Fastify({
|
||||
return503OnClosing: false,
|
||||
forceCloseConnections: false
|
||||
})
|
||||
|
||||
fastify.get('/', async (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
await fastify.listen({ port: 0 })
|
||||
|
||||
const instance = new Client('http://localhost:' + fastify.server.address().port, {
|
||||
pipelining: 2
|
||||
})
|
||||
|
||||
const responses = await Promise.allSettled([
|
||||
instance.request({ path: '/', method: 'GET' }),
|
||||
instance.request({ path: '/', method: 'GET' }),
|
||||
instance.request({ path: '/', method: 'GET' }),
|
||||
instance.request({ path: '/', method: 'GET' })
|
||||
])
|
||||
|
||||
t.equal(responses[0].status, 'fulfilled')
|
||||
t.equal(responses[1].status, 'fulfilled')
|
||||
t.equal(responses[2].status, 'rejected')
|
||||
t.equal(responses[3].status, 'rejected')
|
||||
|
||||
await instance.close()
|
||||
})
|
||||
729
node_modules/fastify/test/close.test.js
generated
vendored
Normal file
729
node_modules/fastify/test/close.test.js
generated
vendored
Normal file
@@ -0,0 +1,729 @@
|
||||
'use strict'
|
||||
|
||||
const net = require('node:net')
|
||||
const http = require('node:http')
|
||||
const { test } = require('tap')
|
||||
const Fastify = require('..')
|
||||
const { Client } = require('undici')
|
||||
const semver = require('semver')
|
||||
const split = require('split2')
|
||||
const { sleep } = require('./helper')
|
||||
|
||||
test('close callback', t => {
|
||||
t.plan(7)
|
||||
const fastify = Fastify()
|
||||
fastify.addHook('onClose', onClose)
|
||||
function onClose (instance, done) {
|
||||
t.type(fastify, this)
|
||||
t.type(fastify, instance)
|
||||
t.equal(fastify, this)
|
||||
t.equal(fastify, instance)
|
||||
done()
|
||||
}
|
||||
|
||||
fastify.listen({ port: 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({ port: 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({ port: 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({ port: 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.code, 'FST_ERR_REOPENED_CLOSE_SERVER')
|
||||
})
|
||||
}, 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.code, 'FST_ERR_REOPENED_CLOSE_SERVER')
|
||||
})
|
||||
}, 100)
|
||||
})
|
||||
})
|
||||
|
||||
const isNodeVersionGte1819 = semver.gte(process.version, '18.19.0')
|
||||
test('Current opened connection should continue to work after closing and return "connection: close" header - return503OnClosing: false, skip Node >= v18.19.x', { skip: isNodeVersionGte1819 }, t => {
|
||||
const fastify = Fastify({
|
||||
return503OnClosing: false,
|
||||
forceCloseConnections: false
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
fastify.close()
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
const port = fastify.server.address().port
|
||||
const client = net.createConnection({ port }, () => {
|
||||
client.write('GET / HTTP/1.1\r\nHost: example.com\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\nHost: example.com\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()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Current opened connection should NOT continue to work after closing and return "connection: close" header - return503OnClosing: false, skip Node < v18.19.x', { skip: !isNodeVersionGte1819 }, t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify({
|
||||
return503OnClosing: false,
|
||||
forceCloseConnections: false
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
fastify.close()
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
const port = fastify.server.address().port
|
||||
const client = net.createConnection({ port }, () => {
|
||||
client.write('GET / HTTP/1.1\r\nHost: example.com\r\n\r\n')
|
||||
|
||||
client.on('error', function () {
|
||||
// Depending on the Operating System
|
||||
// the socket could error or not.
|
||||
// However, it will always be closed.
|
||||
})
|
||||
|
||||
client.on('close', function () {
|
||||
t.pass('close')
|
||||
})
|
||||
|
||||
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\nHost: example.com\r\n\r\n')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Current opened connection should not accept new incoming connections', t => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify({ forceCloseConnections: false })
|
||||
fastify.get('/', (req, reply) => {
|
||||
fastify.close()
|
||||
setTimeout(() => {
|
||||
reply.send({ hello: 'world' })
|
||||
}, 250)
|
||||
})
|
||||
|
||||
fastify.listen({ port: 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('rejected incoming connections should be logged', t => {
|
||||
t.plan(2)
|
||||
const stream = split(JSON.parse)
|
||||
const fastify = Fastify({
|
||||
forceCloseConnections: false,
|
||||
logger: {
|
||||
stream,
|
||||
level: 'info'
|
||||
}
|
||||
})
|
||||
|
||||
const messages = []
|
||||
stream.on('data', message => {
|
||||
messages.push(message)
|
||||
})
|
||||
fastify.get('/', (req, reply) => {
|
||||
fastify.close()
|
||||
setTimeout(() => {
|
||||
reply.send({ hello: 'world' })
|
||||
}, 250)
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
const instance = new Client('http://localhost:' + fastify.server.address().port)
|
||||
// initial request to trigger close
|
||||
instance.request({ path: '/', method: 'GET' })
|
||||
// subsequent request should be rejected
|
||||
instance.request({ path: '/', method: 'GET' }).then(() => {
|
||||
t.ok(messages.find(message => message.msg.includes('request aborted')))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Cannot be reopened the closed server without listen callback', async t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
|
||||
await fastify.listen({ port: 0 })
|
||||
await fastify.close()
|
||||
|
||||
try {
|
||||
await fastify.listen({ port: 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({ port: 0 })
|
||||
await fastify.close()
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
reject(err)
|
||||
})
|
||||
}).catch(err => {
|
||||
t.equal(err.code, 'FST_ERR_REOPENED_CLOSE_SERVER')
|
||||
t.ok(err)
|
||||
})
|
||||
})
|
||||
|
||||
const server = http.createServer()
|
||||
const noSupport = typeof server.closeAllConnections !== 'function'
|
||||
|
||||
test('shutsdown while keep-alive connections are active (non-async, native)', { skip: noSupport }, 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({ port: 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)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('shutsdown while keep-alive connections are active (non-async, idle, native)', { skip: noSupport }, t => {
|
||||
t.plan(5)
|
||||
|
||||
const timeoutTime = 2 * 60 * 1000
|
||||
const fastify = Fastify({ forceCloseConnections: 'idle' })
|
||||
|
||||
fastify.server.setTimeout(timeoutTime)
|
||||
fastify.server.keepAliveTimeout = timeoutTime
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 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)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('triggers on-close hook in the right order with multiple bindings', async t => {
|
||||
const expectedOrder = [1, 2, 3]
|
||||
const order = []
|
||||
const fastify = Fastify()
|
||||
|
||||
t.plan(1)
|
||||
|
||||
// Follows LIFO
|
||||
fastify.addHook('onClose', () => {
|
||||
order.push(2)
|
||||
})
|
||||
|
||||
fastify.addHook('onClose', () => {
|
||||
order.push(1)
|
||||
})
|
||||
|
||||
await fastify.listen({ port: 0 })
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
fastify.close(err => {
|
||||
order.push(3)
|
||||
t.match(order, expectedOrder)
|
||||
|
||||
if (err) t.error(err)
|
||||
else resolve()
|
||||
})
|
||||
}, 2000)
|
||||
})
|
||||
})
|
||||
|
||||
test('triggers on-close hook in the right order with multiple bindings (forceCloseConnections - idle)', { skip: noSupport }, async t => {
|
||||
const expectedPayload = { hello: 'world' }
|
||||
const timeoutTime = 2 * 60 * 1000
|
||||
const expectedOrder = [1, 2]
|
||||
const order = []
|
||||
const fastify = Fastify({ forceCloseConnections: 'idle' })
|
||||
|
||||
fastify.server.setTimeout(timeoutTime)
|
||||
fastify.server.keepAliveTimeout = timeoutTime
|
||||
|
||||
fastify.get('/', async (req, reply) => {
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(resolve, 1000)
|
||||
})
|
||||
|
||||
return expectedPayload
|
||||
})
|
||||
|
||||
fastify.addHook('onClose', () => {
|
||||
order.push(1)
|
||||
})
|
||||
|
||||
await fastify.listen({ port: 0 })
|
||||
const addresses = fastify.addresses()
|
||||
const testPlan = (addresses.length * 2) + 1
|
||||
|
||||
t.plan(testPlan)
|
||||
|
||||
for (const addr of addresses) {
|
||||
const { family, address, port } = addr
|
||||
const host = family === 'IPv6' ? `[${address}]` : address
|
||||
const client = new Client(`http://${host}:${port}`, {
|
||||
keepAliveTimeout: 1 * 60 * 1000
|
||||
})
|
||||
|
||||
client.request({ path: '/', method: 'GET' })
|
||||
.then((res) => res.body.json(), err => t.error(err))
|
||||
.then(json => {
|
||||
t.match(json, expectedPayload, 'should payload match')
|
||||
t.notOk(client.closed, 'should client not be closed')
|
||||
}, err => t.error(err))
|
||||
}
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
fastify.close(err => {
|
||||
order.push(2)
|
||||
t.match(order, expectedOrder)
|
||||
|
||||
if (err) t.error(err)
|
||||
else resolve()
|
||||
})
|
||||
}, 2000)
|
||||
})
|
||||
})
|
||||
|
||||
test('triggers on-close hook in the right order with multiple bindings (forceCloseConnections - true)', { skip: noSupport }, async t => {
|
||||
const expectedPayload = { hello: 'world' }
|
||||
const timeoutTime = 2 * 60 * 1000
|
||||
const expectedOrder = [1, 2]
|
||||
const order = []
|
||||
const fastify = Fastify({ forceCloseConnections: true })
|
||||
|
||||
fastify.server.setTimeout(timeoutTime)
|
||||
fastify.server.keepAliveTimeout = timeoutTime
|
||||
|
||||
fastify.get('/', async (req, reply) => {
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(resolve, 1000)
|
||||
})
|
||||
|
||||
return expectedPayload
|
||||
})
|
||||
|
||||
fastify.addHook('onClose', () => {
|
||||
order.push(1)
|
||||
})
|
||||
|
||||
await fastify.listen({ port: 0 })
|
||||
const addresses = fastify.addresses()
|
||||
const testPlan = (addresses.length * 2) + 1
|
||||
|
||||
t.plan(testPlan)
|
||||
|
||||
for (const addr of addresses) {
|
||||
const { family, address, port } = addr
|
||||
const host = family === 'IPv6' ? `[${address}]` : address
|
||||
const client = new Client(`http://${host}:${port}`, {
|
||||
keepAliveTimeout: 1 * 60 * 1000
|
||||
})
|
||||
|
||||
client.request({ path: '/', method: 'GET' })
|
||||
.then((res) => res.body.json(), err => t.error(err))
|
||||
.then(json => {
|
||||
t.match(json, expectedPayload, 'should payload match')
|
||||
t.notOk(client.closed, 'should client not be closed')
|
||||
}, err => t.error(err))
|
||||
}
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
fastify.close(err => {
|
||||
order.push(2)
|
||||
t.match(order, expectedOrder)
|
||||
|
||||
if (err) t.error(err)
|
||||
else resolve()
|
||||
})
|
||||
}, 2000)
|
||||
})
|
||||
})
|
||||
|
||||
test('shutsdown while keep-alive connections are active (non-async, custom)', t => {
|
||||
t.plan(5)
|
||||
|
||||
const timeoutTime = 2 * 60 * 1000
|
||||
const fastify = Fastify({
|
||||
forceCloseConnections: true,
|
||||
serverFactory (handler) {
|
||||
const server = http.createServer(handler)
|
||||
|
||||
server.closeAllConnections = null
|
||||
|
||||
return server
|
||||
}
|
||||
})
|
||||
|
||||
fastify.server.setTimeout(timeoutTime)
|
||||
fastify.server.keepAliveTimeout = timeoutTime
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 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)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('preClose callback', t => {
|
||||
t.plan(5)
|
||||
const fastify = Fastify()
|
||||
fastify.addHook('onClose', onClose)
|
||||
let preCloseCalled = false
|
||||
function onClose (instance, done) {
|
||||
t.equal(preCloseCalled, true)
|
||||
done()
|
||||
}
|
||||
fastify.addHook('preClose', preClose)
|
||||
|
||||
function preClose (done) {
|
||||
t.type(this, fastify)
|
||||
preCloseCalled = true
|
||||
done()
|
||||
}
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
fastify.close((err) => {
|
||||
t.error(err)
|
||||
t.ok('close callback')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('preClose async', async t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
fastify.addHook('onClose', onClose)
|
||||
let preCloseCalled = false
|
||||
async function onClose () {
|
||||
t.equal(preCloseCalled, true)
|
||||
}
|
||||
fastify.addHook('preClose', preClose)
|
||||
|
||||
async function preClose () {
|
||||
preCloseCalled = true
|
||||
t.type(this, fastify)
|
||||
}
|
||||
|
||||
await fastify.listen({ port: 0 })
|
||||
|
||||
await fastify.close()
|
||||
})
|
||||
|
||||
test('preClose execution order', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
const order = []
|
||||
fastify.addHook('onClose', onClose)
|
||||
function onClose (instance, done) {
|
||||
t.same(order, [1, 2, 3])
|
||||
done()
|
||||
}
|
||||
|
||||
fastify.addHook('preClose', (done) => {
|
||||
setTimeout(function () {
|
||||
order.push(1)
|
||||
done()
|
||||
}, 200)
|
||||
})
|
||||
|
||||
fastify.addHook('preClose', async () => {
|
||||
await sleep(100)
|
||||
order.push(2)
|
||||
})
|
||||
|
||||
fastify.addHook('preClose', (done) => {
|
||||
setTimeout(function () {
|
||||
order.push(3)
|
||||
done()
|
||||
}, 100)
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
fastify.close((err) => {
|
||||
t.error(err)
|
||||
t.ok('close callback')
|
||||
})
|
||||
})
|
||||
})
|
||||
43
node_modules/fastify/test/connectionTimeout.test.js
generated
vendored
Normal file
43
node_modules/fastify/test/connectionTimeout.test.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
'use strict'
|
||||
|
||||
const Fastify = require('..')
|
||||
const http = require('node:http')
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
|
||||
test('connectionTimeout', t => {
|
||||
t.plan(6)
|
||||
|
||||
try {
|
||||
Fastify({ connectionTimeout: 1.3 })
|
||||
t.fail('option must be an integer')
|
||||
} catch (err) {
|
||||
t.ok(err)
|
||||
}
|
||||
|
||||
try {
|
||||
Fastify({ connectionTimeout: [] })
|
||||
t.fail('option must be an integer')
|
||||
} catch (err) {
|
||||
t.ok(err)
|
||||
}
|
||||
|
||||
const httpServer = Fastify({ connectionTimeout: 1 }).server
|
||||
t.equal(httpServer.timeout, 1)
|
||||
|
||||
const httpsServer = Fastify({ connectionTimeout: 2, https: {} }).server
|
||||
t.equal(httpsServer.timeout, 2)
|
||||
|
||||
const http2Server = Fastify({ connectionTimeout: 3, http2: true }).server
|
||||
t.equal(http2Server.timeout, 3)
|
||||
|
||||
const serverFactory = (handler, _) => {
|
||||
const server = http.createServer((req, res) => {
|
||||
handler(req, res)
|
||||
})
|
||||
server.setTimeout(5)
|
||||
return server
|
||||
}
|
||||
const customServer = Fastify({ connectionTimeout: 4, serverFactory }).server
|
||||
t.equal(customServer.timeout, 5)
|
||||
})
|
||||
900
node_modules/fastify/test/constrained-routes.test.js
generated
vendored
Normal file
900
node_modules/fastify/test/constrained-routes.test.js
generated
vendored
Normal file
@@ -0,0 +1,900 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('../fastify')
|
||||
|
||||
test('Should register a host constrained route', t => {
|
||||
t.plan(7)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { host: 'fastify.dev' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
}
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
host: 'fastify.dev'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(res.payload), { hello: 'world' })
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
host: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 404)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 404)
|
||||
})
|
||||
})
|
||||
|
||||
test('Should register the same route with host constraints', t => {
|
||||
t.plan(8)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { host: 'fastify.dev' },
|
||||
handler: (req, reply) => {
|
||||
reply.send('fastify.dev')
|
||||
}
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { host: 'example.com' },
|
||||
handler: (req, reply) => {
|
||||
reply.send('example.com')
|
||||
}
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
host: 'fastify.dev'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'fastify.dev')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
host: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload, 'example.com')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
host: 'fancy.ca'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 404)
|
||||
})
|
||||
})
|
||||
|
||||
test('Should allow registering custom constrained routes', t => {
|
||||
t.plan(8)
|
||||
|
||||
const constraint = {
|
||||
name: 'secret',
|
||||
storage: function () {
|
||||
const secrets = {}
|
||||
return {
|
||||
get: (secret) => { return secrets[secret] || null },
|
||||
set: (secret, store) => { secrets[secret] = store }
|
||||
}
|
||||
},
|
||||
deriveConstraint: (req, ctx) => {
|
||||
return req.headers['x-secret']
|
||||
},
|
||||
validate () { return true }
|
||||
}
|
||||
|
||||
const fastify = Fastify({ constraints: { secret: constraint } })
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { secret: 'alpha' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'from alpha' })
|
||||
}
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { secret: 'beta' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'from beta' })
|
||||
}
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'X-Secret': 'alpha'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(res.payload), { hello: 'from alpha' })
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'X-Secret': 'beta'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(res.payload), { hello: 'from beta' })
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'X-Secret': 'gamma'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 404)
|
||||
})
|
||||
})
|
||||
|
||||
test('Should allow registering custom constrained routes outside constructor', t => {
|
||||
t.plan(8)
|
||||
|
||||
const constraint = {
|
||||
name: 'secret',
|
||||
storage: function () {
|
||||
const secrets = {}
|
||||
return {
|
||||
get: (secret) => { return secrets[secret] || null },
|
||||
set: (secret, store) => { secrets[secret] = store }
|
||||
}
|
||||
},
|
||||
deriveConstraint: (req, ctx) => {
|
||||
return req.headers['x-secret']
|
||||
},
|
||||
validate () { return true }
|
||||
}
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.addConstraintStrategy(constraint)
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { secret: 'alpha' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'from alpha' })
|
||||
}
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { secret: 'beta' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'from beta' })
|
||||
}
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'X-Secret': 'alpha'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(res.payload), { hello: 'from alpha' })
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'X-Secret': 'beta'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(res.payload), { hello: 'from beta' })
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
'X-Secret': 'gamma'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 404)
|
||||
})
|
||||
})
|
||||
|
||||
test('Custom constrained routes registered also for HEAD method generated by fastify', t => {
|
||||
t.plan(3)
|
||||
|
||||
const constraint = {
|
||||
name: 'secret',
|
||||
storage: function () {
|
||||
const secrets = {}
|
||||
return {
|
||||
get: (secret) => { return secrets[secret] || null },
|
||||
set: (secret, store) => { secrets[secret] = store }
|
||||
}
|
||||
},
|
||||
deriveConstraint: (req, ctx) => {
|
||||
return req.headers['x-secret']
|
||||
},
|
||||
validate () { return true }
|
||||
}
|
||||
|
||||
const fastify = Fastify({ constraints: { secret: constraint } })
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { secret: 'mySecret' },
|
||||
handler: (req, reply) => {
|
||||
reply.send('from mySecret - my length is 31')
|
||||
}
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'HEAD',
|
||||
url: '/',
|
||||
headers: {
|
||||
'X-Secret': 'mySecret'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(res.headers['content-length'], '31')
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('Custom constrained routes registered with addConstraintStrategy apply also for HEAD method generated by fastify', t => {
|
||||
t.plan(3)
|
||||
|
||||
const constraint = {
|
||||
name: 'secret',
|
||||
storage: function () {
|
||||
const secrets = {}
|
||||
return {
|
||||
get: (secret) => { return secrets[secret] || null },
|
||||
set: (secret, store) => { secrets[secret] = store }
|
||||
}
|
||||
},
|
||||
deriveConstraint: (req, ctx) => {
|
||||
return req.headers['x-secret']
|
||||
},
|
||||
validate () { return true }
|
||||
}
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.addConstraintStrategy(constraint)
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { secret: 'mySecret' },
|
||||
handler: (req, reply) => {
|
||||
reply.send('from mySecret - my length is 31')
|
||||
}
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'HEAD',
|
||||
url: '/',
|
||||
headers: {
|
||||
'X-Secret': 'mySecret'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(res.headers['content-length'], '31')
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('Add a constraint strategy after fastify instance was started', t => {
|
||||
t.plan(4)
|
||||
|
||||
const constraint = {
|
||||
name: 'secret',
|
||||
storage: function () {
|
||||
const secrets = {}
|
||||
return {
|
||||
get: (secret) => { return secrets[secret] || null },
|
||||
set: (secret, store) => { secrets[secret] = store }
|
||||
}
|
||||
},
|
||||
deriveConstraint: (req, ctx) => {
|
||||
return req.headers['x-secret']
|
||||
},
|
||||
validate () { return true }
|
||||
}
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
handler: (req, reply) => { reply.send('ok') }
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(res.payload, 'ok')
|
||||
t.equal(res.statusCode, 200)
|
||||
|
||||
t.throws(
|
||||
() => fastify.addConstraintStrategy(constraint),
|
||||
'Cannot add constraint strategy when fastify instance is already started!'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
test('Add a constraint strategy should throw an error if there already exist custom strategy with the same name', t => {
|
||||
t.plan(1)
|
||||
|
||||
const constraint = {
|
||||
name: 'secret',
|
||||
storage: function () {
|
||||
const secrets = {}
|
||||
return {
|
||||
get: (secret) => { return secrets[secret] || null },
|
||||
set: (secret, store) => { secrets[secret] = store }
|
||||
}
|
||||
},
|
||||
deriveConstraint: (req, ctx) => {
|
||||
return req.headers['x-secret']
|
||||
},
|
||||
validate () { return true }
|
||||
}
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addConstraintStrategy(constraint)
|
||||
t.throws(
|
||||
() => fastify.addConstraintStrategy(constraint),
|
||||
'There already exists a custom constraint with the name secret.'
|
||||
)
|
||||
})
|
||||
|
||||
test('Add a constraint strategy shouldn\'t throw an error if default constraint with the same name isn\'t used', t => {
|
||||
t.plan(1)
|
||||
|
||||
const constraint = {
|
||||
name: 'version',
|
||||
storage: function () {
|
||||
const secrets = {}
|
||||
return {
|
||||
get: (secret) => { return secrets[secret] || null },
|
||||
set: (secret, store) => { secrets[secret] = store }
|
||||
}
|
||||
},
|
||||
deriveConstraint: (req, ctx) => {
|
||||
return req.headers['x-secret']
|
||||
},
|
||||
validate () { return true }
|
||||
}
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.addConstraintStrategy(constraint)
|
||||
|
||||
t.pass()
|
||||
})
|
||||
|
||||
test('Add a constraint strategy should throw an error if default constraint with the same name is used', t => {
|
||||
t.plan(1)
|
||||
|
||||
const constraint = {
|
||||
name: 'version',
|
||||
storage: function () {
|
||||
const secrets = {}
|
||||
return {
|
||||
get: (secret) => { return secrets[secret] || null },
|
||||
set: (secret, store) => { secrets[secret] = store }
|
||||
}
|
||||
},
|
||||
deriveConstraint: (req, ctx) => {
|
||||
return req.headers['x-secret']
|
||||
},
|
||||
validate () { return true }
|
||||
}
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { version: '1.0.0' },
|
||||
handler: (req, reply) => {
|
||||
reply.send('ok')
|
||||
}
|
||||
})
|
||||
|
||||
t.throws(
|
||||
() => fastify.addConstraintStrategy(constraint),
|
||||
'There already exists a route with version constraint.'
|
||||
)
|
||||
})
|
||||
|
||||
test('The hasConstraintStrategy should return false for default constraints until they are used', t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
t.equal(fastify.hasConstraintStrategy('version'), false)
|
||||
t.equal(fastify.hasConstraintStrategy('host'), false)
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { host: 'fastify.dev' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'from any other domain' })
|
||||
}
|
||||
})
|
||||
|
||||
t.equal(fastify.hasConstraintStrategy('version'), false)
|
||||
t.equal(fastify.hasConstraintStrategy('host'), true)
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { version: '1.0.0' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'from any other domain' })
|
||||
}
|
||||
})
|
||||
|
||||
t.equal(fastify.hasConstraintStrategy('version'), true)
|
||||
t.equal(fastify.hasConstraintStrategy('host'), true)
|
||||
})
|
||||
|
||||
test('The hasConstraintStrategy should return true if there already exist a custom constraint with the same name', t => {
|
||||
t.plan(2)
|
||||
|
||||
const constraint = {
|
||||
name: 'secret',
|
||||
storage: function () {
|
||||
const secrets = {}
|
||||
return {
|
||||
get: (secret) => { return secrets[secret] || null },
|
||||
set: (secret, store) => { secrets[secret] = store }
|
||||
}
|
||||
},
|
||||
deriveConstraint: (req, ctx) => {
|
||||
return req.headers['x-secret']
|
||||
},
|
||||
validate () { return true }
|
||||
}
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
t.equal(fastify.hasConstraintStrategy('secret'), false)
|
||||
fastify.addConstraintStrategy(constraint)
|
||||
t.equal(fastify.hasConstraintStrategy('secret'), true)
|
||||
})
|
||||
|
||||
test('Should allow registering an unconstrained route after a constrained route', t => {
|
||||
t.plan(6)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { host: 'fastify.dev' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'from fastify.dev' })
|
||||
}
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'from any other domain' })
|
||||
}
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
host: 'fastify.dev'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(res.payload), { hello: 'from fastify.dev' })
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
host: 'example.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(res.payload), { hello: 'from any other domain' })
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('Should allow registering constrained routes in a prefixed plugin', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(async (scope, opts) => {
|
||||
scope.route({
|
||||
method: 'GET',
|
||||
constraints: { host: 'fastify.dev' },
|
||||
path: '/route',
|
||||
handler: (req, reply) => {
|
||||
reply.send({ ok: true })
|
||||
}
|
||||
})
|
||||
}, { prefix: '/prefix' })
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/prefix/route',
|
||||
headers: {
|
||||
host: 'fastify.dev'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(res.payload), { ok: true })
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('Should allow registering a constrained GET route after a constrained HEAD route', t => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.route({
|
||||
method: 'HEAD',
|
||||
url: '/',
|
||||
constraints: { host: 'fastify.dev' },
|
||||
handler: (req, reply) => {
|
||||
reply.header('content-type', 'text/plain')
|
||||
reply.send('custom HEAD response')
|
||||
}
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { host: 'fastify.dev' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'from any other domain' })
|
||||
}
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'HEAD',
|
||||
url: '/',
|
||||
headers: {
|
||||
host: 'fastify.dev'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(res.payload, 'custom HEAD response')
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('Should allow registering a constrained GET route after an unconstrained HEAD route', t => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.route({
|
||||
method: 'HEAD',
|
||||
url: '/',
|
||||
handler: (req, reply) => {
|
||||
reply.header('content-type', 'text/plain')
|
||||
reply.send('HEAD response: length is about 33')
|
||||
}
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { host: 'fastify.dev' },
|
||||
handler: (req, reply) => {
|
||||
reply.header('content-type', 'text/plain')
|
||||
reply.send('Hello from constrains: length is about 41')
|
||||
}
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'HEAD',
|
||||
url: '/',
|
||||
headers: {
|
||||
host: 'fastify.dev'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(res.headers['content-length'], '41')
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('Will not try to re-createprefixed HEAD route if it already exists and exposeHeadRoutes is true for constrained routes', async (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify({ exposeHeadRoutes: true })
|
||||
|
||||
fastify.register((scope, opts, next) => {
|
||||
scope.route({
|
||||
method: 'HEAD',
|
||||
path: '/route',
|
||||
constraints: { host: 'fastify.dev' },
|
||||
handler: (req, reply) => {
|
||||
reply.header('content-type', 'text/plain')
|
||||
reply.send('custom HEAD response')
|
||||
}
|
||||
})
|
||||
scope.route({
|
||||
method: 'GET',
|
||||
path: '/route',
|
||||
constraints: { host: 'fastify.dev' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ ok: true })
|
||||
}
|
||||
})
|
||||
|
||||
next()
|
||||
}, { prefix: '/prefix' })
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
t.ok(true)
|
||||
})
|
||||
|
||||
test('allows separate constrained and unconstrained HEAD routes', async (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify({ exposeHeadRoutes: true })
|
||||
|
||||
fastify.register((scope, opts, next) => {
|
||||
scope.route({
|
||||
method: 'HEAD',
|
||||
path: '/route',
|
||||
handler: (req, reply) => {
|
||||
reply.header('content-type', 'text/plain')
|
||||
reply.send('unconstrained HEAD response')
|
||||
}
|
||||
})
|
||||
|
||||
scope.route({
|
||||
method: 'HEAD',
|
||||
path: '/route',
|
||||
constraints: { host: 'fastify.dev' },
|
||||
handler: (req, reply) => {
|
||||
reply.header('content-type', 'text/plain')
|
||||
reply.send('constrained HEAD response')
|
||||
}
|
||||
})
|
||||
|
||||
scope.route({
|
||||
method: 'GET',
|
||||
path: '/route',
|
||||
constraints: { host: 'fastify.dev' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ ok: true })
|
||||
}
|
||||
})
|
||||
|
||||
next()
|
||||
}, { prefix: '/prefix' })
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
t.ok(true)
|
||||
})
|
||||
|
||||
test('allow async constraints', async (t) => {
|
||||
t.plan(5)
|
||||
|
||||
const constraint = {
|
||||
name: 'secret',
|
||||
storage: function () {
|
||||
const secrets = {}
|
||||
return {
|
||||
get: (secret) => { return secrets[secret] || null },
|
||||
set: (secret, store) => { secrets[secret] = store }
|
||||
}
|
||||
},
|
||||
deriveConstraint: (req, ctx, done) => {
|
||||
done(null, req.headers['x-secret'])
|
||||
},
|
||||
validate () { return true }
|
||||
}
|
||||
|
||||
const fastify = Fastify({ constraints: { secret: constraint } })
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { secret: 'alpha' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'from alpha' })
|
||||
}
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { secret: 'beta' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'from beta' })
|
||||
}
|
||||
})
|
||||
|
||||
{
|
||||
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'alpha' } })
|
||||
t.same(JSON.parse(payload), { hello: 'from alpha' })
|
||||
t.equal(statusCode, 200)
|
||||
}
|
||||
{
|
||||
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'beta' } })
|
||||
t.same(JSON.parse(payload), { hello: 'from beta' })
|
||||
t.equal(statusCode, 200)
|
||||
}
|
||||
{
|
||||
const { statusCode } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'gamma' } })
|
||||
t.equal(statusCode, 404)
|
||||
}
|
||||
})
|
||||
|
||||
test('error in async constraints', async (t) => {
|
||||
t.plan(8)
|
||||
|
||||
const constraint = {
|
||||
name: 'secret',
|
||||
storage: function () {
|
||||
const secrets = {}
|
||||
return {
|
||||
get: (secret) => { return secrets[secret] || null },
|
||||
set: (secret, store) => { secrets[secret] = store }
|
||||
}
|
||||
},
|
||||
deriveConstraint: (req, ctx, done) => {
|
||||
done(Error('kaboom'))
|
||||
},
|
||||
validate () { return true }
|
||||
}
|
||||
|
||||
const fastify = Fastify({ constraints: { secret: constraint } })
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { secret: 'alpha' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'from alpha' })
|
||||
}
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { secret: 'beta' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'from beta' })
|
||||
}
|
||||
})
|
||||
|
||||
{
|
||||
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'alpha' } })
|
||||
t.same(JSON.parse(payload), { error: 'Internal Server Error', message: 'Unexpected error from async constraint', statusCode: 500 })
|
||||
t.equal(statusCode, 500)
|
||||
}
|
||||
{
|
||||
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'beta' } })
|
||||
t.same(JSON.parse(payload), { error: 'Internal Server Error', message: 'Unexpected error from async constraint', statusCode: 500 })
|
||||
t.equal(statusCode, 500)
|
||||
}
|
||||
{
|
||||
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/', headers: { 'X-Secret': 'gamma' } })
|
||||
t.same(JSON.parse(payload), { error: 'Internal Server Error', message: 'Unexpected error from async constraint', statusCode: 500 })
|
||||
t.equal(statusCode, 500)
|
||||
}
|
||||
{
|
||||
const { statusCode, payload } = await fastify.inject({ method: 'GET', path: '/' })
|
||||
t.same(JSON.parse(payload), { error: 'Internal Server Error', message: 'Unexpected error from async constraint', statusCode: 500 })
|
||||
t.equal(statusCode, 500)
|
||||
}
|
||||
})
|
||||
|
||||
test('Allow regex constraints in routes', t => {
|
||||
t.plan(5)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { host: /.*\.fastify\.dev$/ },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'from fastify dev domain' })
|
||||
}
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
host: 'dev.fastify.dev'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(res.payload), { hello: 'from fastify dev domain' })
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: {
|
||||
host: 'google.com'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 404)
|
||||
})
|
||||
})
|
||||
189
node_modules/fastify/test/content-length.test.js
generated
vendored
Normal file
189
node_modules/fastify/test/content-length.test.js
generated
vendored
Normal file
@@ -0,0 +1,189 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('..')
|
||||
|
||||
test('default 413 with bodyLimit option', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify({
|
||||
bodyLimit: 10
|
||||
})
|
||||
|
||||
fastify.post('/', function (req, reply) {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/',
|
||||
body: {
|
||||
text: '12345678901234567890123456789012345678901234567890'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 413)
|
||||
t.equal(res.headers['content-type'], 'application/json; charset=utf-8')
|
||||
t.same(JSON.parse(res.payload), {
|
||||
error: 'Payload Too Large',
|
||||
code: 'FST_ERR_CTP_BODY_TOO_LARGE',
|
||||
message: 'Request body is too large',
|
||||
statusCode: 413
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('default 400 with wrong content-length', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', function (req, reply) {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/',
|
||||
headers: {
|
||||
'content-length': 20
|
||||
},
|
||||
body: {
|
||||
text: '12345678901234567890123456789012345678901234567890'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 400)
|
||||
t.equal(res.headers['content-type'], 'application/json; charset=utf-8')
|
||||
t.same(JSON.parse(res.payload), {
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_CTP_INVALID_CONTENT_LENGTH',
|
||||
message: 'Request body size did not match Content-Length',
|
||||
statusCode: 400
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('custom 413 with bodyLimit option', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify({
|
||||
bodyLimit: 10
|
||||
})
|
||||
|
||||
fastify.post('/', function (req, reply) {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.setErrorHandler(function (err, request, reply) {
|
||||
reply
|
||||
.code(err.statusCode)
|
||||
.type('application/json; charset=utf-8')
|
||||
.send(err)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/',
|
||||
body: {
|
||||
text: '12345678901234567890123456789012345678901234567890'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 413)
|
||||
t.equal(res.headers['content-type'], 'application/json; charset=utf-8')
|
||||
t.same(JSON.parse(res.payload), {
|
||||
error: 'Payload Too Large',
|
||||
code: 'FST_ERR_CTP_BODY_TOO_LARGE',
|
||||
message: 'Request body is too large',
|
||||
statusCode: 413
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('custom 400 with wrong content-length', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', function (req, reply) {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.setErrorHandler(function (err, request, reply) {
|
||||
reply
|
||||
.code(err.statusCode)
|
||||
.type('application/json; charset=utf-8')
|
||||
.send(err)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/',
|
||||
headers: {
|
||||
'content-length': 20
|
||||
},
|
||||
body: {
|
||||
text: '12345678901234567890123456789012345678901234567890'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 400)
|
||||
t.equal(res.headers['content-type'], 'application/json; charset=utf-8')
|
||||
t.same(JSON.parse(res.payload), {
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_CTP_INVALID_CONTENT_LENGTH',
|
||||
message: 'Request body size did not match Content-Length',
|
||||
statusCode: 400
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('#2214 - wrong content-length', t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/', async () => {
|
||||
const error = new Error('MY_ERROR_MESSAGE')
|
||||
error.headers = {
|
||||
'content-length': 2
|
||||
}
|
||||
throw error
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
path: '/'
|
||||
})
|
||||
.then(response => {
|
||||
t.equal(response.headers['content-length'], '' + response.rawPayload.length)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
test('#2543 - wrong content-length with errorHandler', t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.setErrorHandler((_error, _request, reply) => {
|
||||
reply.code(500).send({ message: 'longer than 2 bytes' })
|
||||
})
|
||||
|
||||
fastify.get('/', async () => {
|
||||
const error = new Error('MY_ERROR_MESSAGE')
|
||||
error.headers = {
|
||||
'content-length': 2
|
||||
}
|
||||
throw error
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
path: '/'
|
||||
})
|
||||
.then(res => {
|
||||
t.equal(res.statusCode, 500)
|
||||
t.equal(res.headers['content-length'], '' + res.rawPayload.length)
|
||||
t.same(JSON.parse(res.payload), { message: 'longer than 2 bytes' })
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
752
node_modules/fastify/test/content-parser.test.js
generated
vendored
Normal file
752
node_modules/fastify/test/content-parser.test.js
generated
vendored
Normal file
@@ -0,0 +1,752 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('..')
|
||||
const keys = require('../lib/symbols')
|
||||
const { FST_ERR_CTP_ALREADY_PRESENT, FST_ERR_CTP_INVALID_TYPE, FST_ERR_CTP_INVALID_MEDIA_TYPE } = require('../lib/errors')
|
||||
|
||||
const first = function (req, payload, done) {}
|
||||
const second = function (req, payload, done) {}
|
||||
const third = function (req, payload, done) {}
|
||||
|
||||
test('hasContentTypeParser', t => {
|
||||
test('should know about internal parsers', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.ready(err => {
|
||||
t.error(err)
|
||||
t.ok(fastify.hasContentTypeParser('application/json'))
|
||||
t.ok(fastify.hasContentTypeParser('text/plain'))
|
||||
t.notOk(fastify.hasContentTypeParser('application/jsoff'))
|
||||
})
|
||||
})
|
||||
|
||||
test('should work with string and RegExp', t => {
|
||||
t.plan(7)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.addContentTypeParser(/^image\/.*/, first)
|
||||
fastify.addContentTypeParser(/^application\/.+\+xml/, first)
|
||||
fastify.addContentTypeParser('image/gif', first)
|
||||
|
||||
t.ok(fastify.hasContentTypeParser('application/json'))
|
||||
t.ok(fastify.hasContentTypeParser(/^image\/.*/))
|
||||
t.ok(fastify.hasContentTypeParser(/^application\/.+\+xml/))
|
||||
t.ok(fastify.hasContentTypeParser('image/gif'))
|
||||
t.notOk(fastify.hasContentTypeParser(/^image\/.+\+xml/))
|
||||
t.notOk(fastify.hasContentTypeParser('image/png'))
|
||||
t.notOk(fastify.hasContentTypeParser('*'))
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('getParser', t => {
|
||||
test('should return matching parser', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addContentTypeParser(/^image\/.*/, first)
|
||||
fastify.addContentTypeParser(/^application\/.+\+xml/, second)
|
||||
fastify.addContentTypeParser('text/html', third)
|
||||
|
||||
t.equal(fastify[keys.kContentTypeParser].getParser('application/t+xml').fn, second)
|
||||
t.equal(fastify[keys.kContentTypeParser].getParser('image/png').fn, first)
|
||||
t.equal(fastify[keys.kContentTypeParser].getParser('text/html').fn, third)
|
||||
})
|
||||
|
||||
test('should return matching parser with caching', t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addContentTypeParser('text/html', first)
|
||||
|
||||
t.equal(fastify[keys.kContentTypeParser].getParser('text/html').fn, first)
|
||||
t.equal(fastify[keys.kContentTypeParser].cache.size, 0)
|
||||
t.equal(fastify[keys.kContentTypeParser].getParser('text/html ').fn, first)
|
||||
t.equal(fastify[keys.kContentTypeParser].cache.size, 1)
|
||||
t.equal(fastify[keys.kContentTypeParser].getParser('text/html ').fn, first)
|
||||
t.equal(fastify[keys.kContentTypeParser].cache.size, 1)
|
||||
})
|
||||
|
||||
test('should prefer content type parser with string value', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addContentTypeParser(/^image\/.*/, first)
|
||||
fastify.addContentTypeParser('image/gif', second)
|
||||
|
||||
t.equal(fastify[keys.kContentTypeParser].getParser('image/gif').fn, second)
|
||||
t.equal(fastify[keys.kContentTypeParser].getParser('image/png').fn, first)
|
||||
})
|
||||
|
||||
test('should return parser that catches all if no other is set', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addContentTypeParser('*', first)
|
||||
fastify.addContentTypeParser(/^text\/.*/, second)
|
||||
|
||||
t.equal(fastify[keys.kContentTypeParser].getParser('image/gif').fn, first)
|
||||
t.equal(fastify[keys.kContentTypeParser].getParser('text/html').fn, second)
|
||||
t.equal(fastify[keys.kContentTypeParser].getParser('text').fn, first)
|
||||
})
|
||||
|
||||
test('should return undefined if no matching parser exist', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addContentTypeParser(/^weirdType\/.+/, first)
|
||||
fastify.addContentTypeParser('application/javascript', first)
|
||||
|
||||
t.notOk(fastify[keys.kContentTypeParser].getParser('application/xml'))
|
||||
t.notOk(fastify[keys.kContentTypeParser].getParser('weirdType/'))
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('existingParser', t => {
|
||||
test('returns always false for "*"', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addContentTypeParser(/^image\/.*/, first)
|
||||
fastify.addContentTypeParser(/^application\/.+\+xml/, first)
|
||||
fastify.addContentTypeParser('text/html', first)
|
||||
|
||||
t.notOk(fastify[keys.kContentTypeParser].existingParser('*'))
|
||||
|
||||
fastify.addContentTypeParser('*', first)
|
||||
|
||||
t.notOk(fastify[keys.kContentTypeParser].existingParser('*'))
|
||||
})
|
||||
|
||||
test('let you override the default parser once', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addContentTypeParser('application/json', first)
|
||||
fastify.addContentTypeParser('text/plain', first)
|
||||
|
||||
t.throws(
|
||||
() => fastify.addContentTypeParser('application/json', first),
|
||||
FST_ERR_CTP_ALREADY_PRESENT,
|
||||
"Content type parser 'application/json' already present"
|
||||
)
|
||||
t.throws(
|
||||
() => fastify.addContentTypeParser('text/plain', first),
|
||||
FST_ERR_CTP_ALREADY_PRESENT,
|
||||
"Content type parser 'text/plain' already present"
|
||||
)
|
||||
})
|
||||
|
||||
const fastify = Fastify()
|
||||
const contentTypeParser = fastify[keys.kContentTypeParser]
|
||||
|
||||
fastify.addContentTypeParser(/^image\/.*/, first)
|
||||
fastify.addContentTypeParser(/^application\/.+\+xml/, first)
|
||||
fastify.addContentTypeParser('text/html', first)
|
||||
|
||||
t.ok(contentTypeParser.existingParser(/^image\/.*/))
|
||||
t.ok(contentTypeParser.existingParser('text/html'))
|
||||
t.ok(contentTypeParser.existingParser(/^application\/.+\+xml/))
|
||||
t.notOk(contentTypeParser.existingParser('application/json'))
|
||||
t.notOk(contentTypeParser.existingParser('text/plain'))
|
||||
t.notOk(contentTypeParser.existingParser('image/png'))
|
||||
t.notOk(contentTypeParser.existingParser(/^application\/.+\+json/))
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('add', t => {
|
||||
test('should only accept string and RegExp', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
const contentTypeParser = fastify[keys.kContentTypeParser]
|
||||
|
||||
t.error(contentTypeParser.add('test', {}, first))
|
||||
t.error(contentTypeParser.add(/test/, {}, first))
|
||||
t.throws(
|
||||
() => contentTypeParser.add({}, {}, first),
|
||||
FST_ERR_CTP_INVALID_TYPE,
|
||||
'The content type should be a string or a RegExp'
|
||||
)
|
||||
t.throws(
|
||||
() => contentTypeParser.add(1, {}, first),
|
||||
FST_ERR_CTP_INVALID_TYPE,
|
||||
'The content type should be a string or a RegExp'
|
||||
)
|
||||
})
|
||||
|
||||
test('should set "*" as parser that catches all', t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
const contentTypeParser = fastify[keys.kContentTypeParser]
|
||||
|
||||
contentTypeParser.add('*', {}, first)
|
||||
t.equal(contentTypeParser.customParsers.get('').fn, first)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('non-Error thrown from content parser is properly handled', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
const throwable = 'test'
|
||||
const payload = 'error'
|
||||
|
||||
fastify.addContentTypeParser('text/test', (request, payload, done) => {
|
||||
done(throwable)
|
||||
})
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
})
|
||||
|
||||
fastify.setErrorHandler((err, req, res) => {
|
||||
t.equal(err, throwable)
|
||||
|
||||
res.send(payload)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/',
|
||||
headers: { 'Content-Type': 'text/test' },
|
||||
body: 'some text'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.payload, payload)
|
||||
})
|
||||
})
|
||||
|
||||
test('Error thrown 415 from content type is null and make post request to server', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
const errMsg = new FST_ERR_CTP_INVALID_MEDIA_TYPE(undefined).message
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/',
|
||||
body: 'some text'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 415)
|
||||
t.equal(JSON.parse(res.body).message, errMsg)
|
||||
})
|
||||
})
|
||||
|
||||
test('remove', t => {
|
||||
test('should remove default parser', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
const contentTypeParser = fastify[keys.kContentTypeParser]
|
||||
|
||||
t.ok(contentTypeParser.remove('application/json'))
|
||||
t.notOk(contentTypeParser.customParsers['application/json'])
|
||||
t.notOk(contentTypeParser.parserList.find(parser => parser === 'application/json'))
|
||||
})
|
||||
|
||||
test('should remove RegExp parser', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.addContentTypeParser(/^text\/*/, first)
|
||||
|
||||
const contentTypeParser = fastify[keys.kContentTypeParser]
|
||||
|
||||
t.ok(contentTypeParser.remove(/^text\/*/))
|
||||
t.notOk(contentTypeParser.customParsers[/^text\/*/])
|
||||
t.notOk(contentTypeParser.parserRegExpList.find(parser => parser.toString() === /^text\/*/.toString()))
|
||||
})
|
||||
|
||||
test('should throw an error if content type is neither string nor RegExp', t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
t.throws(() => fastify[keys.kContentTypeParser].remove(12), FST_ERR_CTP_INVALID_TYPE)
|
||||
})
|
||||
|
||||
test('should return false if content type does not exist', t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
t.notOk(fastify[keys.kContentTypeParser].remove('image/png'))
|
||||
})
|
||||
|
||||
test('should not remove any content type parser if content type does not exist', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
const contentTypeParser = fastify[keys.kContentTypeParser]
|
||||
|
||||
t.notOk(contentTypeParser.remove('image/png'))
|
||||
t.same(contentTypeParser.customParsers.size, 2)
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('remove all should remove all existing parsers and reset cache', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.addContentTypeParser('application/xml', first)
|
||||
fastify.addContentTypeParser(/^image\/.*/, first)
|
||||
|
||||
const contentTypeParser = fastify[keys.kContentTypeParser]
|
||||
|
||||
contentTypeParser.getParser('application/xml') // fill cache with one entry
|
||||
contentTypeParser.removeAll()
|
||||
|
||||
t.same(contentTypeParser.cache.size, 0)
|
||||
t.same(contentTypeParser.parserList.length, 0)
|
||||
t.same(contentTypeParser.parserRegExpList.length, 0)
|
||||
t.same(Object.keys(contentTypeParser.customParsers).length, 0)
|
||||
})
|
||||
|
||||
test('Safeguard against malicious content-type / 1', async t => {
|
||||
const badNames = Object.getOwnPropertyNames({}.__proto__) // eslint-disable-line
|
||||
t.plan(badNames.length)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', async () => {
|
||||
return 'ok'
|
||||
})
|
||||
|
||||
for (const prop of badNames) {
|
||||
const response = await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': prop
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
|
||||
t.same(response.statusCode, 415)
|
||||
}
|
||||
})
|
||||
|
||||
test('Safeguard against malicious content-type / 2', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', async () => {
|
||||
return 'ok'
|
||||
})
|
||||
|
||||
const response = await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': '\\u0063\\u006fnstructor'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
|
||||
t.same(response.statusCode, 415)
|
||||
})
|
||||
|
||||
test('Safeguard against malicious content-type / 3', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', async () => {
|
||||
return 'ok'
|
||||
})
|
||||
|
||||
const response = await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': 'constructor; charset=utf-8'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
|
||||
t.same(response.statusCode, 415)
|
||||
})
|
||||
|
||||
test('Safeguard against content-type spoofing - string', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.removeAllContentTypeParsers()
|
||||
fastify.addContentTypeParser('text/plain', function (request, body, done) {
|
||||
t.pass('should be called')
|
||||
done(null, body)
|
||||
})
|
||||
fastify.addContentTypeParser('application/json', function (request, body, done) {
|
||||
t.fail('shouldn\'t be called')
|
||||
done(null, body)
|
||||
})
|
||||
|
||||
fastify.post('/', async () => {
|
||||
return 'ok'
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': 'text/plain; content-type="application/json"'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
})
|
||||
|
||||
test('Safeguard against content-type spoofing - regexp', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.removeAllContentTypeParsers()
|
||||
fastify.addContentTypeParser(/text\/plain/, function (request, body, done) {
|
||||
t.pass('should be called')
|
||||
done(null, body)
|
||||
})
|
||||
fastify.addContentTypeParser(/application\/json/, function (request, body, done) {
|
||||
t.fail('shouldn\'t be called')
|
||||
done(null, body)
|
||||
})
|
||||
|
||||
fastify.post('/', async () => {
|
||||
return 'ok'
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': 'text/plain; content-type="application/json"'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
})
|
||||
|
||||
test('content-type match parameters - string 1', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.removeAllContentTypeParsers()
|
||||
fastify.addContentTypeParser('text/plain; charset=utf8', function (request, body, done) {
|
||||
t.fail('shouldn\'t be called')
|
||||
done(null, body)
|
||||
})
|
||||
fastify.addContentTypeParser('application/json; charset=utf8', function (request, body, done) {
|
||||
t.pass('should be called')
|
||||
done(null, body)
|
||||
})
|
||||
|
||||
fastify.post('/', async () => {
|
||||
return 'ok'
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': 'application/json; charset=utf8'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
})
|
||||
|
||||
test('content-type match parameters - string 2', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.removeAllContentTypeParsers()
|
||||
fastify.addContentTypeParser('application/json; charset=utf8; foo=bar', function (request, body, done) {
|
||||
t.pass('should be called')
|
||||
done(null, body)
|
||||
})
|
||||
fastify.addContentTypeParser('text/plain; charset=utf8; foo=bar', function (request, body, done) {
|
||||
t.fail('shouldn\'t be called')
|
||||
done(null, body)
|
||||
})
|
||||
|
||||
fastify.post('/', async () => {
|
||||
return 'ok'
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': 'application/json; foo=bar; charset=utf8'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
})
|
||||
|
||||
test('content-type match parameters - regexp', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.removeAllContentTypeParsers()
|
||||
fastify.addContentTypeParser(/application\/json; charset=utf8/, function (request, body, done) {
|
||||
t.pass('should be called')
|
||||
done(null, body)
|
||||
})
|
||||
|
||||
fastify.post('/', async () => {
|
||||
return 'ok'
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': 'application/json; charset=utf8'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
})
|
||||
|
||||
test('content-type fail when parameters not match - string 1', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.removeAllContentTypeParsers()
|
||||
fastify.addContentTypeParser('application/json; charset=utf8; foo=bar', function (request, body, done) {
|
||||
t.fail('shouldn\'t be called')
|
||||
done(null, body)
|
||||
})
|
||||
|
||||
fastify.post('/', async () => {
|
||||
return 'ok'
|
||||
})
|
||||
|
||||
const response = await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': 'application/json; charset=utf8'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
|
||||
t.same(response.statusCode, 415)
|
||||
})
|
||||
|
||||
test('content-type fail when parameters not match - string 2', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.removeAllContentTypeParsers()
|
||||
fastify.addContentTypeParser('application/json; charset=utf8; foo=bar', function (request, body, done) {
|
||||
t.fail('shouldn\'t be called')
|
||||
done(null, body)
|
||||
})
|
||||
|
||||
fastify.post('/', async () => {
|
||||
return 'ok'
|
||||
})
|
||||
|
||||
const response = await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': 'application/json; charset=utf8; foo=baz'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
|
||||
t.same(response.statusCode, 415)
|
||||
})
|
||||
|
||||
test('content-type fail when parameters not match - regexp', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.removeAllContentTypeParsers()
|
||||
fastify.addContentTypeParser(/application\/json; charset=utf8; foo=bar/, function (request, body, done) {
|
||||
t.fail('shouldn\'t be called')
|
||||
done(null, body)
|
||||
})
|
||||
|
||||
fastify.post('/', async () => {
|
||||
return 'ok'
|
||||
})
|
||||
|
||||
const response = await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': 'application/json; charset=utf8'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
|
||||
t.same(response.statusCode, 415)
|
||||
})
|
||||
|
||||
// Refs: https://github.com/fastify/fastify/issues/4495
|
||||
test('content-type regexp list should be cloned when plugin override', async t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addContentTypeParser(/^image\/.*/, { parseAs: 'buffer' }, (req, payload, done) => {
|
||||
done(null, payload)
|
||||
})
|
||||
|
||||
fastify.register(function plugin (fastify, options, done) {
|
||||
fastify.post('/', function (request, reply) {
|
||||
reply.type(request.headers['content-type']).send(request.body)
|
||||
})
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
{
|
||||
const { payload, headers, statusCode } = await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
payload: 'jpeg',
|
||||
headers: { 'content-type': 'image/jpeg' }
|
||||
})
|
||||
t.same(statusCode, 200)
|
||||
t.same(headers['content-type'], 'image/jpeg')
|
||||
t.same(payload, 'jpeg')
|
||||
}
|
||||
|
||||
{
|
||||
const { payload, headers, statusCode } = await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
payload: 'png',
|
||||
headers: { 'content-type': 'image/png' }
|
||||
})
|
||||
t.same(statusCode, 200)
|
||||
t.same(headers['content-type'], 'image/png')
|
||||
t.same(payload, 'png')
|
||||
}
|
||||
})
|
||||
|
||||
test('allow partial content-type - essence check', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.removeAllContentTypeParsers()
|
||||
fastify.addContentTypeParser('json', function (request, body, done) {
|
||||
t.pass('should be called')
|
||||
done(null, body)
|
||||
})
|
||||
|
||||
fastify.post('/', async () => {
|
||||
return 'ok'
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': 'application/json; foo=bar; charset=utf8'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': 'image/jpeg'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
})
|
||||
|
||||
test('allow partial content-type - not essence check', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.removeAllContentTypeParsers()
|
||||
fastify.addContentTypeParser('json;', function (request, body, done) {
|
||||
t.pass('should be called')
|
||||
done(null, body)
|
||||
})
|
||||
|
||||
fastify.post('/', async () => {
|
||||
return 'ok'
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': 'application/json; foo=bar; charset=utf8'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': 'image/jpeg'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
})
|
||||
|
||||
test('edge case content-type - ;', async t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.removeAllContentTypeParsers()
|
||||
fastify.addContentTypeParser(';', function (request, body, done) {
|
||||
t.fail('should not be called')
|
||||
done(null, body)
|
||||
})
|
||||
|
||||
fastify.post('/', async () => {
|
||||
return 'ok'
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': 'application/json; foo=bar; charset=utf8'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
headers: {
|
||||
'content-type': 'image/jpeg'
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
|
||||
t.pass('end')
|
||||
})
|
||||
43
node_modules/fastify/test/content-type.test.js
generated
vendored
Normal file
43
node_modules/fastify/test/content-type.test.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('..')
|
||||
|
||||
test('should remove content-type for setErrorHandler', async t => {
|
||||
t.plan(8)
|
||||
let count = 0
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.setErrorHandler(function (error, request, reply) {
|
||||
t.same(error.message, 'kaboom')
|
||||
t.same(reply.hasHeader('content-type'), false)
|
||||
reply.code(400).send({ foo: 'bar' })
|
||||
})
|
||||
fastify.addHook('onSend', async function (request, reply, payload) {
|
||||
count++
|
||||
t.same(typeof payload, 'string')
|
||||
switch (count) {
|
||||
case 1: {
|
||||
// should guess the correct content-type based on payload
|
||||
t.same(reply.getHeader('content-type'), 'text/plain; charset=utf-8')
|
||||
throw Error('kaboom')
|
||||
}
|
||||
case 2: {
|
||||
// should guess the correct content-type based on payload
|
||||
t.same(reply.getHeader('content-type'), 'application/json; charset=utf-8')
|
||||
return payload
|
||||
}
|
||||
default: {
|
||||
t.fail('should not reach')
|
||||
}
|
||||
}
|
||||
})
|
||||
fastify.get('/', function (request, reply) {
|
||||
reply.send('plain-text')
|
||||
})
|
||||
|
||||
const { statusCode, body } = await fastify.inject({ method: 'GET', path: '/' })
|
||||
t.same(statusCode, 400)
|
||||
t.same(body, JSON.stringify({ foo: 'bar' }))
|
||||
})
|
||||
174
node_modules/fastify/test/context-config.test.js
generated
vendored
Normal file
174
node_modules/fastify/test/context-config.test.js
generated
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const { kRouteContext } = require('../lib/symbols')
|
||||
const Fastify = require('..')
|
||||
|
||||
const schema = {
|
||||
schema: { },
|
||||
config: {
|
||||
value1: 'foo',
|
||||
value2: true
|
||||
}
|
||||
}
|
||||
|
||||
function handler (req, reply) {
|
||||
reply.send(reply[kRouteContext].config)
|
||||
}
|
||||
|
||||
test('config', t => {
|
||||
t.plan(9)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/get', {
|
||||
schema: schema.schema,
|
||||
config: Object.assign({}, schema.config)
|
||||
}, handler)
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/route',
|
||||
schema: schema.schema,
|
||||
handler,
|
||||
config: Object.assign({}, schema.config)
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/no-config',
|
||||
schema: schema.schema,
|
||||
handler
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/get'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(response.payload), Object.assign({ url: '/get', method: 'GET' }, schema.config))
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/route'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(response.payload), Object.assign({ url: '/route', method: 'GET' }, schema.config))
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/no-config'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(response.payload), { url: '/no-config', method: 'GET' })
|
||||
})
|
||||
})
|
||||
|
||||
test('config with exposeHeadRoutes', t => {
|
||||
t.plan(9)
|
||||
const fastify = Fastify({ exposeHeadRoutes: true })
|
||||
|
||||
fastify.get('/get', {
|
||||
schema: schema.schema,
|
||||
config: Object.assign({}, schema.config)
|
||||
}, handler)
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/route',
|
||||
schema: schema.schema,
|
||||
handler,
|
||||
config: Object.assign({}, schema.config)
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/no-config',
|
||||
schema: schema.schema,
|
||||
handler
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/get'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(response.payload), Object.assign({ url: '/get', method: 'GET' }, schema.config))
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/route'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(response.payload), Object.assign({ url: '/route', method: 'GET' }, schema.config))
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/no-config'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(response.payload), { url: '/no-config', method: 'GET' })
|
||||
})
|
||||
})
|
||||
|
||||
test('config without exposeHeadRoutes', t => {
|
||||
t.plan(9)
|
||||
const fastify = Fastify({ exposeHeadRoutes: false })
|
||||
|
||||
fastify.get('/get', {
|
||||
schema: schema.schema,
|
||||
config: Object.assign({}, schema.config)
|
||||
}, handler)
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/route',
|
||||
schema: schema.schema,
|
||||
handler,
|
||||
config: Object.assign({}, schema.config)
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/no-config',
|
||||
schema: schema.schema,
|
||||
handler
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/get'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(response.payload), Object.assign({ url: '/get', method: 'GET' }, schema.config))
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/route'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(response.payload), Object.assign({ url: '/route', method: 'GET' }, schema.config))
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/no-config'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(response.payload), { url: '/no-config', method: 'GET' })
|
||||
})
|
||||
})
|
||||
48
node_modules/fastify/test/copy.test.js
generated
vendored
Normal file
48
node_modules/fastify/test/copy.test.js
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const sget = require('simple-get').concat
|
||||
const fastify = require('..')()
|
||||
|
||||
test('can be created - copy', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.route({
|
||||
method: 'COPY',
|
||||
url: '*',
|
||||
handler: function (req, reply) {
|
||||
reply.code(204)
|
||||
.header('location', req.headers.destination)
|
||||
.header('body', req.body.toString())
|
||||
.send()
|
||||
}
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
test('request - copy', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
url: `http://localhost:${fastify.server.address().port}/test.txt`,
|
||||
method: 'COPY',
|
||||
headers: {
|
||||
destination: '/test2.txt',
|
||||
'Content-Type': 'text/plain'
|
||||
},
|
||||
body: '/test3.txt'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.headers.location, '/test2.txt')
|
||||
t.equal(response.headers.body, '/test3.txt')
|
||||
t.equal(response.statusCode, 204)
|
||||
})
|
||||
})
|
||||
})
|
||||
130
node_modules/fastify/test/custom-http-server.test.js
generated
vendored
Normal file
130
node_modules/fastify/test/custom-http-server.test.js
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const http = require('node:http')
|
||||
const dns = require('node:dns').promises
|
||||
const sget = require('simple-get').concat
|
||||
const Fastify = require('..')
|
||||
const { FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE } = require('../lib/errors')
|
||||
|
||||
async function setup () {
|
||||
const localAddresses = await dns.lookup('localhost', { all: true })
|
||||
|
||||
test('Should support a custom http server', { skip: localAddresses.length < 1 }, async t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify({
|
||||
serverFactory: (handler, opts) => {
|
||||
t.ok(opts.serverFactory, 'it is called once for localhost')
|
||||
|
||||
const server = http.createServer((req, res) => {
|
||||
req.custom = true
|
||||
handler(req, res)
|
||||
})
|
||||
|
||||
return server
|
||||
}
|
||||
})
|
||||
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.ok(req.raw.custom)
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.listen({ port: 0 })
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
rejectUnauthorized: false
|
||||
}, (err, response, body) => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(body), { hello: 'world' })
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should not allow forceCloseConnection=idle if the server does not support closeIdleConnections', t => {
|
||||
t.plan(1)
|
||||
|
||||
t.throws(
|
||||
() => {
|
||||
Fastify({
|
||||
forceCloseConnections: 'idle',
|
||||
serverFactory (handler, opts) {
|
||||
return {
|
||||
on () {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE,
|
||||
"Cannot set forceCloseConnections to 'idle' as your HTTP server does not support closeIdleConnections method"
|
||||
)
|
||||
})
|
||||
|
||||
test('Should accept user defined serverFactory and ignore secondary server creation', async t => {
|
||||
const server = http.createServer(() => { })
|
||||
t.teardown(() => new Promise(resolve => server.close(resolve)))
|
||||
const app = await Fastify({
|
||||
serverFactory: () => server
|
||||
})
|
||||
t.resolves(async () => {
|
||||
await app.listen({ port: 0 })
|
||||
})
|
||||
})
|
||||
|
||||
test('Should not call close on the server if it has not created it', async t => {
|
||||
const server = http.createServer()
|
||||
|
||||
const serverFactory = (handler, opts) => {
|
||||
server.on('request', handler)
|
||||
return server
|
||||
}
|
||||
|
||||
const fastify = Fastify({ serverFactory })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
server.listen(0)
|
||||
server.on('listening', resolve)
|
||||
server.on('error', reject)
|
||||
})
|
||||
|
||||
const address = server.address()
|
||||
t.equal(server.listening, true)
|
||||
await fastify.close()
|
||||
|
||||
t.equal(server.listening, true)
|
||||
t.same(server.address(), address)
|
||||
t.same(fastify.addresses(), [address])
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
server.close((err) => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
t.equal(server.listening, false)
|
||||
t.same(server.address(), null)
|
||||
})
|
||||
}
|
||||
|
||||
setup()
|
||||
66
node_modules/fastify/test/custom-parser-async.test.js
generated
vendored
Normal file
66
node_modules/fastify/test/custom-parser-async.test.js
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const sget = require('simple-get').concat
|
||||
const Fastify = require('../fastify')
|
||||
|
||||
process.removeAllListeners('warning')
|
||||
|
||||
test('contentTypeParser should add a custom async parser', t => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.options('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('application/jsoff', async function (req, payload) {
|
||||
const res = await new Promise((resolve, reject) => resolve(payload))
|
||||
return res
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
t.teardown(() => fastify.close())
|
||||
|
||||
t.test('in POST', t => {
|
||||
t.plan(3)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/jsoff'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
||||
})
|
||||
})
|
||||
|
||||
t.test('in OPTIONS', t => {
|
||||
t.plan(3)
|
||||
|
||||
sget({
|
||||
method: 'OPTIONS',
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/jsoff'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
751
node_modules/fastify/test/custom-parser.0.test.js
generated
vendored
Normal file
751
node_modules/fastify/test/custom-parser.0.test.js
generated
vendored
Normal file
@@ -0,0 +1,751 @@
|
||||
'use strict'
|
||||
|
||||
const fs = require('node:fs')
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const sget = require('simple-get').concat
|
||||
const Fastify = require('../fastify')
|
||||
const jsonParser = require('fast-json-body')
|
||||
const { getServerUrl, plainTextParser } = require('./helper')
|
||||
|
||||
process.removeAllListeners('warning')
|
||||
|
||||
test('contentTypeParser method should exist', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
t.ok(fastify.addContentTypeParser)
|
||||
})
|
||||
|
||||
test('contentTypeParser should add a custom parser', t => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.options('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('application/jsoff', function (req, payload, done) {
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
t.teardown(() => fastify.close())
|
||||
|
||||
t.test('in POST', t => {
|
||||
t.plan(3)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/jsoff'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
||||
})
|
||||
})
|
||||
|
||||
t.test('in OPTIONS', t => {
|
||||
t.plan(3)
|
||||
|
||||
sget({
|
||||
method: 'OPTIONS',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/jsoff'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('contentTypeParser should handle multiple custom parsers', t => {
|
||||
t.plan(7)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.post('/hello', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
function customParser (req, payload, done) {
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
}
|
||||
|
||||
fastify.addContentTypeParser('application/jsoff', customParser)
|
||||
fastify.addContentTypeParser('application/ffosj', customParser)
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/jsoff'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
||||
})
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify) + '/hello',
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/ffosj'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('contentTypeParser should handle an array of custom contentTypes', t => {
|
||||
t.plan(7)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.post('/hello', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
function customParser (req, payload, done) {
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
}
|
||||
|
||||
fastify.addContentTypeParser(['application/jsoff', 'application/ffosj'], customParser)
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/jsoff'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
||||
})
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify) + '/hello',
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/ffosj'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('contentTypeParser should handle errors', t => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('application/jsoff', function (req, payload, done) {
|
||||
done(new Error('kaboom!'), {})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/jsoff'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 500)
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('contentTypeParser should support encapsulation', t => {
|
||||
t.plan(6)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register((instance, opts, done) => {
|
||||
instance.addContentTypeParser('application/jsoff', () => {})
|
||||
t.ok(instance.hasContentTypeParser('application/jsoff'))
|
||||
|
||||
instance.register((instance, opts, done) => {
|
||||
instance.addContentTypeParser('application/ffosj', () => {})
|
||||
t.ok(instance.hasContentTypeParser('application/jsoff'))
|
||||
t.ok(instance.hasContentTypeParser('application/ffosj'))
|
||||
done()
|
||||
})
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.ready(err => {
|
||||
t.error(err)
|
||||
t.notOk(fastify.hasContentTypeParser('application/jsoff'))
|
||||
t.notOk(fastify.hasContentTypeParser('application/ffosj'))
|
||||
})
|
||||
})
|
||||
|
||||
test('contentTypeParser should support encapsulation, second try', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register((instance, opts, done) => {
|
||||
instance.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
instance.addContentTypeParser('application/jsoff', function (req, payload, done) {
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/jsoff'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('contentTypeParser shouldn\'t support request with undefined "Content-Type"', t => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('application/jsoff', function (req, payload, done) {
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: 'unknown content type!',
|
||||
headers: {
|
||||
// 'Content-Type': undefined
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 415)
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('the content type should be a string or RegExp', t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
|
||||
try {
|
||||
fastify.addContentTypeParser(null, () => {})
|
||||
t.fail()
|
||||
} catch (err) {
|
||||
t.equal(err.code, 'FST_ERR_CTP_INVALID_TYPE')
|
||||
t.equal(err.message, 'The content type should be a string or a RegExp')
|
||||
}
|
||||
})
|
||||
|
||||
test('the content type cannot be an empty string', t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
|
||||
try {
|
||||
fastify.addContentTypeParser('', () => {})
|
||||
t.fail()
|
||||
} catch (err) {
|
||||
t.equal(err.code, 'FST_ERR_CTP_EMPTY_TYPE')
|
||||
t.equal(err.message, 'The content type cannot be an empty string')
|
||||
}
|
||||
})
|
||||
|
||||
test('the content type handler should be a function', t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
|
||||
try {
|
||||
fastify.addContentTypeParser('aaa', null)
|
||||
t.fail()
|
||||
} catch (err) {
|
||||
t.equal(err.code, 'FST_ERR_CTP_INVALID_HANDLER')
|
||||
t.equal(err.message, 'The content type handler should be a function')
|
||||
}
|
||||
})
|
||||
|
||||
test('catch all content type parser', t => {
|
||||
t.plan(7)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('*', function (req, payload, done) {
|
||||
let data = ''
|
||||
payload.on('data', chunk => { data += chunk })
|
||||
payload.on('end', () => {
|
||||
done(null, data)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: 'hello',
|
||||
headers: {
|
||||
'Content-Type': 'application/jsoff'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), 'hello')
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: 'hello',
|
||||
headers: {
|
||||
'Content-Type': 'very-weird-content-type'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), 'hello')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('catch all content type parser should not interfere with other conte type parsers', t => {
|
||||
t.plan(7)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('*', function (req, payload, done) {
|
||||
let data = ''
|
||||
payload.on('data', chunk => { data += chunk })
|
||||
payload.on('end', () => {
|
||||
done(null, data)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('application/jsoff', function (req, payload, done) {
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/jsoff'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: 'hello',
|
||||
headers: {
|
||||
'Content-Type': 'very-weird-content-type'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), 'hello')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Issue 492 https://github.com/fastify/fastify/issues/492
|
||||
test('\'*\' catch undefined Content-Type requests', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.addContentTypeParser('*', function (req, payload, done) {
|
||||
let data = ''
|
||||
payload.on('data', chunk => { data += chunk })
|
||||
payload.on('end', () => {
|
||||
done(null, data)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.post('/', (req, res) => {
|
||||
// Needed to avoid json stringify
|
||||
res.type('text/plain').send(req.body)
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, function (err) {
|
||||
t.error(err)
|
||||
|
||||
const fileStream = fs.createReadStream(__filename)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify) + '/',
|
||||
body: fileStream
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body + '', fs.readFileSync(__filename).toString())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('cannot add custom parser after binding', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.post('/', (req, res) => {
|
||||
res.type('text/plain').send(req.body)
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, function (err) {
|
||||
t.error(err)
|
||||
|
||||
try {
|
||||
fastify.addContentTypeParser('*', () => {})
|
||||
t.fail()
|
||||
} catch (e) {
|
||||
t.pass()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
test('Can override the default json parser', t => {
|
||||
t.plan(5)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('application/json', function (req, payload, done) {
|
||||
t.ok('called')
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body.toString(), '{"hello":"world"}')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Can override the default plain text parser', t => {
|
||||
t.plan(5)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('text/plain', function (req, payload, done) {
|
||||
t.ok('called')
|
||||
plainTextParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: 'hello world',
|
||||
headers: {
|
||||
'Content-Type': 'text/plain'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body.toString(), 'hello world')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Can override the default json parser in a plugin', t => {
|
||||
t.plan(5)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register((instance, opts, done) => {
|
||||
instance.addContentTypeParser('application/json', function (req, payload, done) {
|
||||
t.ok('called')
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
instance.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body.toString(), '{"hello":"world"}')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Can\'t override the json parser multiple times', t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addContentTypeParser('application/json', function (req, payload, done) {
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
try {
|
||||
fastify.addContentTypeParser('application/json', function (req, payload, done) {
|
||||
t.ok('called')
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
} catch (err) {
|
||||
t.equal(err.code, 'FST_ERR_CTP_ALREADY_PRESENT')
|
||||
t.equal(err.message, 'Content type parser \'application/json\' already present.')
|
||||
}
|
||||
})
|
||||
|
||||
test('Can\'t override the plain text parser multiple times', t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addContentTypeParser('text/plain', function (req, payload, done) {
|
||||
plainTextParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
try {
|
||||
fastify.addContentTypeParser('text/plain', function (req, payload, done) {
|
||||
t.ok('called')
|
||||
plainTextParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
} catch (err) {
|
||||
t.equal(err.code, 'FST_ERR_CTP_ALREADY_PRESENT')
|
||||
t.equal(err.message, 'Content type parser \'text/plain\' already present.')
|
||||
}
|
||||
})
|
||||
|
||||
test('Should get the body as string', t => {
|
||||
t.plan(6)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('application/json', { parseAs: 'string' }, function (req, body, done) {
|
||||
t.ok('called')
|
||||
t.ok(typeof body === 'string')
|
||||
try {
|
||||
const json = JSON.parse(body)
|
||||
done(null, json)
|
||||
} catch (err) {
|
||||
err.statusCode = 400
|
||||
done(err, undefined)
|
||||
}
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body.toString(), '{"hello":"world"}')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should return defined body with no custom parser defined and content type = \'text/plain\'', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: 'hello world',
|
||||
headers: {
|
||||
'Content-Type': 'text/plain'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body.toString(), 'hello world')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should have typeof body object with no custom parser defined, no body defined and content type = \'text/plain\'', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
headers: {
|
||||
'Content-Type': 'text/plain'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(typeof body, 'object')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
298
node_modules/fastify/test/custom-parser.1.test.js
generated
vendored
Normal file
298
node_modules/fastify/test/custom-parser.1.test.js
generated
vendored
Normal file
@@ -0,0 +1,298 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const sget = require('simple-get').concat
|
||||
const Fastify = require('../fastify')
|
||||
const jsonParser = require('fast-json-body')
|
||||
const { getServerUrl } = require('./helper')
|
||||
|
||||
process.removeAllListeners('warning')
|
||||
|
||||
test('Should have typeof body object with no custom parser defined, null body and content type = \'text/plain\'', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: null,
|
||||
headers: {
|
||||
'Content-Type': 'text/plain'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(typeof body, 'object')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should have typeof body object with no custom parser defined, undefined body and content type = \'text/plain\'', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: undefined,
|
||||
headers: {
|
||||
'Content-Type': 'text/plain'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(typeof body, 'object')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should get the body as string', t => {
|
||||
t.plan(6)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('text/plain', { parseAs: 'string' }, function (req, body, done) {
|
||||
t.ok('called')
|
||||
t.ok(typeof body === 'string')
|
||||
try {
|
||||
const plainText = body
|
||||
done(null, plainText)
|
||||
} catch (err) {
|
||||
err.statusCode = 400
|
||||
done(err, undefined)
|
||||
}
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: 'hello world',
|
||||
headers: {
|
||||
'Content-Type': 'text/plain'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body.toString(), 'hello world')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should get the body as buffer', t => {
|
||||
t.plan(6)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('application/json', { parseAs: 'buffer' }, function (req, body, done) {
|
||||
t.ok('called')
|
||||
t.ok(body instanceof Buffer)
|
||||
try {
|
||||
const json = JSON.parse(body)
|
||||
done(null, json)
|
||||
} catch (err) {
|
||||
err.statusCode = 400
|
||||
done(err, undefined)
|
||||
}
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body.toString(), '{"hello":"world"}')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should get the body as buffer', t => {
|
||||
t.plan(6)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('text/plain', { parseAs: 'buffer' }, function (req, body, done) {
|
||||
t.ok('called')
|
||||
t.ok(body instanceof Buffer)
|
||||
try {
|
||||
const plainText = body
|
||||
done(null, plainText)
|
||||
} catch (err) {
|
||||
err.statusCode = 400
|
||||
done(err, undefined)
|
||||
}
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: 'hello world',
|
||||
headers: {
|
||||
'Content-Type': 'text/plain'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body.toString(), 'hello world')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should parse empty bodies as a string', t => {
|
||||
t.plan(9)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addContentTypeParser('text/plain', { parseAs: 'string' }, (req, body, done) => {
|
||||
t.equal(body, '')
|
||||
done(null, body)
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
method: ['POST', 'DELETE'],
|
||||
url: '/',
|
||||
handler (request, reply) {
|
||||
reply.send(request.body)
|
||||
}
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '',
|
||||
headers: {
|
||||
'Content-Type': 'text/plain'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body.toString(), '')
|
||||
})
|
||||
|
||||
sget({
|
||||
method: 'DELETE',
|
||||
url: getServerUrl(fastify),
|
||||
body: '',
|
||||
headers: {
|
||||
'Content-Type': 'text/plain',
|
||||
'Content-Length': '0'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body.toString(), '')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should parse empty bodies as a buffer', t => {
|
||||
t.plan(6)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('text/plain', { parseAs: 'buffer' }, function (req, body, done) {
|
||||
t.ok(body instanceof Buffer)
|
||||
t.equal(body.length, 0)
|
||||
done(null, body)
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '',
|
||||
headers: {
|
||||
'Content-Type': 'text/plain'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body.length, 0)
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('The charset should not interfere with the content type handling', t => {
|
||||
t.plan(5)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('application/json', function (req, payload, done) {
|
||||
t.ok('called')
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=utf-8'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body.toString(), '{"hello":"world"}')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
102
node_modules/fastify/test/custom-parser.2.test.js
generated
vendored
Normal file
102
node_modules/fastify/test/custom-parser.2.test.js
generated
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const sget = require('simple-get').concat
|
||||
const Fastify = require('../fastify')
|
||||
const { getServerUrl } = require('./helper')
|
||||
|
||||
process.removeAllListeners('warning')
|
||||
|
||||
test('Wrong parseAs parameter', t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
|
||||
try {
|
||||
fastify.addContentTypeParser('application/json', { parseAs: 'fireworks' }, () => {})
|
||||
t.fail('should throw')
|
||||
} catch (err) {
|
||||
t.equal(err.code, 'FST_ERR_CTP_INVALID_PARSE_TYPE')
|
||||
t.equal(err.message, "The body parser can only parse your data as 'string' or 'buffer', you asked 'fireworks' which is not supported.")
|
||||
}
|
||||
})
|
||||
|
||||
test('Should allow defining the bodyLimit per parser', t => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify()
|
||||
t.teardown(() => fastify.close())
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser(
|
||||
'x/foo',
|
||||
{ parseAs: 'string', bodyLimit: 5 },
|
||||
function (req, body, done) {
|
||||
t.fail('should not be invoked')
|
||||
done()
|
||||
}
|
||||
)
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '1234567890',
|
||||
headers: {
|
||||
'Content-Type': 'x/foo'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.strictSame(JSON.parse(body.toString()), {
|
||||
statusCode: 413,
|
||||
code: 'FST_ERR_CTP_BODY_TOO_LARGE',
|
||||
error: 'Payload Too Large',
|
||||
message: 'Request body is too large'
|
||||
})
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('route bodyLimit should take precedence over a custom parser bodyLimit', t => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify()
|
||||
t.teardown(() => fastify.close())
|
||||
|
||||
fastify.post('/', { bodyLimit: 5 }, (request, reply) => {
|
||||
reply.send(request.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser(
|
||||
'x/foo',
|
||||
{ parseAs: 'string', bodyLimit: 100 },
|
||||
function (req, body, done) {
|
||||
t.fail('should not be invoked')
|
||||
done()
|
||||
}
|
||||
)
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '1234567890',
|
||||
headers: { 'Content-Type': 'x/foo' }
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.strictSame(JSON.parse(body.toString()), {
|
||||
statusCode: 413,
|
||||
code: 'FST_ERR_CTP_BODY_TOO_LARGE',
|
||||
error: 'Payload Too Large',
|
||||
message: 'Request body is too large'
|
||||
})
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
245
node_modules/fastify/test/custom-parser.3.test.js
generated
vendored
Normal file
245
node_modules/fastify/test/custom-parser.3.test.js
generated
vendored
Normal file
@@ -0,0 +1,245 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const sget = require('simple-get').concat
|
||||
const Fastify = require('../fastify')
|
||||
const jsonParser = require('fast-json-body')
|
||||
const { getServerUrl } = require('./helper')
|
||||
|
||||
process.removeAllListeners('warning')
|
||||
|
||||
test('should be able to use default parser for extra content type', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
t.teardown(() => fastify.close())
|
||||
|
||||
fastify.post('/', (request, reply) => {
|
||||
reply.send(request.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('text/json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore'))
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'text/json'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.strictSame(JSON.parse(body.toString()), { hello: 'world' })
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('contentTypeParser should add a custom parser with RegExp value', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.options('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser(/.*\+json$/, function (req, payload, done) {
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
t.teardown(() => fastify.close())
|
||||
|
||||
t.test('in POST', t => {
|
||||
t.plan(3)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/vnd.test+json'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
||||
})
|
||||
})
|
||||
|
||||
t.test('in OPTIONS', t => {
|
||||
t.plan(3)
|
||||
|
||||
sget({
|
||||
method: 'OPTIONS',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'weird/content-type+json'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('contentTypeParser should add multiple custom parsers with RegExp values', async t => {
|
||||
t.plan(6)
|
||||
const fastify = Fastify()
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser(/.*\+json$/, function (req, payload, done) {
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser(/.*\+xml$/, function (req, payload, done) {
|
||||
done(null, 'xml')
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser(/.*\+myExtension$/i, function (req, payload, done) {
|
||||
let data = ''
|
||||
payload.on('data', chunk => { data += chunk })
|
||||
payload.on('end', () => {
|
||||
done(null, data + 'myExtension')
|
||||
})
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
{
|
||||
const response = await fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/',
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/vnd.hello+json'
|
||||
}
|
||||
})
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(response.payload.toString(), '{"hello":"world"}')
|
||||
}
|
||||
|
||||
{
|
||||
const response = await fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/',
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/test+xml'
|
||||
}
|
||||
})
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(response.payload.toString(), 'xml')
|
||||
}
|
||||
|
||||
await fastify.inject({
|
||||
method: 'POST',
|
||||
path: '/',
|
||||
payload: 'abcdefg',
|
||||
headers: {
|
||||
'Content-Type': 'application/+myExtension'
|
||||
}
|
||||
}).then((response) => {
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(response.payload.toString(), 'abcdefgmyExtension')
|
||||
}).catch((err) => {
|
||||
t.error(err)
|
||||
})
|
||||
})
|
||||
|
||||
test('catch all content type parser should not interfere with content type parser', t => {
|
||||
t.plan(10)
|
||||
const fastify = Fastify()
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('*', function (req, payload, done) {
|
||||
let data = ''
|
||||
payload.on('data', chunk => { data += chunk })
|
||||
payload.on('end', () => {
|
||||
done(null, data)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser(/^application\/.*/, function (req, payload, done) {
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('text/html', function (req, payload, done) {
|
||||
let data = ''
|
||||
payload.on('data', chunk => { data += chunk })
|
||||
payload.on('end', () => {
|
||||
done(null, data + 'html')
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"myKey":"myValue"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ myKey: 'myValue' }))
|
||||
})
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: 'body',
|
||||
headers: {
|
||||
'Content-Type': 'very-weird-content-type'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), 'body')
|
||||
})
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: 'my text',
|
||||
headers: {
|
||||
'Content-Type': 'text/html'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), 'my texthtml')
|
||||
})
|
||||
})
|
||||
})
|
||||
239
node_modules/fastify/test/custom-parser.4.test.js
generated
vendored
Normal file
239
node_modules/fastify/test/custom-parser.4.test.js
generated
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const sget = require('simple-get').concat
|
||||
const Fastify = require('../fastify')
|
||||
const jsonParser = require('fast-json-body')
|
||||
const { getServerUrl } = require('./helper')
|
||||
|
||||
process.removeAllListeners('warning')
|
||||
|
||||
test('should prefer string content types over RegExp ones', t => {
|
||||
t.plan(7)
|
||||
const fastify = Fastify()
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser(/^application\/.*/, function (req, payload, done) {
|
||||
let data = ''
|
||||
payload.on('data', chunk => { data += chunk })
|
||||
payload.on('end', () => {
|
||||
done(null, data)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser('application/json', function (req, payload, done) {
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"k1":"myValue", "k2": "myValue"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ k1: 'myValue', k2: 'myValue' }))
|
||||
})
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: 'javascript',
|
||||
headers: {
|
||||
'Content-Type': 'application/javascript'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), 'javascript')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('removeContentTypeParser should support arrays of content types to remove', t => {
|
||||
t.plan(8)
|
||||
|
||||
const fastify = Fastify()
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.addContentTypeParser('application/xml', function (req, payload, done) {
|
||||
payload.on('data', () => {})
|
||||
payload.on('end', () => {
|
||||
done(null, 'xml')
|
||||
})
|
||||
})
|
||||
|
||||
fastify.addContentTypeParser(/^image\/.*/, function (req, payload, done) {
|
||||
payload.on('data', () => {})
|
||||
payload.on('end', () => {
|
||||
done(null, 'image')
|
||||
})
|
||||
})
|
||||
|
||||
fastify.removeContentTypeParser([/^image\/.*/, 'application/json'])
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '<?xml version="1.0">',
|
||||
headers: {
|
||||
'Content-Type': 'application/xml'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), 'xml')
|
||||
})
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '',
|
||||
headers: {
|
||||
'Content-Type': 'image/png'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 415)
|
||||
})
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{test: "test"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 415)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('removeContentTypeParser should support encapsulation', t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addContentTypeParser('application/xml', function (req, payload, done) {
|
||||
payload.on('data', () => {})
|
||||
payload.on('end', () => {
|
||||
done(null, 'xml')
|
||||
})
|
||||
})
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.register(function (instance, options, done) {
|
||||
instance.removeContentTypeParser('application/xml')
|
||||
|
||||
instance.post('/encapsulated', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify) + '/encapsulated',
|
||||
body: '<?xml version="1.0">',
|
||||
headers: {
|
||||
'Content-Type': 'application/xml'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 415)
|
||||
})
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '<?xml version="1.0">',
|
||||
headers: {
|
||||
'Content-Type': 'application/xml'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), 'xml')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('removeAllContentTypeParsers should support encapsulation', t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.register(function (instance, options, done) {
|
||||
instance.removeAllContentTypeParsers()
|
||||
|
||||
instance.post('/encapsulated', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify) + '/encapsulated',
|
||||
body: '{}',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 415)
|
||||
})
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"test":1}',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(body.toString()).test, 1)
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
149
node_modules/fastify/test/custom-parser.5.test.js
generated
vendored
Normal file
149
node_modules/fastify/test/custom-parser.5.test.js
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const sget = require('simple-get').concat
|
||||
const Fastify = require('../fastify')
|
||||
const jsonParser = require('fast-json-body')
|
||||
const { getServerUrl, plainTextParser } = require('./helper')
|
||||
|
||||
process.removeAllListeners('warning')
|
||||
|
||||
test('cannot remove all content type parsers after binding', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.listen({ port: 0 }, function (err) {
|
||||
t.error(err)
|
||||
|
||||
t.throws(() => fastify.removeAllContentTypeParsers())
|
||||
})
|
||||
})
|
||||
|
||||
test('cannot remove content type parsers after binding', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.listen({ port: 0 }, function (err) {
|
||||
t.error(err)
|
||||
|
||||
t.throws(() => fastify.removeContentTypeParser('application/json'))
|
||||
})
|
||||
})
|
||||
|
||||
test('should be able to override the default json parser after removeAllContentTypeParsers', t => {
|
||||
t.plan(5)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.removeAllContentTypeParsers()
|
||||
|
||||
fastify.addContentTypeParser('application/json', function (req, payload, done) {
|
||||
t.ok('called')
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('should be able to override the default plain text parser after removeAllContentTypeParsers', t => {
|
||||
t.plan(5)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.removeAllContentTypeParsers()
|
||||
|
||||
fastify.addContentTypeParser('text/plain', function (req, payload, done) {
|
||||
t.ok('called')
|
||||
plainTextParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: 'hello world',
|
||||
headers: {
|
||||
'Content-Type': 'text/plain'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body.toString(), 'hello world')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('should be able to add a custom content type parser after removeAllContentTypeParsers', t => {
|
||||
t.plan(5)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.removeAllContentTypeParsers()
|
||||
|
||||
fastify.addContentTypeParser('application/jsoff', function (req, payload, done) {
|
||||
t.ok('called')
|
||||
jsonParser(payload, function (err, body) {
|
||||
done(err, body)
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: getServerUrl(fastify),
|
||||
body: '{"hello":"world"}',
|
||||
headers: {
|
||||
'Content-Type': 'application/jsoff'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
137
node_modules/fastify/test/custom-querystring-parser.test.js
generated
vendored
Normal file
137
node_modules/fastify/test/custom-querystring-parser.test.js
generated
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const querystring = require('node:querystring')
|
||||
const sget = require('simple-get').concat
|
||||
const Fastify = require('..')
|
||||
|
||||
test('Custom querystring parser', t => {
|
||||
t.plan(9)
|
||||
|
||||
const fastify = Fastify({
|
||||
querystringParser: function (str) {
|
||||
t.equal(str, 'foo=bar&baz=faz')
|
||||
return querystring.parse(str)
|
||||
}
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.same(req.query, {
|
||||
foo: 'bar',
|
||||
baz: 'faz'
|
||||
})
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, (err, address) => {
|
||||
t.error(err)
|
||||
t.teardown(() => fastify.close())
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: `${address}?foo=bar&baz=faz`
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: `${address}?foo=bar&baz=faz`
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Custom querystring parser should be called also if there is nothing to parse', t => {
|
||||
t.plan(9)
|
||||
|
||||
const fastify = Fastify({
|
||||
querystringParser: function (str) {
|
||||
t.equal(str, '')
|
||||
return querystring.parse(str)
|
||||
}
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.same(req.query, {})
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, (err, address) => {
|
||||
t.error(err)
|
||||
t.teardown(() => fastify.close())
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: address
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: address
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Querystring without value', t => {
|
||||
t.plan(9)
|
||||
|
||||
const fastify = Fastify({
|
||||
querystringParser: function (str) {
|
||||
t.equal(str, 'foo')
|
||||
return querystring.parse(str)
|
||||
}
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.same(req.query, { foo: '' })
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, (err, address) => {
|
||||
t.error(err)
|
||||
t.teardown(() => fastify.close())
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: `${address}?foo`
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: `${address}?foo`
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Custom querystring parser should be a function', t => {
|
||||
t.plan(1)
|
||||
|
||||
try {
|
||||
Fastify({
|
||||
querystringParser: 10
|
||||
})
|
||||
t.fail('Should throw')
|
||||
} catch (err) {
|
||||
t.equal(
|
||||
err.message,
|
||||
"querystringParser option should be a function, instead got 'number'"
|
||||
)
|
||||
}
|
||||
})
|
||||
1213
node_modules/fastify/test/decorator.test.js
generated
vendored
Normal file
1213
node_modules/fastify/test/decorator.test.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
88
node_modules/fastify/test/default-route.test.js
generated
vendored
Normal file
88
node_modules/fastify/test/default-route.test.js
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('..')
|
||||
const { FSTDEP014 } = require('../lib/warnings')
|
||||
|
||||
// Silence the standard warning logs. We will test the messages explicitly.
|
||||
process.removeAllListeners('warning')
|
||||
|
||||
test('setDefaultRoute should emit a deprecation warning', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
const defaultRoute = (req, res) => {
|
||||
res.end('hello from defaultRoute')
|
||||
}
|
||||
|
||||
process.on('warning', onWarning)
|
||||
function onWarning (warning) {
|
||||
t.equal(warning.name, 'DeprecationWarning')
|
||||
t.equal(warning.code, FSTDEP014.code)
|
||||
}
|
||||
|
||||
t.teardown(() => {
|
||||
process.removeListener('warning', onWarning)
|
||||
FSTDEP014.emitted = false
|
||||
})
|
||||
|
||||
fastify.setDefaultRoute(defaultRoute)
|
||||
})
|
||||
|
||||
test('getDefaultRoute should emit a deprecation warning', t => {
|
||||
t.plan(2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
process.on('warning', onWarning)
|
||||
function onWarning (warning) {
|
||||
t.equal(warning.name, 'DeprecationWarning')
|
||||
t.equal(warning.code, FSTDEP014.code)
|
||||
}
|
||||
|
||||
t.teardown(() => {
|
||||
process.removeListener('warning', onWarning)
|
||||
FSTDEP014.emitted = false
|
||||
})
|
||||
|
||||
fastify.getDefaultRoute()
|
||||
})
|
||||
|
||||
test('should fail if defaultRoute is not a function', t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
const defaultRoute = {}
|
||||
|
||||
fastify.get('/', () => {})
|
||||
|
||||
try {
|
||||
fastify.setDefaultRoute(defaultRoute)
|
||||
} catch (error) {
|
||||
t.equal(error.code, 'FST_ERR_DEFAULT_ROUTE_INVALID_TYPE')
|
||||
}
|
||||
})
|
||||
|
||||
test('correctly sets, returns, and calls defaultRoute', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
const defaultRoute = (req, res) => {
|
||||
res.end('hello from defaultRoute')
|
||||
}
|
||||
|
||||
fastify.setDefaultRoute(defaultRoute)
|
||||
const returnedDefaultRoute = fastify.getDefaultRoute()
|
||||
t.equal(returnedDefaultRoute, defaultRoute)
|
||||
|
||||
fastify.get('/', () => {})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/random'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.body, 'hello from defaultRoute')
|
||||
})
|
||||
})
|
||||
321
node_modules/fastify/test/delete.test.js
generated
vendored
Normal file
321
node_modules/fastify/test/delete.test.js
generated
vendored
Normal file
@@ -0,0 +1,321 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const sget = require('simple-get').concat
|
||||
const fastify = require('..')()
|
||||
|
||||
const schema = {
|
||||
schema: {
|
||||
response: {
|
||||
'2xx': {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const querySchema = {
|
||||
schema: {
|
||||
querystring: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const paramsSchema = {
|
||||
schema: {
|
||||
params: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
},
|
||||
test: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const headersSchema = {
|
||||
schema: {
|
||||
headers: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'x-test': {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const bodySchema = {
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
response: {
|
||||
'2xx': {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test('shorthand - delete', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.delete('/', schema, function (req, reply) {
|
||||
reply.code(200).send({ hello: 'world' })
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('shorthand - delete params', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.delete('/params/:foo/:test', paramsSchema, function (req, reply) {
|
||||
reply.code(200).send(req.params)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('shorthand - delete, querystring schema', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.delete('/query', querySchema, function (req, reply) {
|
||||
reply.send(req.query)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('shorthand - get, headers schema', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.delete('/headers', headersSchema, function (req, reply) {
|
||||
reply.code(200).send(req.headers)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('missing schema - delete', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.delete('/missing', function (req, reply) {
|
||||
reply.code(200).send({ hello: 'world' })
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('body - delete', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.delete('/body', bodySchema, function (req, reply) {
|
||||
reply.send(req.body)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
test('shorthand - request delete', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
method: 'DELETE',
|
||||
url: 'http://localhost:' + fastify.server.address().port
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-length'], '' + body.length)
|
||||
t.same(JSON.parse(body), { hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request delete params schema', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
method: 'DELETE',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/params/world/123'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-length'], '' + body.length)
|
||||
t.same(JSON.parse(body), { foo: 'world', test: 123 })
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request delete params schema error', t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: 'DELETE',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/params/world/string'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 400)
|
||||
t.same(JSON.parse(body), {
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_VALIDATION',
|
||||
message: 'params/test must be integer',
|
||||
statusCode: 400
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request delete headers schema', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'x-test': 1
|
||||
},
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/headers'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-length'], '' + body.length)
|
||||
t.equal(JSON.parse(body)['x-test'], 1)
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request delete headers schema error', t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'x-test': 'abc'
|
||||
},
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/headers'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 400)
|
||||
t.same(JSON.parse(body), {
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_VALIDATION',
|
||||
message: 'headers/x-test must be number',
|
||||
statusCode: 400
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request delete querystring schema', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
method: 'DELETE',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/query?hello=123'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-length'], '' + body.length)
|
||||
t.same(JSON.parse(body), { hello: 123 })
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request delete querystring schema error', t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: 'DELETE',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/query?hello=world'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 400)
|
||||
t.same(JSON.parse(body), {
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_VALIDATION',
|
||||
message: 'querystring/hello must be integer',
|
||||
statusCode: 400
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request delete missing schema', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
method: 'DELETE',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/missing'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-length'], '' + body.length)
|
||||
t.same(JSON.parse(body), { hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - delete with body', t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: 'DELETE',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/body',
|
||||
body: {
|
||||
hello: 'world'
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body, { hello: 'world' })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// https://github.com/fastify/fastify/issues/936
|
||||
test('shorthand - delete with application/json Content-Type header and without body', t => {
|
||||
t.plan(4)
|
||||
const fastify = require('..')()
|
||||
fastify.delete('/', {}, (req, reply) => {
|
||||
t.equal(req.body, undefined)
|
||||
reply.send(req.body)
|
||||
})
|
||||
fastify.inject({
|
||||
method: 'DELETE',
|
||||
url: '/',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: null
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(response.payload.toString(), '')
|
||||
})
|
||||
})
|
||||
61
node_modules/fastify/test/diagnostics-channel.test.js
generated
vendored
Normal file
61
node_modules/fastify/test/diagnostics-channel.test.js
generated
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const proxyquire = require('proxyquire')
|
||||
|
||||
test('diagnostics_channel when present and subscribers', t => {
|
||||
t.plan(3)
|
||||
|
||||
let fastifyInHook
|
||||
|
||||
const dc = {
|
||||
channel (name) {
|
||||
t.equal(name, 'fastify.initialization')
|
||||
return {
|
||||
hasSubscribers: true,
|
||||
publish (event) {
|
||||
t.ok(event.fastify)
|
||||
fastifyInHook = event.fastify
|
||||
}
|
||||
}
|
||||
},
|
||||
'@noCallThru': true
|
||||
}
|
||||
|
||||
const fastify = proxyquire('../fastify', {
|
||||
'node:diagnostics_channel': dc
|
||||
})()
|
||||
t.equal(fastifyInHook, fastify)
|
||||
})
|
||||
|
||||
test('diagnostics_channel when present and no subscribers', t => {
|
||||
t.plan(1)
|
||||
|
||||
const dc = {
|
||||
channel (name) {
|
||||
t.equal(name, 'fastify.initialization')
|
||||
return {
|
||||
hasSubscribers: false,
|
||||
publish () {
|
||||
t.fail('publish should not be called')
|
||||
}
|
||||
}
|
||||
},
|
||||
'@noCallThru': true
|
||||
}
|
||||
|
||||
proxyquire('../fastify', {
|
||||
'node:diagnostics_channel': dc
|
||||
})()
|
||||
})
|
||||
|
||||
test('diagnostics_channel when not present', t => {
|
||||
t.plan(1)
|
||||
|
||||
t.doesNotThrow(() => {
|
||||
proxyquire('../fastify', {
|
||||
'node:diagnostics_channel': null
|
||||
})()
|
||||
})
|
||||
})
|
||||
69
node_modules/fastify/test/encapsulated-child-logger-factory.test.js
generated
vendored
Normal file
69
node_modules/fastify/test/encapsulated-child-logger-factory.test.js
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const Fastify = require('..')
|
||||
const fp = require('fastify-plugin')
|
||||
|
||||
test('encapsulates an child logger factory', async t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(async function (fastify) {
|
||||
fastify.setChildLoggerFactory(function pluginFactory (logger, bindings, opts) {
|
||||
const child = logger.child(bindings, opts)
|
||||
child.customLog = function (message) {
|
||||
t.equal(message, 'custom')
|
||||
}
|
||||
return child
|
||||
})
|
||||
fastify.get('/encapsulated', async (req) => {
|
||||
req.log.customLog('custom')
|
||||
})
|
||||
})
|
||||
|
||||
fastify.setChildLoggerFactory(function globalFactory (logger, bindings, opts) {
|
||||
const child = logger.child(bindings, opts)
|
||||
child.globalLog = function (message) {
|
||||
t.equal(message, 'global')
|
||||
}
|
||||
return child
|
||||
})
|
||||
fastify.get('/not-encapsulated', async (req) => {
|
||||
req.log.globalLog('global')
|
||||
})
|
||||
|
||||
const res1 = await fastify.inject('/encapsulated')
|
||||
t.equal(res1.statusCode, 200)
|
||||
|
||||
const res2 = await fastify.inject('/not-encapsulated')
|
||||
t.equal(res2.statusCode, 200)
|
||||
})
|
||||
|
||||
test('child logger factory set on root scope when using fastify-plugin', async t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(fp(async function (fastify) {
|
||||
// Using fastify-plugin, the factory should be set on the root scope
|
||||
fastify.setChildLoggerFactory(function pluginFactory (logger, bindings, opts) {
|
||||
const child = logger.child(bindings, opts)
|
||||
child.customLog = function (message) {
|
||||
t.equal(message, 'custom')
|
||||
}
|
||||
return child
|
||||
})
|
||||
fastify.get('/not-encapsulated-1', async (req) => {
|
||||
req.log.customLog('custom')
|
||||
})
|
||||
}))
|
||||
|
||||
fastify.get('/not-encapsulated-2', async (req) => {
|
||||
req.log.customLog('custom')
|
||||
})
|
||||
|
||||
const res1 = await fastify.inject('/not-encapsulated-1')
|
||||
t.equal(res1.statusCode, 200)
|
||||
|
||||
const res2 = await fastify.inject('/not-encapsulated-2')
|
||||
t.equal(res2.statusCode, 200)
|
||||
})
|
||||
50
node_modules/fastify/test/encapsulated-error-handler.test.js
generated
vendored
Normal file
50
node_modules/fastify/test/encapsulated-error-handler.test.js
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const Fastify = require('..')
|
||||
|
||||
test('encapsulates an error handler', async t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(async function (fastify) {
|
||||
fastify.setErrorHandler(async function a (err) {
|
||||
t.equal(err.message, 'kaboom')
|
||||
throw new Error('caught')
|
||||
})
|
||||
fastify.get('/encapsulated', async () => { throw new Error('kaboom') })
|
||||
})
|
||||
|
||||
fastify.setErrorHandler(async function b (err) {
|
||||
t.equal(err.message, 'caught')
|
||||
throw new Error('wrapped')
|
||||
})
|
||||
|
||||
const res = await fastify.inject('/encapsulated')
|
||||
t.equal(res.json().message, 'wrapped')
|
||||
})
|
||||
|
||||
test('onError hook nested', async t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.register(async function (fastify) {
|
||||
fastify.setErrorHandler(async function a (err) {
|
||||
t.equal(err.message, 'kaboom')
|
||||
throw new Error('caught')
|
||||
})
|
||||
fastify.get('/encapsulated', async () => { throw new Error('kaboom') })
|
||||
})
|
||||
|
||||
fastify.setErrorHandler(async function b (err) {
|
||||
t.equal(err.message, 'caught')
|
||||
throw new Error('wrapped')
|
||||
})
|
||||
|
||||
fastify.addHook('onError', async function (request, reply, err) {
|
||||
t.equal(err.message, 'kaboom')
|
||||
})
|
||||
|
||||
const res = await fastify.inject('/encapsulated')
|
||||
t.equal(res.json().message, 'wrapped')
|
||||
})
|
||||
10
node_modules/fastify/test/esm/errorCodes.test.mjs
generated
vendored
Normal file
10
node_modules/fastify/test/esm/errorCodes.test.mjs
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import { errorCodes } from '../../fastify.js'
|
||||
import t from 'tap'
|
||||
|
||||
t.test('errorCodes in ESM', async t => {
|
||||
// test a custom fastify error using errorCodes with ESM
|
||||
const customError = errorCodes.FST_ERR_VALIDATION('custom error message')
|
||||
t.ok(typeof customError !== 'undefined')
|
||||
t.ok(customError instanceof errorCodes.FST_ERR_VALIDATION)
|
||||
t.equal(customError.message, 'custom error message')
|
||||
})
|
||||
13
node_modules/fastify/test/esm/esm.test.mjs
generated
vendored
Normal file
13
node_modules/fastify/test/esm/esm.test.mjs
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
import t from 'tap'
|
||||
import Fastify from '../../fastify.js'
|
||||
|
||||
t.test('esm support', async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(import('./plugin.mjs'), { foo: 'bar' })
|
||||
fastify.register(import('./other.mjs'))
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
t.equal(fastify.foo, 'bar')
|
||||
})
|
||||
18
node_modules/fastify/test/esm/index.test.js
generated
vendored
Normal file
18
node_modules/fastify/test/esm/index.test.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const semver = require('semver')
|
||||
|
||||
if (semver.lt(process.versions.node, '14.13.0')) {
|
||||
t.skip('Skip named exports because Node version < 14.13.0')
|
||||
} else {
|
||||
// Node v8 throw a `SyntaxError: Unexpected token import`
|
||||
// even if this branch is never touch in the code,
|
||||
// by using `eval` we can avoid this issue.
|
||||
// eslint-disable-next-line
|
||||
new Function('module', 'return import(module)')('./named-exports.mjs').catch((err) => {
|
||||
process.nextTick(() => {
|
||||
throw err
|
||||
})
|
||||
})
|
||||
}
|
||||
14
node_modules/fastify/test/esm/named-exports.mjs
generated
vendored
Normal file
14
node_modules/fastify/test/esm/named-exports.mjs
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
import t from 'tap'
|
||||
import { fastify } from '../../fastify.js'
|
||||
|
||||
// This test is executed in index.test.js
|
||||
t.test('named exports support', async t => {
|
||||
const app = fastify()
|
||||
|
||||
app.register(import('./plugin.mjs'), { foo: 'bar' })
|
||||
app.register(import('./other.mjs'))
|
||||
|
||||
await app.ready()
|
||||
|
||||
t.equal(app.foo, 'bar')
|
||||
})
|
||||
8
node_modules/fastify/test/esm/other.mjs
generated
vendored
Normal file
8
node_modules/fastify/test/esm/other.mjs
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// Imported in both index.test.js & esm.test.mjs
|
||||
import t from 'tap'
|
||||
|
||||
async function other (fastify, opts) {
|
||||
t.equal(fastify.foo, 'bar')
|
||||
}
|
||||
|
||||
export default other
|
||||
8
node_modules/fastify/test/esm/plugin.mjs
generated
vendored
Normal file
8
node_modules/fastify/test/esm/plugin.mjs
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
// Imported in both index.test.js & esm.test.mjs
|
||||
async function plugin (fastify, opts) {
|
||||
fastify.decorate('foo', opts.foo)
|
||||
}
|
||||
|
||||
plugin[Symbol.for('skip-override')] = true
|
||||
|
||||
export default plugin
|
||||
291
node_modules/fastify/test/fastify-instance.test.js
generated
vendored
Normal file
291
node_modules/fastify/test/fastify-instance.test.js
generated
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('..')
|
||||
const os = require('node:os')
|
||||
|
||||
const {
|
||||
kOptions,
|
||||
kErrorHandler,
|
||||
kChildLoggerFactory
|
||||
} = require('../lib/symbols')
|
||||
|
||||
test('root fastify instance is an object', t => {
|
||||
t.plan(1)
|
||||
t.type(Fastify(), 'object')
|
||||
})
|
||||
|
||||
test('fastify instance should contains ajv options', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify({
|
||||
ajv: {
|
||||
customOptions: {
|
||||
nullable: false
|
||||
}
|
||||
}
|
||||
})
|
||||
t.same(fastify[kOptions].ajv, {
|
||||
customOptions: {
|
||||
nullable: false
|
||||
},
|
||||
plugins: []
|
||||
})
|
||||
})
|
||||
|
||||
test('fastify instance should contains ajv options.plugins nested arrays', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify({
|
||||
ajv: {
|
||||
customOptions: {
|
||||
nullable: false
|
||||
},
|
||||
plugins: [[]]
|
||||
}
|
||||
})
|
||||
t.same(fastify[kOptions].ajv, {
|
||||
customOptions: {
|
||||
nullable: false
|
||||
},
|
||||
plugins: [[]]
|
||||
})
|
||||
})
|
||||
|
||||
test('fastify instance get invalid ajv options', t => {
|
||||
t.plan(1)
|
||||
t.throws(() => Fastify({
|
||||
ajv: {
|
||||
customOptions: 8
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
test('fastify instance get invalid ajv options.plugins', t => {
|
||||
t.plan(1)
|
||||
t.throws(() => Fastify({
|
||||
ajv: {
|
||||
customOptions: {},
|
||||
plugins: 8
|
||||
}
|
||||
}))
|
||||
})
|
||||
|
||||
test('fastify instance should contain default errorHandler', t => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify()
|
||||
t.ok(fastify[kErrorHandler].func instanceof Function)
|
||||
t.same(fastify.errorHandler, fastify[kErrorHandler].func)
|
||||
t.same(Object.getOwnPropertyDescriptor(fastify, 'errorHandler').set, undefined)
|
||||
})
|
||||
|
||||
test('errorHandler in plugin should be separate from the external one', async t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register((instance, opts, done) => {
|
||||
const inPluginErrHandler = (_, __, reply) => {
|
||||
reply.send({ plugin: 'error-object' })
|
||||
}
|
||||
|
||||
instance.setErrorHandler(inPluginErrHandler)
|
||||
|
||||
t.notSame(instance.errorHandler, fastify.errorHandler)
|
||||
t.equal(instance.errorHandler.name, 'bound inPluginErrHandler')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
t.ok(fastify[kErrorHandler].func instanceof Function)
|
||||
t.same(fastify.errorHandler, fastify[kErrorHandler].func)
|
||||
})
|
||||
|
||||
test('fastify instance should contain default childLoggerFactory', t => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify()
|
||||
t.ok(fastify[kChildLoggerFactory] instanceof Function)
|
||||
t.same(fastify.childLoggerFactory, fastify[kChildLoggerFactory])
|
||||
t.same(Object.getOwnPropertyDescriptor(fastify, 'childLoggerFactory').set, undefined)
|
||||
})
|
||||
|
||||
test('childLoggerFactory in plugin should be separate from the external one', async t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register((instance, opts, done) => {
|
||||
const inPluginLoggerFactory = function (logger, bindings, opts) {
|
||||
return logger.child(bindings, opts)
|
||||
}
|
||||
|
||||
instance.setChildLoggerFactory(inPluginLoggerFactory)
|
||||
|
||||
t.notSame(instance.childLoggerFactory, fastify.childLoggerFactory)
|
||||
t.equal(instance.childLoggerFactory.name, 'inPluginLoggerFactory')
|
||||
|
||||
done()
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
|
||||
t.ok(fastify[kChildLoggerFactory] instanceof Function)
|
||||
t.same(fastify.childLoggerFactory, fastify[kChildLoggerFactory])
|
||||
})
|
||||
|
||||
test('ready should resolve in order when called multiply times (promises only)', async (t) => {
|
||||
const app = Fastify()
|
||||
const expectedOrder = [1, 2, 3, 4, 5]
|
||||
const result = []
|
||||
|
||||
const promises = [1, 2, 3, 4, 5]
|
||||
.map((id) => app.ready().then(() => result.push(id)))
|
||||
|
||||
await Promise.all(promises)
|
||||
|
||||
t.strictSame(result, expectedOrder, 'Should resolve in order')
|
||||
})
|
||||
|
||||
test('ready should reject in order when called multiply times (promises only)', async (t) => {
|
||||
const app = Fastify()
|
||||
const expectedOrder = [1, 2, 3, 4, 5]
|
||||
const result = []
|
||||
|
||||
app.register((instance, opts, done) => {
|
||||
setTimeout(() => done(new Error('test')), 500)
|
||||
})
|
||||
|
||||
const promises = [1, 2, 3, 4, 5]
|
||||
.map((id) => app.ready().catch(() => result.push(id)))
|
||||
|
||||
await Promise.all(promises)
|
||||
|
||||
t.strictSame(result, expectedOrder, 'Should resolve in order')
|
||||
})
|
||||
|
||||
test('ready should reject in order when called multiply times (callbacks only)', async (t) => {
|
||||
const app = Fastify()
|
||||
const expectedOrder = [1, 2, 3, 4, 5]
|
||||
const result = []
|
||||
|
||||
app.register((instance, opts, done) => {
|
||||
setTimeout(() => done(new Error('test')), 500)
|
||||
})
|
||||
|
||||
expectedOrder.map((id) => app.ready(() => result.push(id)))
|
||||
|
||||
await app.ready().catch(err => {
|
||||
t.equal(err.message, 'test')
|
||||
})
|
||||
|
||||
t.strictSame(result, expectedOrder, 'Should resolve in order')
|
||||
})
|
||||
|
||||
test('ready should resolve in order when called multiply times (callbacks only)', async (t) => {
|
||||
const app = Fastify()
|
||||
const expectedOrder = [1, 2, 3, 4, 5]
|
||||
const result = []
|
||||
|
||||
expectedOrder.map((id) => app.ready(() => result.push(id)))
|
||||
|
||||
await app.ready()
|
||||
|
||||
t.strictSame(result, expectedOrder, 'Should resolve in order')
|
||||
})
|
||||
|
||||
test('ready should resolve in order when called multiply times (mixed)', async (t) => {
|
||||
const app = Fastify()
|
||||
const expectedOrder = [1, 2, 3, 4, 5, 6]
|
||||
const result = []
|
||||
|
||||
for (const order of expectedOrder) {
|
||||
if (order % 2) {
|
||||
app.ready(() => result.push(order))
|
||||
} else {
|
||||
app.ready().then(() => result.push(order))
|
||||
}
|
||||
}
|
||||
|
||||
await app.ready()
|
||||
|
||||
t.strictSame(result, expectedOrder, 'Should resolve in order')
|
||||
})
|
||||
|
||||
test('ready should reject in order when called multiply times (mixed)', async (t) => {
|
||||
const app = Fastify()
|
||||
const expectedOrder = [1, 2, 3, 4, 5, 6]
|
||||
const result = []
|
||||
|
||||
app.register((instance, opts, done) => {
|
||||
setTimeout(() => done(new Error('test')), 500)
|
||||
})
|
||||
|
||||
for (const order of expectedOrder) {
|
||||
if (order % 2) {
|
||||
app.ready(() => result.push(order))
|
||||
} else {
|
||||
app.ready().then(null, () => result.push(order))
|
||||
}
|
||||
}
|
||||
|
||||
await app.ready().catch(err => {
|
||||
t.equal(err.message, 'test')
|
||||
})
|
||||
|
||||
t.strictSame(result, expectedOrder, 'Should resolve in order')
|
||||
})
|
||||
|
||||
test('ready should resolve in order when called multiply times (mixed)', async (t) => {
|
||||
const app = Fastify()
|
||||
const expectedOrder = [1, 2, 3, 4, 5, 6]
|
||||
const result = []
|
||||
|
||||
for (const order of expectedOrder) {
|
||||
if (order % 2) {
|
||||
app.ready().then(() => result.push(order))
|
||||
} else {
|
||||
app.ready(() => result.push(order))
|
||||
}
|
||||
}
|
||||
|
||||
await app.ready()
|
||||
|
||||
t.strictSame(result, expectedOrder, 'Should resolve in order')
|
||||
})
|
||||
|
||||
test('fastify instance should contains listeningOrigin property (with port and host)', async t => {
|
||||
t.plan(1)
|
||||
const port = 3000
|
||||
const host = '127.0.0.1'
|
||||
const fastify = Fastify()
|
||||
await fastify.listen({ port, host })
|
||||
t.same(fastify.listeningOrigin, `http://${host}:${port}`)
|
||||
await fastify.close()
|
||||
})
|
||||
|
||||
test('fastify instance should contains listeningOrigin property (with port and https)', async t => {
|
||||
t.plan(1)
|
||||
const port = 3000
|
||||
const host = '127.0.0.1'
|
||||
const fastify = Fastify({ https: {} })
|
||||
await fastify.listen({ port, host })
|
||||
t.same(fastify.listeningOrigin, `https://${host}:${port}`)
|
||||
await fastify.close()
|
||||
})
|
||||
|
||||
test('fastify instance should contains listeningOrigin property (unix socket)', { skip: os.platform() === 'win32' }, async t => {
|
||||
const fastify = Fastify()
|
||||
const path = `fastify.${Date.now()}.sock`
|
||||
await fastify.listen({ path })
|
||||
t.same(fastify.listeningOrigin, path)
|
||||
await fastify.close()
|
||||
})
|
||||
|
||||
test('fastify instance should contains listeningOrigin property (IPv6)', async t => {
|
||||
t.plan(1)
|
||||
const port = 3000
|
||||
const host = '::1'
|
||||
const fastify = Fastify()
|
||||
await fastify.listen({ port, host })
|
||||
t.same(fastify.listeningOrigin, `http://[::1]:${port}`)
|
||||
await fastify.close()
|
||||
})
|
||||
135
node_modules/fastify/test/findRoute.test.js
generated
vendored
Normal file
135
node_modules/fastify/test/findRoute.test.js
generated
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const Fastify = require('..')
|
||||
const fastifyPlugin = require('fastify-plugin')
|
||||
|
||||
test('findRoute should return null when route cannot be found due to a different method', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/artists/:artistId', {
|
||||
schema: {
|
||||
params: { artistId: { type: 'integer' } }
|
||||
},
|
||||
handler: (req, reply) => reply.send(typeof req.params.artistId)
|
||||
})
|
||||
|
||||
t.equal(fastify.findRoute({
|
||||
method: 'POST',
|
||||
url: '/artists/:artistId'
|
||||
}), null)
|
||||
})
|
||||
|
||||
test('findRoute should return an immutable route to avoid leaking and runtime route modifications', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/artists/:artistId', {
|
||||
schema: {
|
||||
params: { artistId: { type: 'integer' } }
|
||||
},
|
||||
handler: (req, reply) => reply.send(typeof req.params.artistId)
|
||||
})
|
||||
|
||||
let route = fastify.findRoute({
|
||||
method: 'GET',
|
||||
url: '/artists/:artistId'
|
||||
})
|
||||
|
||||
route.params = {
|
||||
...route.params,
|
||||
id: ':id'
|
||||
}
|
||||
|
||||
route = fastify.findRoute({
|
||||
method: 'GET',
|
||||
url: '/artists/:artistId'
|
||||
})
|
||||
t.same(route.params, { artistId: ':artistId' })
|
||||
})
|
||||
|
||||
test('findRoute should return null when route cannot be found due to a different path', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/artists/:artistId', {
|
||||
schema: {
|
||||
params: { artistId: { type: 'integer' } }
|
||||
},
|
||||
handler: (req, reply) => reply.send(typeof req.params.artistId)
|
||||
})
|
||||
|
||||
t.equal(fastify.findRoute({
|
||||
method: 'GET',
|
||||
url: '/books/:bookId'
|
||||
}), null)
|
||||
})
|
||||
|
||||
test('findRoute should return the route when found', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
const handler = (req, reply) => reply.send(typeof req.params.artistId)
|
||||
|
||||
fastify.get('/artists/:artistId', {
|
||||
schema: {
|
||||
params: { artistId: { type: 'integer' } }
|
||||
},
|
||||
handler
|
||||
})
|
||||
|
||||
const route = fastify.findRoute({
|
||||
method: 'GET',
|
||||
url: '/artists/:artistId'
|
||||
})
|
||||
|
||||
t.same(route.params, { artistId: ':artistId' })
|
||||
})
|
||||
|
||||
test('findRoute should work correctly when used within plugins', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
const handler = (req, reply) => reply.send(typeof req.params.artistId)
|
||||
fastify.get('/artists/:artistId', {
|
||||
schema: {
|
||||
params: { artistId: { type: 'integer' } }
|
||||
},
|
||||
handler
|
||||
})
|
||||
|
||||
function validateRoutePlugin (instance, opts, done) {
|
||||
const validateParams = function () {
|
||||
return instance.findRoute({
|
||||
method: 'GET',
|
||||
url: '/artists/:artistId'
|
||||
}) !== null
|
||||
}
|
||||
instance.decorate('validateRoutes', { validateParams })
|
||||
done()
|
||||
}
|
||||
|
||||
fastify.register(fastifyPlugin(validateRoutePlugin))
|
||||
|
||||
fastify.ready(() => {
|
||||
t.equal(fastify.validateRoutes.validateParams(), true)
|
||||
})
|
||||
})
|
||||
|
||||
test('findRoute should not expose store', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/artists/:artistId', {
|
||||
schema: {
|
||||
params: { artistId: { type: 'integer' } }
|
||||
},
|
||||
handler: (req, reply) => reply.send(typeof req.params.artistId)
|
||||
})
|
||||
|
||||
const route = fastify.findRoute({
|
||||
method: 'GET',
|
||||
url: '/artists/:artistId'
|
||||
})
|
||||
t.equal(route.store, undefined)
|
||||
})
|
||||
212
node_modules/fastify/test/fluent-schema.test.js
generated
vendored
Normal file
212
node_modules/fastify/test/fluent-schema.test.js
generated
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('..')
|
||||
const S = require('fluent-json-schema')
|
||||
|
||||
test('use fluent-json-schema object', t => {
|
||||
t.plan(15)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/:id', {
|
||||
handler: (req, reply) => { reply.send({ name: 'a', surname: 'b', dateOfBirth: '01-01-2020' }) },
|
||||
schema: {
|
||||
params: S.object().prop('id', S.integer().minimum(42)),
|
||||
headers: S.object().prop('x-custom', S.string().format('email')),
|
||||
query: S.object().prop('surname', S.string().required()),
|
||||
body: S.object().prop('name', S.string().required()),
|
||||
response: {
|
||||
200: S.object()
|
||||
.prop('name', S.string())
|
||||
.prop('surname', S.string())
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// check params
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/1',
|
||||
headers: { 'x-custom': 'me@me.me' },
|
||||
query: { surname: 'bar' },
|
||||
payload: { name: 'foo' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 400)
|
||||
t.same(res.json(), { statusCode: 400, code: 'FST_ERR_VALIDATION', error: 'Bad Request', message: 'params/id must be >= 42' })
|
||||
})
|
||||
|
||||
// check header
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/42',
|
||||
headers: { 'x-custom': 'invalid' },
|
||||
query: { surname: 'bar' },
|
||||
payload: { name: 'foo' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 400)
|
||||
t.same(res.json(), { statusCode: 400, code: 'FST_ERR_VALIDATION', error: 'Bad Request', message: 'headers/x-custom must match format "email"' })
|
||||
})
|
||||
|
||||
// check query
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/42',
|
||||
headers: { 'x-custom': 'me@me.me' },
|
||||
query: { },
|
||||
payload: { name: 'foo' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 400)
|
||||
t.same(res.json(), { statusCode: 400, code: 'FST_ERR_VALIDATION', error: 'Bad Request', message: 'querystring must have required property \'surname\'' })
|
||||
})
|
||||
|
||||
// check body
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/42',
|
||||
headers: { 'x-custom': 'me@me.me' },
|
||||
query: { surname: 'bar' },
|
||||
payload: { name: [1, 2, 3] }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 400)
|
||||
t.same(res.json(), { statusCode: 400, code: 'FST_ERR_VALIDATION', error: 'Bad Request', message: 'body/name must be string' })
|
||||
})
|
||||
|
||||
// check response
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/42',
|
||||
headers: { 'x-custom': 'me@me.me' },
|
||||
query: { surname: 'bar' },
|
||||
payload: { name: 'foo' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 200)
|
||||
t.same(res.json(), { name: 'a', surname: 'b' })
|
||||
})
|
||||
})
|
||||
|
||||
test('use complex fluent-json-schema object', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
const addressSchema = S.object()
|
||||
.id('#address')
|
||||
.prop('line1').required()
|
||||
.prop('line2')
|
||||
.prop('country').required()
|
||||
.prop('city').required()
|
||||
.prop('zipcode').required()
|
||||
|
||||
const commonSchemas = S.object()
|
||||
.id('https://fastify/demo')
|
||||
.definition('addressSchema', addressSchema)
|
||||
|
||||
fastify.addSchema(commonSchemas)
|
||||
|
||||
const bodyJsonSchema = S.object()
|
||||
.prop('residence', S.ref('https://fastify/demo#address')).required()
|
||||
.prop('office', S.ref('https://fastify/demo#/definitions/addressSchema')).required()
|
||||
|
||||
fastify.post('/the/url', { schema: { body: bodyJsonSchema } }, () => { })
|
||||
fastify.ready(err => t.error(err))
|
||||
})
|
||||
|
||||
test('use fluent schema and plain JSON schema', t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
const addressSchema = S.object()
|
||||
.id('#address')
|
||||
.prop('line1').required()
|
||||
.prop('line2')
|
||||
.prop('country').required()
|
||||
.prop('city').required()
|
||||
.prop('zipcode').required()
|
||||
|
||||
const commonSchemas = S.object()
|
||||
.id('https://fastify/demo')
|
||||
.definition('addressSchema', addressSchema)
|
||||
|
||||
const sharedAddressSchema = {
|
||||
$id: 'sharedAddress',
|
||||
type: 'object',
|
||||
required: ['line1', 'country', 'city', 'zipcode'],
|
||||
properties: {
|
||||
line1: { type: 'string' },
|
||||
line2: { type: 'string' },
|
||||
country: { type: 'string' },
|
||||
city: { type: 'string' },
|
||||
zipcode: { type: 'string' }
|
||||
}
|
||||
}
|
||||
|
||||
fastify.addSchema(commonSchemas)
|
||||
fastify.addSchema(sharedAddressSchema)
|
||||
|
||||
const bodyJsonSchema = S.object()
|
||||
.prop('residence', S.ref('https://fastify/demo#address')).required()
|
||||
.prop('office', S.ref('https://fastify/demo#/definitions/addressSchema')).required()
|
||||
|
||||
fastify.post('/the/url', { schema: { body: bodyJsonSchema } }, () => { })
|
||||
fastify.ready(err => t.error(err))
|
||||
})
|
||||
|
||||
test('Should call valueOf internally', t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = new Fastify()
|
||||
|
||||
const addressSchema = S.object()
|
||||
.id('#address')
|
||||
.prop('line1').required()
|
||||
.prop('line2')
|
||||
.prop('country').required()
|
||||
.prop('city').required()
|
||||
.prop('zipcode').required()
|
||||
|
||||
const commonSchemas = S.object()
|
||||
.id('https://fastify/demo')
|
||||
.definition('addressSchema', addressSchema)
|
||||
|
||||
fastify.addSchema(commonSchemas)
|
||||
|
||||
fastify.route({
|
||||
method: 'POST',
|
||||
url: '/query',
|
||||
handler: () => {},
|
||||
schema: {
|
||||
query: S.object().prop('hello', S.string()).required(),
|
||||
body: S.object().prop('hello', S.string()).required(),
|
||||
params: S.object().prop('hello', S.string()).required(),
|
||||
headers: S.object().prop('hello', S.string()).required(),
|
||||
response: {
|
||||
200: S.object().prop('hello', S.string()).required(),
|
||||
201: S.object().prop('hello', S.string()).required()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
method: 'POST',
|
||||
url: '/querystring',
|
||||
handler: () => {},
|
||||
schema: {
|
||||
querystring: S.object().prop('hello', S.string()).required(),
|
||||
body: S.object().prop('hello', S.string()).required(),
|
||||
params: S.object().prop('hello', S.string()).required(),
|
||||
headers: S.object().prop('hello', S.string()).required(),
|
||||
response: {
|
||||
200: S.object().prop('hello', S.string()).required(),
|
||||
201: S.object().prop('hello', S.string()).required()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
fastify.ready(t.error)
|
||||
})
|
||||
466
node_modules/fastify/test/genReqId.test.js
generated
vendored
Normal file
466
node_modules/fastify/test/genReqId.test.js
generated
vendored
Normal file
@@ -0,0 +1,466 @@
|
||||
'use strict'
|
||||
|
||||
const { Readable } = require('node:stream')
|
||||
const { test } = require('tap')
|
||||
const fp = require('fastify-plugin')
|
||||
const Fastify = require('..')
|
||||
|
||||
test('Should accept a custom genReqId function', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify({
|
||||
genReqId: function (req) {
|
||||
return 'a'
|
||||
}
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'a')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Custom genReqId function gets raw request as argument', t => {
|
||||
t.plan(9)
|
||||
|
||||
const REQUEST_ID = 'REQ-1234'
|
||||
|
||||
const fastify = Fastify({
|
||||
genReqId: function (req) {
|
||||
t.notOk('id' in req)
|
||||
t.notOk('raw' in req)
|
||||
t.ok(req instanceof Readable)
|
||||
// http.IncomingMessage does have `rawHeaders` property, but FastifyRequest does not
|
||||
const index = req.rawHeaders.indexOf('x-request-id')
|
||||
const xReqId = req.rawHeaders[index + 1]
|
||||
t.equal(xReqId, REQUEST_ID)
|
||||
t.equal(req.headers['x-request-id'], REQUEST_ID)
|
||||
return xReqId
|
||||
}
|
||||
})
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.equal(req.id, REQUEST_ID)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'x-request-id': REQUEST_ID
|
||||
},
|
||||
url: 'http://localhost:' + fastify.server.address().port
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, REQUEST_ID)
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Should accept option to set genReqId with setGenReqId option', t => {
|
||||
t.plan(9)
|
||||
|
||||
const fastify = Fastify({
|
||||
genReqId: function (req) {
|
||||
return 'base'
|
||||
}
|
||||
})
|
||||
|
||||
fastify.register(function (instance, opts, next) {
|
||||
instance.setGenReqId(function (req) {
|
||||
return 'foo'
|
||||
})
|
||||
instance.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
next()
|
||||
}, { prefix: 'foo' })
|
||||
|
||||
fastify.register(function (instance, opts, next) {
|
||||
instance.setGenReqId(function (req) {
|
||||
return 'bar'
|
||||
})
|
||||
instance.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
next()
|
||||
}, { prefix: 'bar' })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'base')
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/foo'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'foo')
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/bar'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'bar')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
|
||||
test('Should encapsulate setGenReqId', t => {
|
||||
t.plan(12)
|
||||
|
||||
const fastify = Fastify({
|
||||
genReqId: function (req) {
|
||||
return 'base'
|
||||
}
|
||||
})
|
||||
|
||||
const bazInstance = function (instance, opts, next) {
|
||||
instance.register(barInstance, { prefix: 'baz' })
|
||||
|
||||
instance.setGenReqId(function (req) {
|
||||
return 'baz'
|
||||
})
|
||||
instance.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
next()
|
||||
}
|
||||
|
||||
const barInstance = function (instance, opts, next) {
|
||||
instance.setGenReqId(function (req) {
|
||||
return 'bar'
|
||||
})
|
||||
instance.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
next()
|
||||
}
|
||||
|
||||
const fooInstance = function (instance, opts, next) {
|
||||
instance.register(bazInstance, { prefix: 'baz' })
|
||||
instance.register(barInstance, { prefix: 'bar' })
|
||||
|
||||
instance.setGenReqId(function (req) {
|
||||
return 'foo'
|
||||
})
|
||||
|
||||
instance.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
next()
|
||||
}
|
||||
|
||||
fastify.register(fooInstance, { prefix: 'foo' })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'base')
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/foo'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'foo')
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/foo/bar'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'bar')
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/foo/baz'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'baz')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
|
||||
test('Should encapsulate setGenReqId', t => {
|
||||
t.plan(12)
|
||||
|
||||
const fastify = Fastify({
|
||||
genReqId: function (req) {
|
||||
return 'base'
|
||||
}
|
||||
})
|
||||
|
||||
const bazInstance = function (instance, opts, next) {
|
||||
instance.register(barInstance, { prefix: 'baz' })
|
||||
|
||||
instance.setGenReqId(function (req) {
|
||||
return 'baz'
|
||||
})
|
||||
instance.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
next()
|
||||
}
|
||||
|
||||
const barInstance = function (instance, opts, next) {
|
||||
instance.setGenReqId(function (req) {
|
||||
return 'bar'
|
||||
})
|
||||
instance.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
next()
|
||||
}
|
||||
|
||||
const fooInstance = function (instance, opts, next) {
|
||||
instance.register(bazInstance, { prefix: 'baz' })
|
||||
instance.register(barInstance, { prefix: 'bar' })
|
||||
|
||||
instance.setGenReqId(function (req) {
|
||||
return 'foo'
|
||||
})
|
||||
|
||||
instance.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
next()
|
||||
}
|
||||
|
||||
fastify.register(fooInstance, { prefix: 'foo' })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'base')
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/foo'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'foo')
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/foo/bar'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'bar')
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/foo/baz'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'baz')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
|
||||
test('Should not alter parent of genReqId', t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
const fooInstance = function (instance, opts, next) {
|
||||
instance.setGenReqId(function (req) {
|
||||
return 'foo'
|
||||
})
|
||||
|
||||
instance.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
next()
|
||||
}
|
||||
|
||||
fastify.register(fooInstance, { prefix: 'foo' })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'req-1')
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/foo'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'foo')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
|
||||
test('Should have child instance user parent genReqId', t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify({
|
||||
genReqId: function (req) {
|
||||
return 'foo'
|
||||
}
|
||||
})
|
||||
|
||||
const fooInstance = function (instance, opts, next) {
|
||||
instance.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
next()
|
||||
}
|
||||
|
||||
fastify.register(fooInstance, { prefix: 'foo' })
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'foo')
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/foo'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'foo')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
|
||||
test('genReqId set on root scope when using fastify-plugin', t => {
|
||||
t.plan(6)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register(fp(function (fastify, options, done) {
|
||||
fastify.setGenReqId(function (req) {
|
||||
return 'not-encapsulated'
|
||||
})
|
||||
fastify.get('/not-encapsulated-1', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
done()
|
||||
}))
|
||||
|
||||
fastify.get('/not-encapsulated-2', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/not-encapsulated-1'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'not-encapsulated')
|
||||
fastify.close()
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/not-encapsulated-2'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.equal(payload.id, 'not-encapsulated')
|
||||
fastify.close()
|
||||
})
|
||||
})
|
||||
383
node_modules/fastify/test/get.test.js
generated
vendored
Normal file
383
node_modules/fastify/test/get.test.js
generated
vendored
Normal file
@@ -0,0 +1,383 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const sget = require('simple-get').concat
|
||||
const fastify = require('..')()
|
||||
|
||||
const schema = {
|
||||
schema: {
|
||||
response: {
|
||||
'2xx': {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const nullSchema = {
|
||||
schema: {
|
||||
response: {
|
||||
'2xx': {
|
||||
type: 'null'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const numberSchema = {
|
||||
schema: {
|
||||
response: {
|
||||
'2xx': {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const querySchema = {
|
||||
schema: {
|
||||
querystring: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const paramsSchema = {
|
||||
schema: {
|
||||
params: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
},
|
||||
test: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const headersSchema = {
|
||||
schema: {
|
||||
headers: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
'x-test': {
|
||||
type: 'number'
|
||||
},
|
||||
'Y-Test': {
|
||||
type: 'number'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test('shorthand - get', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.get('/', schema, function (req, reply) {
|
||||
reply.code(200).send({ hello: 'world' })
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('shorthand - get (return null)', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.get('/null', nullSchema, function (req, reply) {
|
||||
reply.code(200).send(null)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('shorthand - get params', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.get('/params/:foo/:test', paramsSchema, function (req, reply) {
|
||||
reply.code(200).send(req.params)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('shorthand - get, querystring schema', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.get('/query', querySchema, function (req, reply) {
|
||||
reply.code(200).send(req.query)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('shorthand - get, headers schema', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.get('/headers', headersSchema, function (req, reply) {
|
||||
reply.code(200).send(req.headers)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('missing schema - get', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.get('/missing', function (req, reply) {
|
||||
reply.code(200).send({ hello: 'world' })
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('custom serializer - get', t => {
|
||||
t.plan(1)
|
||||
|
||||
function customSerializer (data) {
|
||||
return JSON.stringify(data)
|
||||
}
|
||||
|
||||
try {
|
||||
fastify.get('/custom-serializer', numberSchema, function (req, reply) {
|
||||
reply.code(200).serializer(customSerializer).send({ hello: 'world' })
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('empty response', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.get('/empty', function (req, reply) {
|
||||
reply.code(200).send()
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('send a falsy boolean', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.get('/boolean', function (req, reply) {
|
||||
reply.code(200).send(false)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
test('shorthand - request get', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-length'], '' + body.length)
|
||||
t.same(JSON.parse(body), { hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request get params schema', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/params/world/123'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-length'], '' + body.length)
|
||||
t.same(JSON.parse(body), { foo: 'world', test: 123 })
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request get params schema error', t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/params/world/string'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 400)
|
||||
t.same(JSON.parse(body), {
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_VALIDATION',
|
||||
message: 'params/test must be integer',
|
||||
statusCode: 400
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request get headers schema', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'x-test': '1',
|
||||
'Y-Test': '3'
|
||||
},
|
||||
json: true,
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/headers'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body['x-test'], 1)
|
||||
t.equal(body['y-test'], 3)
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request get headers schema error', t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'x-test': 'abc'
|
||||
},
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/headers'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 400)
|
||||
t.same(JSON.parse(body), {
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_VALIDATION',
|
||||
message: 'headers/x-test must be number',
|
||||
statusCode: 400
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request get querystring schema', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/query?hello=123'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-length'], '' + body.length)
|
||||
t.same(JSON.parse(body), { hello: 123 })
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request get querystring schema error', t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/query?hello=world'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 400)
|
||||
t.same(JSON.parse(body), {
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_VALIDATION',
|
||||
message: 'querystring/hello must be integer',
|
||||
statusCode: 400
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request get missing schema', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/missing'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-length'], '' + body.length)
|
||||
t.same(JSON.parse(body), { hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - custom serializer', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/custom-serializer'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-length'], '' + body.length)
|
||||
t.same(JSON.parse(body), { hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - empty response', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/empty'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-length'], '0')
|
||||
t.same(body.toString(), '')
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - send a falsy boolean', t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/boolean'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), 'false')
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - send null value', t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/null'
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), 'null')
|
||||
})
|
||||
})
|
||||
})
|
||||
45
node_modules/fastify/test/handler-context.test.js
generated
vendored
Normal file
45
node_modules/fastify/test/handler-context.test.js
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
'use strict'
|
||||
const test = require('tap').test
|
||||
const { kRouteContext } = require('../lib/symbols')
|
||||
const fastify = require('../')
|
||||
|
||||
test('handlers receive correct `this` context', async (t) => {
|
||||
t.plan(4)
|
||||
|
||||
// simulate plugin that uses fastify-plugin
|
||||
const plugin = function (instance, opts, done) {
|
||||
instance.decorate('foo', 'foo')
|
||||
done()
|
||||
}
|
||||
plugin[Symbol.for('skip-override')] = true
|
||||
|
||||
const instance = fastify()
|
||||
instance.register(plugin)
|
||||
|
||||
instance.get('/', function (req, reply) {
|
||||
t.ok(this.foo)
|
||||
t.equal(this.foo, 'foo')
|
||||
reply.send()
|
||||
})
|
||||
|
||||
await instance.inject('/')
|
||||
|
||||
t.ok(instance.foo)
|
||||
t.equal(instance.foo, 'foo')
|
||||
})
|
||||
|
||||
test('handlers have access to the internal context', async (t) => {
|
||||
t.plan(5)
|
||||
|
||||
const instance = fastify()
|
||||
instance.get('/', { config: { foo: 'bar' } }, function (req, reply) {
|
||||
t.ok(reply[kRouteContext])
|
||||
t.ok(reply[kRouteContext].config)
|
||||
t.type(reply[kRouteContext].config, Object)
|
||||
t.ok(reply[kRouteContext].config.foo)
|
||||
t.equal(reply[kRouteContext].config.foo, 'bar')
|
||||
reply.send()
|
||||
})
|
||||
|
||||
await instance.inject('/')
|
||||
})
|
||||
93
node_modules/fastify/test/has-route.test.js
generated
vendored
Normal file
93
node_modules/fastify/test/has-route.test.js
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('../fastify')
|
||||
|
||||
test('hasRoute', t => {
|
||||
t.plan(5)
|
||||
const test = t.test
|
||||
const fastify = Fastify()
|
||||
|
||||
test('hasRoute - invalid options', t => {
|
||||
t.plan(3)
|
||||
|
||||
t.equal(fastify.hasRoute({ }), false)
|
||||
|
||||
t.equal(fastify.hasRoute({ method: 'GET' }), false)
|
||||
|
||||
t.equal(fastify.hasRoute({ constraints: [] }), false)
|
||||
})
|
||||
|
||||
test('hasRoute - primitive method', t => {
|
||||
t.plan(2)
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
handler: function (req, reply) {
|
||||
reply.send({ hello: 'world' })
|
||||
}
|
||||
})
|
||||
|
||||
t.equal(fastify.hasRoute({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}), true)
|
||||
|
||||
t.equal(fastify.hasRoute({
|
||||
method: 'POST',
|
||||
url: '/'
|
||||
}), false)
|
||||
})
|
||||
|
||||
test('hasRoute - with constraints', t => {
|
||||
t.plan(2)
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { version: '1.2.0' },
|
||||
handler: (req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
}
|
||||
})
|
||||
|
||||
t.equal(fastify.hasRoute({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { version: '1.2.0' }
|
||||
}), true)
|
||||
|
||||
t.equal(fastify.hasRoute({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
constraints: { version: '1.3.0' }
|
||||
}), false)
|
||||
})
|
||||
|
||||
test('hasRoute - parametric route regexp with constraints', t => {
|
||||
t.plan(1)
|
||||
// parametric with regexp
|
||||
fastify.get('/example/:file(^\\d+).png', function (request, reply) { })
|
||||
|
||||
t.equal(fastify.hasRoute({
|
||||
method: 'GET',
|
||||
url: '/example/12345.png'
|
||||
}), true)
|
||||
})
|
||||
|
||||
test('hasRoute - finds a route even if method is not uppercased', t => {
|
||||
t.plan(1)
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/equal',
|
||||
handler: function (req, reply) {
|
||||
reply.send({ hello: 'world' })
|
||||
}
|
||||
})
|
||||
|
||||
t.equal(fastify.hasRoute({
|
||||
method: 'get',
|
||||
url: '/equal'
|
||||
}), true)
|
||||
})
|
||||
})
|
||||
368
node_modules/fastify/test/head.test.js
generated
vendored
Normal file
368
node_modules/fastify/test/head.test.js
generated
vendored
Normal file
@@ -0,0 +1,368 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const sget = require('simple-get').concat
|
||||
const fastify = require('..')()
|
||||
|
||||
const schema = {
|
||||
schema: {
|
||||
response: {
|
||||
'2xx': {
|
||||
type: 'null'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const querySchema = {
|
||||
schema: {
|
||||
querystring: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const paramsSchema = {
|
||||
schema: {
|
||||
params: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
type: 'string'
|
||||
},
|
||||
test: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test('shorthand - head', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.head('/', schema, function (req, reply) {
|
||||
reply.code(200).send(null)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('shorthand - custom head', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.get('/proxy/*', function (req, reply) {
|
||||
reply.code(200).send(null)
|
||||
})
|
||||
|
||||
fastify.head('/proxy/*', function (req, reply) {
|
||||
reply.headers({ 'x-foo': 'bar' })
|
||||
reply.code(200).send(null)
|
||||
})
|
||||
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('shorthand - custom head with constraints', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.get('/proxy/*', { constraints: { version: '1.0.0' } }, function (req, reply) {
|
||||
reply.code(200).send(null)
|
||||
})
|
||||
|
||||
fastify.head('/proxy/*', { constraints: { version: '1.0.0' } }, function (req, reply) {
|
||||
reply.headers({ 'x-foo': 'bar' })
|
||||
reply.code(200).send(null)
|
||||
})
|
||||
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('shorthand - should not reset a head route', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.get('/query1', function (req, reply) {
|
||||
reply.code(200).send(null)
|
||||
})
|
||||
|
||||
fastify.put('/query1', function (req, reply) {
|
||||
reply.code(200).send(null)
|
||||
})
|
||||
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('shorthand - should override head route when setting multiple routes', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/query2',
|
||||
handler: function (req, reply) {
|
||||
reply.headers({ 'x-foo': 'bar' })
|
||||
reply.code(200).send(null)
|
||||
}
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
method: ['POST', 'PUT', 'HEAD'],
|
||||
url: '/query2',
|
||||
handler: function (req, reply) {
|
||||
reply.headers({ 'x-foo': 'bar' })
|
||||
reply.code(200).send(null)
|
||||
}
|
||||
})
|
||||
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('shorthand - should override head route when setting multiple routes', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.route({
|
||||
method: ['GET'],
|
||||
url: '/query3',
|
||||
handler: function (req, reply) {
|
||||
reply.headers({ 'x-foo': 'bar' })
|
||||
reply.code(200).send(null)
|
||||
}
|
||||
})
|
||||
|
||||
fastify.route({
|
||||
method: ['POST', 'PUT', 'HEAD'],
|
||||
url: '/query3',
|
||||
handler: function (req, reply) {
|
||||
reply.headers({ 'x-foo': 'bar' })
|
||||
reply.code(200).send(null)
|
||||
}
|
||||
})
|
||||
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('shorthand - should set get and head route in the same api call', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.route({
|
||||
method: ['HEAD', 'GET'],
|
||||
url: '/query4',
|
||||
handler: function (req, reply) {
|
||||
reply.headers({ 'x-foo': 'bar' })
|
||||
reply.code(200).send(null)
|
||||
}
|
||||
})
|
||||
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('shorthand - head params', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.head('/params/:foo/:test', paramsSchema, function (req, reply) {
|
||||
reply.send(null)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('shorthand - head, querystring schema', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.head('/query', querySchema, function (req, reply) {
|
||||
reply.code(200).send(null)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('missing schema - head', t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify.head('/missing', function (req, reply) {
|
||||
reply.code(200).send(null)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
test('shorthand - request head', t => {
|
||||
t.plan(2)
|
||||
sget({
|
||||
method: 'HEAD',
|
||||
url: 'http://localhost:' + fastify.server.address().port
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request head params schema', t => {
|
||||
t.plan(2)
|
||||
sget({
|
||||
method: 'HEAD',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/params/world/123'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request head params schema error', t => {
|
||||
t.plan(2)
|
||||
sget({
|
||||
method: 'HEAD',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/params/world/string'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 400)
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request head querystring schema', t => {
|
||||
t.plan(2)
|
||||
sget({
|
||||
method: 'HEAD',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/query?hello=123'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request head querystring schema error', t => {
|
||||
t.plan(2)
|
||||
sget({
|
||||
method: 'HEAD',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/query?hello=world'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 400)
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request head missing schema', t => {
|
||||
t.plan(2)
|
||||
sget({
|
||||
method: 'HEAD',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/missing'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request head custom head', t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: 'HEAD',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/proxy/test'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.headers['x-foo'], 'bar')
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - request head custom head with constraints', t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: 'HEAD',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/proxy/test',
|
||||
headers: {
|
||||
version: '1.0.0'
|
||||
}
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.headers['x-foo'], 'bar')
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - should not reset a head route', t => {
|
||||
t.plan(2)
|
||||
sget({
|
||||
method: 'HEAD',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/query1'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - should override head route when setting multiple routes', t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: 'HEAD',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/query2'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.headers['x-foo'], 'bar')
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - should override head route when setting multiple routes', t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: 'HEAD',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/query3'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.headers['x-foo'], 'bar')
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('shorthand - should set get and head route in the same api call', t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: 'HEAD',
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/query4'
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.headers['x-foo'], 'bar')
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
})
|
||||
65
node_modules/fastify/test/header-overflow.test.js
generated
vendored
Normal file
65
node_modules/fastify/test/header-overflow.test.js
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('..')
|
||||
const sget = require('simple-get').concat
|
||||
|
||||
const maxHeaderSize = 1024
|
||||
|
||||
test('Should return 431 if request header fields are too large', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify({ http: { maxHeaderSize } })
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
handler: (_req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
}
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, function (err) {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
headers: {
|
||||
'Large-Header': 'a'.repeat(maxHeaderSize)
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 431)
|
||||
})
|
||||
})
|
||||
|
||||
t.teardown(() => fastify.close())
|
||||
})
|
||||
|
||||
test('Should return 431 if URI is too long', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = Fastify({ http: { maxHeaderSize } })
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
handler: (_req, reply) => {
|
||||
reply.send({ hello: 'world' })
|
||||
}
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, function (err) {
|
||||
t.error(err)
|
||||
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port + `/${'a'.repeat(maxHeaderSize)}`
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 431)
|
||||
})
|
||||
})
|
||||
|
||||
t.teardown(() => fastify.close())
|
||||
})
|
||||
458
node_modules/fastify/test/helper.js
generated
vendored
Normal file
458
node_modules/fastify/test/helper.js
generated
vendored
Normal file
@@ -0,0 +1,458 @@
|
||||
'use strict'
|
||||
|
||||
const sget = require('simple-get').concat
|
||||
const dns = require('node:dns').promises
|
||||
const stream = require('node:stream')
|
||||
const { promisify } = require('node:util')
|
||||
const symbols = require('../lib/symbols')
|
||||
|
||||
module.exports.sleep = promisify(setTimeout)
|
||||
|
||||
/**
|
||||
* @param method HTTP request method
|
||||
* @param t tap instance
|
||||
* @param isSetErrorHandler true: using setErrorHandler
|
||||
*/
|
||||
module.exports.payloadMethod = function (method, t, isSetErrorHandler = false) {
|
||||
const test = t.test
|
||||
const fastify = require('..')()
|
||||
|
||||
if (isSetErrorHandler) {
|
||||
fastify.setErrorHandler(function (err, request, reply) {
|
||||
t.type(request, 'object')
|
||||
t.type(request, fastify[symbols.kRequest].parent)
|
||||
reply
|
||||
.code(err.statusCode)
|
||||
.type('application/json; charset=utf-8')
|
||||
.send(err)
|
||||
})
|
||||
}
|
||||
|
||||
const upMethod = method.toUpperCase()
|
||||
const loMethod = method.toLowerCase()
|
||||
|
||||
const schema = {
|
||||
schema: {
|
||||
response: {
|
||||
'2xx': {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test(`${upMethod} can be created`, t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify[loMethod]('/', schema, function (req, reply) {
|
||||
reply.code(200).send(req.body)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test(`${upMethod} without schema can be created`, t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify[loMethod]('/missing', function (req, reply) {
|
||||
reply.code(200).send(req.body)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test(`${upMethod} with body and querystring`, t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify[loMethod]('/with-query', function (req, reply) {
|
||||
req.body.hello = req.body.hello + req.query.foo
|
||||
reply.code(200).send(req.body)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test(`${upMethod} with bodyLimit option`, t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify[loMethod]('/with-limit', { bodyLimit: 1 }, function (req, reply) {
|
||||
reply.send(req.body)
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, function (err) {
|
||||
if (err) {
|
||||
t.error(err)
|
||||
return
|
||||
}
|
||||
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
test(`${upMethod} - correctly replies`, t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
body: {
|
||||
hello: 'world'
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body, { hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} - correctly replies with very large body`, t => {
|
||||
t.plan(3)
|
||||
|
||||
const largeString = 'world'.repeat(13200)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
body: { hello: largeString },
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body, { hello: largeString })
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} - correctly replies if the content type has the charset`, t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
body: JSON.stringify({ hello: 'world' }),
|
||||
headers: {
|
||||
'content-type': 'application/json; charset=utf-8'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body.toString(), JSON.stringify({ hello: 'world' }))
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} without schema - correctly replies`, t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/missing',
|
||||
body: {
|
||||
hello: 'world'
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body, { hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} with body and querystring - correctly replies`, t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/with-query?foo=hello',
|
||||
body: {
|
||||
hello: 'world'
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body, { hello: 'worldhello' })
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} with no body - correctly replies`, t => {
|
||||
t.plan(6)
|
||||
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/missing',
|
||||
headers: { 'Content-Length': '0' }
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(body.toString(), '')
|
||||
})
|
||||
|
||||
// Must use inject to make a request without a Content-Length header
|
||||
fastify.inject({
|
||||
method: upMethod,
|
||||
url: '/missing'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.payload.toString(), '')
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} returns 415 - incorrect media type if body is not json`, t => {
|
||||
t.plan(2)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/missing',
|
||||
body: 'hello world'
|
||||
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
if (upMethod === 'OPTIONS') {
|
||||
t.equal(response.statusCode, 200)
|
||||
} else {
|
||||
t.equal(response.statusCode, 415)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
if (loMethod === 'options') {
|
||||
test('OPTIONS returns 415 - should return 415 if Content-Type is not json or plain text', t => {
|
||||
t.plan(2)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/missing',
|
||||
body: 'hello world',
|
||||
headers: {
|
||||
'Content-Type': 'text/xml'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 415)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
test(`${upMethod} returns 400 - Bad Request`, t => {
|
||||
t.plan(4)
|
||||
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
body: 'hello world',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 400)
|
||||
})
|
||||
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': '0'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 400)
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} returns 413 - Payload Too Large`, t => {
|
||||
t.plan(upMethod === 'OPTIONS' ? 4 : 6)
|
||||
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': 1024 * 1024 + 1
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 413)
|
||||
})
|
||||
|
||||
// Node errors for OPTIONS requests with a stream body and no Content-Length header
|
||||
if (upMethod !== 'OPTIONS') {
|
||||
let chunk = Buffer.alloc(1024 * 1024 + 1, 0)
|
||||
const largeStream = new stream.Readable({
|
||||
read () {
|
||||
this.push(chunk)
|
||||
chunk = null
|
||||
}
|
||||
})
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: largeStream
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 413)
|
||||
})
|
||||
}
|
||||
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: `http://localhost:${fastify.server.address().port}/with-limit`,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: {},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 413)
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} should fail with empty body and application/json content-type`, t => {
|
||||
if (upMethod === 'OPTIONS') return t.end()
|
||||
|
||||
t.plan(12)
|
||||
|
||||
fastify.inject({
|
||||
method: `${upMethod}`,
|
||||
url: '/',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(res.payload), {
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_CTP_EMPTY_JSON_BODY',
|
||||
message: 'Body cannot be empty when content-type is set to \'application/json\'',
|
||||
statusCode: 400
|
||||
})
|
||||
})
|
||||
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: `http://localhost:${fastify.server.address().port}`,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
}, (err, res, body) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(body.toString()), {
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_CTP_EMPTY_JSON_BODY',
|
||||
message: 'Body cannot be empty when content-type is set to \'application/json\'',
|
||||
statusCode: 400
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: `${upMethod}`,
|
||||
url: '/',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
payload: null
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(res.payload), {
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_CTP_EMPTY_JSON_BODY',
|
||||
message: 'Body cannot be empty when content-type is set to \'application/json\'',
|
||||
statusCode: 400
|
||||
})
|
||||
})
|
||||
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: `http://localhost:${fastify.server.address().port}`,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
payload: null
|
||||
}, (err, res, body) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(body.toString()), {
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_CTP_EMPTY_JSON_BODY',
|
||||
message: 'Body cannot be empty when content-type is set to \'application/json\'',
|
||||
statusCode: 400
|
||||
})
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: `${upMethod}`,
|
||||
url: '/',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
payload: undefined
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(res.payload), {
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_CTP_EMPTY_JSON_BODY',
|
||||
message: 'Body cannot be empty when content-type is set to \'application/json\'',
|
||||
statusCode: 400
|
||||
})
|
||||
})
|
||||
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: `http://localhost:${fastify.server.address().port}`,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
payload: undefined
|
||||
}, (err, res, body) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(body.toString()), {
|
||||
error: 'Bad Request',
|
||||
code: 'FST_ERR_CTP_EMPTY_JSON_BODY',
|
||||
message: 'Body cannot be empty when content-type is set to \'application/json\'',
|
||||
statusCode: 400
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function lookupToIp (lookup) {
|
||||
return lookup.family === 6 ? `[${lookup.address}]` : lookup.address
|
||||
}
|
||||
|
||||
module.exports.getLoopbackHost = async () => {
|
||||
const lookup = await dns.lookup('localhost')
|
||||
return [lookup.address, lookupToIp(lookup)]
|
||||
}
|
||||
|
||||
module.exports.plainTextParser = function (request, callback) {
|
||||
let body = ''
|
||||
request.setEncoding('utf8')
|
||||
request.on('error', onError)
|
||||
request.on('data', onData)
|
||||
request.on('end', onEnd)
|
||||
function onError (err) {
|
||||
callback(err, null)
|
||||
}
|
||||
function onData (chunk) {
|
||||
body += chunk
|
||||
}
|
||||
function onEnd () {
|
||||
callback(null, body)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.getServerUrl = function (app) {
|
||||
const { address, port } = app.server.address()
|
||||
return address === '::1'
|
||||
? `http://[${address}]:${port}`
|
||||
: `http://${address}:${port}`
|
||||
}
|
||||
1075
node_modules/fastify/test/hooks-async.test.js
generated
vendored
Normal file
1075
node_modules/fastify/test/hooks-async.test.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1143
node_modules/fastify/test/hooks.on-listen.test.js
generated
vendored
Normal file
1143
node_modules/fastify/test/hooks.on-listen.test.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
403
node_modules/fastify/test/hooks.on-ready.test.js
generated
vendored
Normal file
403
node_modules/fastify/test/hooks.on-ready.test.js
generated
vendored
Normal file
@@ -0,0 +1,403 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const Fastify = require('../fastify')
|
||||
const immediate = require('node:util').promisify(setImmediate)
|
||||
|
||||
t.test('onReady should be called in order', t => {
|
||||
t.plan(7)
|
||||
const fastify = Fastify()
|
||||
|
||||
let order = 0
|
||||
|
||||
fastify.addHook('onReady', function (done) {
|
||||
t.equal(order++, 0, 'called in root')
|
||||
t.equal(this.pluginName, fastify.pluginName, 'the this binding is the right instance')
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.register(async (childOne, o) => {
|
||||
childOne.addHook('onReady', function (done) {
|
||||
t.equal(order++, 1, 'called in childOne')
|
||||
t.equal(this.pluginName, childOne.pluginName, 'the this binding is the right instance')
|
||||
done()
|
||||
})
|
||||
|
||||
childOne.register(async (childTwo, o) => {
|
||||
childTwo.addHook('onReady', async function () {
|
||||
await immediate()
|
||||
t.equal(order++, 2, 'called in childTwo')
|
||||
t.equal(this.pluginName, childTwo.pluginName, 'the this binding is the right instance')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
fastify.ready(err => t.error(err))
|
||||
})
|
||||
|
||||
t.test('onReady should be called once', async (t) => {
|
||||
const app = Fastify()
|
||||
let counter = 0
|
||||
|
||||
app.addHook('onReady', async function () {
|
||||
counter++
|
||||
})
|
||||
|
||||
const promises = [1, 2, 3, 4, 5].map((id) => app.ready().then(() => id))
|
||||
|
||||
const result = await Promise.race(promises)
|
||||
|
||||
t.strictSame(result, 1, 'Should resolve in order')
|
||||
t.equal(counter, 1, 'Should call onReady only once')
|
||||
})
|
||||
|
||||
t.test('async onReady should be called in order', async t => {
|
||||
t.plan(7)
|
||||
const fastify = Fastify()
|
||||
|
||||
let order = 0
|
||||
|
||||
fastify.addHook('onReady', async function () {
|
||||
await immediate()
|
||||
t.equal(order++, 0, 'called in root')
|
||||
t.equal(this.pluginName, fastify.pluginName, 'the this binding is the right instance')
|
||||
})
|
||||
|
||||
fastify.register(async (childOne, o) => {
|
||||
childOne.addHook('onReady', async function () {
|
||||
await immediate()
|
||||
t.equal(order++, 1, 'called in childOne')
|
||||
t.equal(this.pluginName, childOne.pluginName, 'the this binding is the right instance')
|
||||
})
|
||||
|
||||
childOne.register(async (childTwo, o) => {
|
||||
childTwo.addHook('onReady', async function () {
|
||||
await immediate()
|
||||
t.equal(order++, 2, 'called in childTwo')
|
||||
t.equal(this.pluginName, childTwo.pluginName, 'the this binding is the right instance')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
t.pass('ready')
|
||||
})
|
||||
|
||||
t.test('mix ready and onReady', async t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
let order = 0
|
||||
|
||||
fastify.addHook('onReady', async function () {
|
||||
await immediate()
|
||||
order++
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
t.equal(order, 1)
|
||||
|
||||
await fastify.ready()
|
||||
t.equal(order, 1, 'ready hooks execute once')
|
||||
})
|
||||
|
||||
t.test('listen and onReady order', async t => {
|
||||
t.plan(9)
|
||||
|
||||
const fastify = Fastify()
|
||||
let order = 0
|
||||
|
||||
fastify.register((instance, opts, done) => {
|
||||
instance.ready(checkOrder.bind(null, 0))
|
||||
instance.addHook('onReady', checkOrder.bind(null, 4))
|
||||
|
||||
instance.register((subinstance, opts, done) => {
|
||||
subinstance.ready(checkOrder.bind(null, 1))
|
||||
subinstance.addHook('onReady', checkOrder.bind(null, 5))
|
||||
|
||||
subinstance.register((realSubInstance, opts, done) => {
|
||||
realSubInstance.ready(checkOrder.bind(null, 2))
|
||||
realSubInstance.addHook('onReady', checkOrder.bind(null, 6))
|
||||
done()
|
||||
})
|
||||
done()
|
||||
})
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.addHook('onReady', checkOrder.bind(null, 3))
|
||||
|
||||
await fastify.ready()
|
||||
t.pass('trigger the onReady')
|
||||
await fastify.listen({ port: 0 })
|
||||
t.pass('do not trigger the onReady')
|
||||
|
||||
await fastify.close()
|
||||
|
||||
function checkOrder (shouldbe) {
|
||||
t.equal(order, shouldbe)
|
||||
order++
|
||||
}
|
||||
})
|
||||
|
||||
t.test('multiple ready calls', async t => {
|
||||
t.plan(11)
|
||||
|
||||
const fastify = Fastify()
|
||||
let order = 0
|
||||
|
||||
fastify.register(async (instance, opts) => {
|
||||
instance.ready(checkOrder.bind(null, 1))
|
||||
instance.addHook('onReady', checkOrder.bind(null, 6))
|
||||
|
||||
await instance.register(async (subinstance, opts) => {
|
||||
subinstance.ready(checkOrder.bind(null, 2))
|
||||
subinstance.addHook('onReady', checkOrder.bind(null, 7))
|
||||
})
|
||||
|
||||
t.equal(order, 0, 'ready and hooks not triggered yet')
|
||||
order++
|
||||
})
|
||||
|
||||
fastify.addHook('onReady', checkOrder.bind(null, 3))
|
||||
fastify.addHook('onReady', checkOrder.bind(null, 4))
|
||||
fastify.addHook('onReady', checkOrder.bind(null, 5))
|
||||
|
||||
await fastify.ready()
|
||||
t.pass('trigger the onReady')
|
||||
|
||||
await fastify.ready()
|
||||
t.pass('do not trigger the onReady')
|
||||
|
||||
await fastify.ready()
|
||||
t.pass('do not trigger the onReady')
|
||||
|
||||
function checkOrder (shouldbe) {
|
||||
t.equal(order, shouldbe)
|
||||
order++
|
||||
}
|
||||
})
|
||||
|
||||
t.test('onReady should manage error in sync', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addHook('onReady', function (done) {
|
||||
t.pass('called in root')
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.register(async (childOne, o) => {
|
||||
childOne.addHook('onReady', function (done) {
|
||||
t.pass('called in childOne')
|
||||
done(new Error('FAIL ON READY'))
|
||||
})
|
||||
|
||||
childOne.register(async (childTwo, o) => {
|
||||
childTwo.addHook('onReady', async function () {
|
||||
t.fail('should not be called')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
fastify.ready(err => {
|
||||
t.ok(err)
|
||||
t.equal(err.message, 'FAIL ON READY')
|
||||
})
|
||||
})
|
||||
|
||||
t.test('onReady should manage error in async', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addHook('onReady', function (done) {
|
||||
t.pass('called in root')
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.register(async (childOne, o) => {
|
||||
childOne.addHook('onReady', async function () {
|
||||
t.pass('called in childOne')
|
||||
throw new Error('FAIL ON READY')
|
||||
})
|
||||
|
||||
childOne.register(async (childTwo, o) => {
|
||||
childTwo.addHook('onReady', async function () {
|
||||
t.fail('should not be called')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
fastify.ready(err => {
|
||||
t.ok(err)
|
||||
t.equal(err.message, 'FAIL ON READY')
|
||||
})
|
||||
})
|
||||
|
||||
t.test('onReady should manage sync error', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addHook('onReady', function (done) {
|
||||
t.pass('called in root')
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.register(async (childOne, o) => {
|
||||
childOne.addHook('onReady', function (done) {
|
||||
t.pass('called in childOne')
|
||||
throw new Error('FAIL UNWANTED SYNC EXCEPTION')
|
||||
})
|
||||
|
||||
childOne.register(async (childTwo, o) => {
|
||||
childTwo.addHook('onReady', async function () {
|
||||
t.fail('should not be called')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
fastify.ready(err => {
|
||||
t.ok(err)
|
||||
t.equal(err.message, 'FAIL UNWANTED SYNC EXCEPTION')
|
||||
})
|
||||
})
|
||||
|
||||
t.test('onReady can not add decorators or application hooks', t => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addHook('onReady', function (done) {
|
||||
t.pass('called in root')
|
||||
fastify.decorate('test', () => {})
|
||||
|
||||
fastify.addHook('onReady', async function () {
|
||||
t.fail('it will be not called')
|
||||
})
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.addHook('onReady', function (done) {
|
||||
t.ok(this.hasDecorator('test'))
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.ready(err => { t.error(err) })
|
||||
})
|
||||
|
||||
t.test('onReady cannot add lifecycle hooks', t => {
|
||||
t.plan(5)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addHook('onReady', function (done) {
|
||||
t.pass('called in root')
|
||||
try {
|
||||
fastify.addHook('onRequest', (request, reply, done) => {})
|
||||
} catch (error) {
|
||||
t.ok(error)
|
||||
t.equal(error.message, 'Root plugin has already booted')
|
||||
// TODO: look where the error pops up
|
||||
t.equal(error.code, 'AVV_ERR_ROOT_PLG_BOOTED')
|
||||
done(error)
|
||||
}
|
||||
})
|
||||
|
||||
fastify.addHook('onRequest', (request, reply, done) => {})
|
||||
fastify.get('/', async () => 'hello')
|
||||
|
||||
fastify.ready((err) => { t.ok(err) })
|
||||
})
|
||||
|
||||
t.test('onReady throw loading error', t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
|
||||
try {
|
||||
fastify.addHook('onReady', async function (done) {})
|
||||
} catch (e) {
|
||||
t.ok(e.code, 'FST_ERR_HOOK_INVALID_ASYNC_HANDLER')
|
||||
t.ok(e.message === 'Async function has too many arguments. Async hooks should not use the \'done\' argument.')
|
||||
}
|
||||
})
|
||||
|
||||
t.test('onReady does not call done', t => {
|
||||
t.plan(6)
|
||||
const fastify = Fastify({ pluginTimeout: 500 })
|
||||
|
||||
fastify.addHook('onReady', function (done) {
|
||||
t.pass('called in root')
|
||||
// done() // don't call done to test timeout
|
||||
})
|
||||
|
||||
fastify.ready(err => {
|
||||
t.ok(err)
|
||||
t.equal(err.message, "A callback for 'onReady' hook timed out. You may have forgotten to call 'done' function or to resolve a Promise")
|
||||
t.equal(err.code, 'FST_ERR_HOOK_TIMEOUT')
|
||||
t.ok(err.cause)
|
||||
t.equal(err.cause.code, 'AVV_ERR_READY_TIMEOUT')
|
||||
})
|
||||
})
|
||||
|
||||
t.test('onReady execution order', t => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify({ })
|
||||
|
||||
let i = 0
|
||||
fastify.ready(() => { i++; t.equal(i, 1) })
|
||||
fastify.ready(() => { i++; t.equal(i, 2) })
|
||||
fastify.ready(() => { i++; t.equal(i, 3) })
|
||||
})
|
||||
|
||||
t.test('ready return the server with callback', t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.ready((err, instance) => {
|
||||
t.error(err)
|
||||
t.same(instance, fastify)
|
||||
})
|
||||
})
|
||||
|
||||
t.test('ready return the server with Promise', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.ready()
|
||||
.then(instance => { t.same(instance, fastify) })
|
||||
.catch(err => { t.fail(err) })
|
||||
})
|
||||
|
||||
t.test('ready return registered', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register((one, opts, done) => {
|
||||
one.ready().then(itself => { t.same(itself, one) })
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.register((two, opts, done) => {
|
||||
two.ready().then(itself => { t.same(itself, two) })
|
||||
|
||||
two.register((twoDotOne, opts, done) => {
|
||||
twoDotOne.ready().then(itself => { t.same(itself, twoDotOne) })
|
||||
done()
|
||||
})
|
||||
done()
|
||||
})
|
||||
|
||||
fastify.ready()
|
||||
.then(instance => { t.same(instance, fastify) })
|
||||
.catch(err => { t.fail(err) })
|
||||
})
|
||||
|
||||
t.test('do not crash with error in follow up onReady hook', async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addHook('onReady', async function () {
|
||||
})
|
||||
|
||||
fastify.addHook('onReady', function () {
|
||||
throw new Error('kaboom')
|
||||
})
|
||||
|
||||
await t.rejects(fastify.ready())
|
||||
})
|
||||
3626
node_modules/fastify/test/hooks.test.js
generated
vendored
Normal file
3626
node_modules/fastify/test/hooks.test.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
172
node_modules/fastify/test/http2/closing.test.js
generated
vendored
Normal file
172
node_modules/fastify/test/http2/closing.test.js
generated
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const Fastify = require('../..')
|
||||
const http2 = require('node:http2')
|
||||
const { promisify } = require('node:util')
|
||||
const connect = promisify(http2.connect)
|
||||
const { once } = require('node:events')
|
||||
const { buildCertificate } = require('../build-certificate')
|
||||
const { getServerUrl } = require('../helper')
|
||||
|
||||
t.before(buildCertificate)
|
||||
|
||||
t.test('http/2 request while fastify closing', t => {
|
||||
let fastify
|
||||
try {
|
||||
fastify = Fastify({
|
||||
http2: true
|
||||
})
|
||||
t.pass('http2 successfully loaded')
|
||||
} catch (e) {
|
||||
t.fail('http2 loading failed', e)
|
||||
}
|
||||
|
||||
fastify.get('/', () => Promise.resolve({}))
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
t.test('return 200', t => {
|
||||
const url = getServerUrl(fastify)
|
||||
const session = http2.connect(url, function () {
|
||||
this.request({
|
||||
':method': 'GET',
|
||||
':path': '/'
|
||||
}).on('response', headers => {
|
||||
t.equal(headers[':status'], 503)
|
||||
t.end()
|
||||
this.destroy()
|
||||
}).on('error', () => {
|
||||
// Nothing to do here,
|
||||
// we are not interested in this error that might
|
||||
// happen or not
|
||||
})
|
||||
fastify.close()
|
||||
})
|
||||
session.on('error', () => {
|
||||
// Nothing to do here,
|
||||
// we are not interested in this error that might
|
||||
// happen or not
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.test('http/2 request while fastify closing - return503OnClosing: false', t => {
|
||||
let fastify
|
||||
try {
|
||||
fastify = Fastify({
|
||||
http2: true,
|
||||
return503OnClosing: false
|
||||
})
|
||||
t.pass('http2 successfully loaded')
|
||||
} catch (e) {
|
||||
t.fail('http2 loading failed', e)
|
||||
}
|
||||
|
||||
fastify.get('/', () => Promise.resolve({}))
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
t.test('return 200', t => {
|
||||
const url = getServerUrl(fastify)
|
||||
const session = http2.connect(url, function () {
|
||||
this.request({
|
||||
':method': 'GET',
|
||||
':path': '/'
|
||||
}).on('response', headers => {
|
||||
t.equal(headers[':status'], 200)
|
||||
t.end()
|
||||
this.destroy()
|
||||
}).on('error', () => {
|
||||
// Nothing to do here,
|
||||
// we are not interested in this error that might
|
||||
// happen or not
|
||||
})
|
||||
fastify.close()
|
||||
})
|
||||
session.on('error', () => {
|
||||
// Nothing to do here,
|
||||
// we are not interested in this error that might
|
||||
// happen or not
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
t.test('http/2 closes successfully with async await', async t => {
|
||||
const fastify = Fastify({
|
||||
http2SessionTimeout: 100,
|
||||
http2: true
|
||||
})
|
||||
|
||||
await fastify.listen({ port: 0 })
|
||||
|
||||
const url = getServerUrl(fastify)
|
||||
const session = await connect(url)
|
||||
// An error might or might not happen, as it's OS dependent.
|
||||
session.on('error', () => {})
|
||||
await fastify.close()
|
||||
})
|
||||
|
||||
t.test('https/2 closes successfully with async await', async t => {
|
||||
const fastify = Fastify({
|
||||
http2SessionTimeout: 100,
|
||||
http2: true,
|
||||
https: {
|
||||
key: global.context.key,
|
||||
cert: global.context.cert
|
||||
}
|
||||
})
|
||||
|
||||
await fastify.listen({ port: 0 })
|
||||
|
||||
const url = getServerUrl(fastify)
|
||||
const session = await connect(url)
|
||||
// An error might or might not happen, as it's OS dependent.
|
||||
session.on('error', () => {})
|
||||
await fastify.close()
|
||||
})
|
||||
|
||||
t.test('http/2 server side session emits a timeout event', async t => {
|
||||
let _resolve
|
||||
const p = new Promise((resolve) => { _resolve = resolve })
|
||||
|
||||
const fastify = Fastify({
|
||||
http2SessionTimeout: 100,
|
||||
http2: true
|
||||
})
|
||||
|
||||
fastify.get('/', async (req) => {
|
||||
req.raw.stream.session.on('timeout', () => _resolve())
|
||||
return {}
|
||||
})
|
||||
|
||||
await fastify.listen({ port: 0 })
|
||||
|
||||
const url = getServerUrl(fastify)
|
||||
const session = await connect(url)
|
||||
const req = session.request({
|
||||
':method': 'GET',
|
||||
':path': '/'
|
||||
}).end()
|
||||
|
||||
const [headers] = await once(req, 'response')
|
||||
t.equal(headers[':status'], 200)
|
||||
req.resume()
|
||||
|
||||
// An error might or might not happen, as it's OS dependent.
|
||||
session.on('error', () => {})
|
||||
await p
|
||||
await fastify.close()
|
||||
})
|
||||
91
node_modules/fastify/test/http2/constraint.test.js
generated
vendored
Normal file
91
node_modules/fastify/test/http2/constraint.test.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('../..')
|
||||
const h2url = require('h2url')
|
||||
|
||||
const alpha = { res: 'alpha' }
|
||||
const beta = { res: 'beta' }
|
||||
|
||||
const { buildCertificate } = require('../build-certificate')
|
||||
t.before(buildCertificate)
|
||||
|
||||
test('A route supports host constraints under http2 protocol and secure connection', (t) => {
|
||||
t.plan(5)
|
||||
|
||||
let fastify
|
||||
try {
|
||||
fastify = Fastify({
|
||||
http2: true,
|
||||
https: {
|
||||
key: global.context.key,
|
||||
cert: global.context.cert
|
||||
}
|
||||
})
|
||||
t.pass('Key/cert successfully loaded')
|
||||
} catch (e) {
|
||||
t.fail('Key/cert loading failed', e)
|
||||
}
|
||||
|
||||
const constrain = 'fastify.dev'
|
||||
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
handler: function (_, reply) {
|
||||
reply.code(200).send(alpha)
|
||||
}
|
||||
})
|
||||
fastify.route({
|
||||
method: 'GET',
|
||||
url: '/beta',
|
||||
constraints: { host: constrain },
|
||||
handler: function (_, reply) {
|
||||
reply.code(200).send(beta)
|
||||
}
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
t.test('https get request - no constrain', async (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const url = `https://localhost:${fastify.server.address().port}`
|
||||
const res = await h2url.concat({ url })
|
||||
|
||||
t.equal(res.headers[':status'], 200)
|
||||
t.equal(res.headers['content-length'], '' + JSON.stringify(alpha).length)
|
||||
t.same(JSON.parse(res.body), alpha)
|
||||
})
|
||||
|
||||
t.test('https get request - constrain', async (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const url = `https://localhost:${fastify.server.address().port}/beta`
|
||||
const res = await h2url.concat({
|
||||
url,
|
||||
headers: {
|
||||
':authority': constrain
|
||||
}
|
||||
})
|
||||
|
||||
t.equal(res.headers[':status'], 200)
|
||||
t.equal(res.headers['content-length'], '' + JSON.stringify(beta).length)
|
||||
t.same(JSON.parse(res.body), beta)
|
||||
})
|
||||
|
||||
t.test('https get request - constrain - not found', async (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const url = `https://localhost:${fastify.server.address().port}/beta`
|
||||
const res = await h2url.concat({
|
||||
url
|
||||
})
|
||||
|
||||
t.equal(res.headers[':status'], 404)
|
||||
})
|
||||
})
|
||||
})
|
||||
35
node_modules/fastify/test/http2/head.test.js
generated
vendored
Normal file
35
node_modules/fastify/test/http2/head.test.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('../..')
|
||||
const h2url = require('h2url')
|
||||
const msg = { hello: 'world' }
|
||||
|
||||
let fastify
|
||||
try {
|
||||
fastify = Fastify({
|
||||
http2: true
|
||||
})
|
||||
t.pass('http2 successfully loaded')
|
||||
} catch (e) {
|
||||
t.fail('http2 loading failed', e)
|
||||
}
|
||||
|
||||
fastify.all('/', function (req, reply) {
|
||||
reply.code(200).send(msg)
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
test('http HEAD request', async (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const url = `http://localhost:${fastify.server.address().port}`
|
||||
const res = await h2url.concat({ url, method: 'HEAD' })
|
||||
|
||||
t.equal(res.headers[':status'], 200)
|
||||
})
|
||||
})
|
||||
18
node_modules/fastify/test/http2/missing-http2-module.test.js
generated
vendored
Normal file
18
node_modules/fastify/test/http2/missing-http2-module.test.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const proxyquire = require('proxyquire')
|
||||
const server = proxyquire('../../lib/server', { 'node:http2': null })
|
||||
const Fastify = proxyquire('../..', { './lib/server.js': server })
|
||||
|
||||
test('should throw when http2 module cannot be found', t => {
|
||||
t.plan(2)
|
||||
try {
|
||||
Fastify({ http2: true })
|
||||
t.fail('fastify did not throw expected error')
|
||||
} catch (err) {
|
||||
t.equal(err.code, 'FST_ERR_HTTP2_INVALID_VERSION')
|
||||
t.equal(err.message, 'HTTP2 is available only from node >= 8.8.1')
|
||||
}
|
||||
})
|
||||
53
node_modules/fastify/test/http2/plain.test.js
generated
vendored
Normal file
53
node_modules/fastify/test/http2/plain.test.js
generated
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('../..')
|
||||
const h2url = require('h2url')
|
||||
const msg = { hello: 'world' }
|
||||
|
||||
let fastify
|
||||
try {
|
||||
fastify = Fastify({
|
||||
http2: true
|
||||
})
|
||||
t.pass('http2 successfully loaded')
|
||||
} catch (e) {
|
||||
t.fail('http2 loading failed', e)
|
||||
}
|
||||
|
||||
fastify.get('/', function (req, reply) {
|
||||
reply.code(200).send(msg)
|
||||
})
|
||||
|
||||
fastify.get('/hostname', function (req, reply) {
|
||||
reply.code(200).send(req.hostname)
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
test('http get request', async (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const url = `http://localhost:${fastify.server.address().port}`
|
||||
const res = await h2url.concat({ url })
|
||||
|
||||
t.equal(res.headers[':status'], 200)
|
||||
t.equal(res.headers['content-length'], '' + JSON.stringify(msg).length)
|
||||
|
||||
t.same(JSON.parse(res.body), msg)
|
||||
})
|
||||
|
||||
test('http hostname', async (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const hostname = `localhost:${fastify.server.address().port}`
|
||||
|
||||
const url = `http://${hostname}/hostname`
|
||||
const res = await h2url.concat({ url })
|
||||
|
||||
t.equal(res.body, hostname)
|
||||
})
|
||||
})
|
||||
110
node_modules/fastify/test/http2/secure-with-fallback.test.js
generated
vendored
Normal file
110
node_modules/fastify/test/http2/secure-with-fallback.test.js
generated
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('../..')
|
||||
const h2url = require('h2url')
|
||||
const sget = require('simple-get').concat
|
||||
const msg = { hello: 'world' }
|
||||
|
||||
const { buildCertificate } = require('../build-certificate')
|
||||
t.before(buildCertificate)
|
||||
|
||||
test('secure with fallback', (t) => {
|
||||
t.plan(7)
|
||||
|
||||
let fastify
|
||||
try {
|
||||
fastify = Fastify({
|
||||
http2: true,
|
||||
https: {
|
||||
allowHTTP1: true,
|
||||
key: global.context.key,
|
||||
cert: global.context.cert
|
||||
}
|
||||
})
|
||||
t.pass('Key/cert successfully loaded')
|
||||
} catch (e) {
|
||||
t.fail('Key/cert loading failed', e)
|
||||
}
|
||||
|
||||
fastify.get('/', function (req, reply) {
|
||||
reply.code(200).send(msg)
|
||||
})
|
||||
|
||||
fastify.post('/', function (req, reply) {
|
||||
reply.code(200).send(req.body)
|
||||
})
|
||||
|
||||
fastify.get('/error', async function (req, reply) {
|
||||
throw new Error('kaboom')
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
t.test('https get error', async (t) => {
|
||||
t.plan(1)
|
||||
|
||||
const url = `https://localhost:${fastify.server.address().port}/error`
|
||||
const res = await h2url.concat({ url })
|
||||
|
||||
t.equal(res.headers[':status'], 500)
|
||||
})
|
||||
|
||||
t.test('https post', async (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const url = `https://localhost:${fastify.server.address().port}`
|
||||
const res = await h2url.concat({
|
||||
url,
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ hello: 'http2' }),
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
})
|
||||
|
||||
t.equal(res.headers[':status'], 200)
|
||||
t.same(JSON.parse(res.body), { hello: 'http2' })
|
||||
})
|
||||
|
||||
t.test('https get request', async (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const url = `https://localhost:${fastify.server.address().port}`
|
||||
const res = await h2url.concat({ url })
|
||||
|
||||
t.equal(res.headers[':status'], 200)
|
||||
t.equal(res.headers['content-length'], '' + JSON.stringify(msg).length)
|
||||
t.same(JSON.parse(res.body), msg)
|
||||
})
|
||||
|
||||
t.test('http1 get request', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'https://localhost:' + fastify.server.address().port,
|
||||
rejectUnauthorized: false
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-length'], '' + body.length)
|
||||
t.same(JSON.parse(body), { hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
t.test('http1 get error', (t) => {
|
||||
t.plan(2)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'https://localhost:' + fastify.server.address().port + '/error',
|
||||
rejectUnauthorized: false
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 500)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
59
node_modules/fastify/test/http2/secure.test.js
generated
vendored
Normal file
59
node_modules/fastify/test/http2/secure.test.js
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('../..')
|
||||
const h2url = require('h2url')
|
||||
const msg = { hello: 'world' }
|
||||
|
||||
const { buildCertificate } = require('../build-certificate')
|
||||
t.before(buildCertificate)
|
||||
|
||||
test('secure', (t) => {
|
||||
t.plan(4)
|
||||
|
||||
let fastify
|
||||
try {
|
||||
fastify = Fastify({
|
||||
http2: true,
|
||||
https: {
|
||||
key: global.context.key,
|
||||
cert: global.context.cert
|
||||
}
|
||||
})
|
||||
t.pass('Key/cert successfully loaded')
|
||||
} catch (e) {
|
||||
t.fail('Key/cert loading failed', e)
|
||||
}
|
||||
|
||||
fastify.get('/', function (req, reply) {
|
||||
reply.code(200).send(msg)
|
||||
})
|
||||
fastify.get('/proto', function (req, reply) {
|
||||
reply.code(200).send({ proto: req.protocol })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
t.test('https get request', async (t) => {
|
||||
t.plan(3)
|
||||
|
||||
const url = `https://localhost:${fastify.server.address().port}`
|
||||
const res = await h2url.concat({ url })
|
||||
|
||||
t.equal(res.headers[':status'], 200)
|
||||
t.equal(res.headers['content-length'], '' + JSON.stringify(msg).length)
|
||||
t.same(JSON.parse(res.body), msg)
|
||||
})
|
||||
|
||||
t.test('https get request without trust proxy - protocol', async (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const url = `https://localhost:${fastify.server.address().port}/proto`
|
||||
t.same(JSON.parse((await h2url.concat({ url })).body), { proto: 'https' })
|
||||
t.same(JSON.parse((await h2url.concat({ url, headers: { 'X-Forwarded-Proto': 'lorem' } })).body), { proto: 'https' })
|
||||
})
|
||||
})
|
||||
})
|
||||
35
node_modules/fastify/test/http2/unknown-http-method.test.js
generated
vendored
Normal file
35
node_modules/fastify/test/http2/unknown-http-method.test.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('../..')
|
||||
const h2url = require('h2url')
|
||||
const msg = { hello: 'world' }
|
||||
|
||||
const fastify = Fastify({
|
||||
http2: true
|
||||
})
|
||||
|
||||
fastify.get('/', function (req, reply) {
|
||||
reply.code(200).send(msg)
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
test('http UNKNOWN_METHOD request', async (t) => {
|
||||
t.plan(2)
|
||||
|
||||
const url = `http://localhost:${fastify.server.address().port}`
|
||||
const res = await h2url.concat({ url, method: 'UNKNOWN_METHOD' })
|
||||
|
||||
t.equal(res.headers[':status'], 404)
|
||||
t.same(JSON.parse(res.body), {
|
||||
statusCode: 404,
|
||||
code: 'FST_ERR_NOT_FOUND',
|
||||
error: 'Not Found',
|
||||
message: 'Not Found'
|
||||
})
|
||||
})
|
||||
})
|
||||
63
node_modules/fastify/test/https/custom-https-server.test.js
generated
vendored
Normal file
63
node_modules/fastify/test/https/custom-https-server.test.js
generated
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('../..')
|
||||
const https = require('node:https')
|
||||
const dns = require('node:dns').promises
|
||||
const sget = require('simple-get').concat
|
||||
const { buildCertificate } = require('../build-certificate')
|
||||
|
||||
async function setup () {
|
||||
await buildCertificate()
|
||||
|
||||
const localAddresses = await dns.lookup('localhost', { all: true })
|
||||
|
||||
test('Should support a custom https server', { skip: localAddresses.length < 1 }, async t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify({
|
||||
serverFactory: (handler, opts) => {
|
||||
t.ok(opts.serverFactory, 'it is called once for localhost')
|
||||
|
||||
const options = {
|
||||
key: global.context.key,
|
||||
cert: global.context.cert
|
||||
}
|
||||
|
||||
const server = https.createServer(options, (req, res) => {
|
||||
req.custom = true
|
||||
handler(req, res)
|
||||
})
|
||||
|
||||
return server
|
||||
}
|
||||
})
|
||||
|
||||
t.teardown(fastify.close.bind(fastify))
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.ok(req.raw.custom)
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.listen({ port: 0 })
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'https://localhost:' + fastify.server.address().port,
|
||||
rejectUnauthorized: false
|
||||
}, (err, response, body) => {
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(JSON.parse(body), { hello: 'world' })
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
setup()
|
||||
76
node_modules/fastify/test/https/https.test.js
generated
vendored
Normal file
76
node_modules/fastify/test/https/https.test.js
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const sget = require('simple-get').concat
|
||||
const Fastify = require('../..')
|
||||
|
||||
const { buildCertificate } = require('../build-certificate')
|
||||
t.before(buildCertificate)
|
||||
|
||||
test('https', (t) => {
|
||||
t.plan(4)
|
||||
|
||||
let fastify
|
||||
try {
|
||||
fastify = Fastify({
|
||||
https: {
|
||||
key: global.context.key,
|
||||
cert: global.context.cert
|
||||
}
|
||||
})
|
||||
t.pass('Key/cert successfully loaded')
|
||||
} catch (e) {
|
||||
t.fail('Key/cert loading failed', e)
|
||||
}
|
||||
|
||||
fastify.get('/', function (req, reply) {
|
||||
reply.code(200).send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.get('/proto', function (req, reply) {
|
||||
reply.code(200).send({ proto: req.protocol })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
t.test('https get request', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'https://localhost:' + fastify.server.address().port,
|
||||
rejectUnauthorized: false
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.equal(response.headers['content-length'], '' + body.length)
|
||||
t.same(JSON.parse(body), { hello: 'world' })
|
||||
})
|
||||
})
|
||||
|
||||
t.test('https get request without trust proxy - protocol', t => {
|
||||
t.plan(4)
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'https://localhost:' + fastify.server.address().port + '/proto',
|
||||
rejectUnauthorized: false
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(body), { proto: 'https' })
|
||||
})
|
||||
sget({
|
||||
method: 'GET',
|
||||
url: 'https://localhost:' + fastify.server.address().port + '/proto',
|
||||
rejectUnauthorized: false,
|
||||
headers: {
|
||||
'x-forwarded-proto': 'lorem'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.same(JSON.parse(body), { proto: 'https' })
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
18
node_modules/fastify/test/imports.test.js
generated
vendored
Normal file
18
node_modules/fastify/test/imports.test.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
|
||||
test('should import as default', t => {
|
||||
t.plan(2)
|
||||
const fastify = require('..')
|
||||
t.ok(fastify)
|
||||
t.equal(typeof fastify, 'function')
|
||||
})
|
||||
|
||||
test('should import as esm', t => {
|
||||
t.plan(2)
|
||||
const { fastify } = require('..')
|
||||
t.ok(fastify)
|
||||
t.equal(typeof fastify, 'function')
|
||||
})
|
||||
486
node_modules/fastify/test/inject.test.js
generated
vendored
Normal file
486
node_modules/fastify/test/inject.test.js
generated
vendored
Normal file
@@ -0,0 +1,486 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Stream = require('node:stream')
|
||||
const util = require('node:util')
|
||||
const Fastify = require('..')
|
||||
const FormData = require('form-data')
|
||||
const { Readable } = require('node:stream')
|
||||
|
||||
test('inject should exist', t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
t.ok(fastify.inject)
|
||||
t.equal(typeof fastify.inject, 'function')
|
||||
})
|
||||
|
||||
test('should wait for the ready event', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
const payload = { hello: 'world' }
|
||||
|
||||
fastify.register((instance, opts, done) => {
|
||||
instance.get('/', (req, reply) => {
|
||||
reply.send(payload)
|
||||
})
|
||||
|
||||
setTimeout(done, 500)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(payload, JSON.parse(res.payload))
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.headers['content-length'], '17')
|
||||
})
|
||||
})
|
||||
|
||||
test('inject get request', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
const payload = { hello: 'world' }
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send(payload)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(payload, JSON.parse(res.payload))
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.headers['content-length'], '17')
|
||||
})
|
||||
})
|
||||
|
||||
test('inject get request - code check', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
const payload = { hello: 'world' }
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.code(201).send(payload)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(payload, JSON.parse(res.payload))
|
||||
t.equal(res.statusCode, 201)
|
||||
t.equal(res.headers['content-length'], '17')
|
||||
})
|
||||
})
|
||||
|
||||
test('inject get request - headers check', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.header('content-type', 'text/plain').send('')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal('', res.payload)
|
||||
t.equal(res.headers['content-type'], 'text/plain')
|
||||
t.equal(res.headers['content-length'], '0')
|
||||
})
|
||||
})
|
||||
|
||||
test('inject get request - querystring', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send(req.query)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/?hello=world'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same({ hello: 'world' }, JSON.parse(res.payload))
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.headers['content-length'], '17')
|
||||
})
|
||||
})
|
||||
|
||||
test('inject get request - params', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/:hello', (req, reply) => {
|
||||
reply.send(req.params)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/world'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same({ hello: 'world' }, JSON.parse(res.payload))
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.headers['content-length'], '17')
|
||||
})
|
||||
})
|
||||
|
||||
test('inject get request - wildcard', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/test/*', (req, reply) => {
|
||||
reply.send(req.params)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/test/wildcard'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same({ '*': 'wildcard' }, JSON.parse(res.payload))
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.headers['content-length'], '16')
|
||||
})
|
||||
})
|
||||
|
||||
test('inject get request - headers', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send(req.headers)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
headers: { hello: 'world' }
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal('world', JSON.parse(res.payload).hello)
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.headers['content-length'], '69')
|
||||
})
|
||||
})
|
||||
|
||||
test('inject post request', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
const payload = { hello: 'world' }
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/',
|
||||
payload
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same(payload, JSON.parse(res.payload))
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.headers['content-length'], '17')
|
||||
})
|
||||
})
|
||||
|
||||
test('inject post request - send stream', t => {
|
||||
t.plan(4)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/',
|
||||
headers: { 'content-type': 'application/json' },
|
||||
payload: getStream()
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same('{"hello":"world"}', res.payload)
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.headers['content-length'], '17')
|
||||
})
|
||||
})
|
||||
|
||||
test('inject get request - reply stream', t => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send(getStream())
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.same('{"hello":"world"}', res.payload)
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
})
|
||||
|
||||
test('inject promisify - waiting for ready event', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
const payload = { hello: 'world' }
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send(payload)
|
||||
})
|
||||
|
||||
const injectParams = {
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}
|
||||
fastify.inject(injectParams)
|
||||
.then(res => {
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
.catch(t.fail)
|
||||
})
|
||||
|
||||
test('inject promisify - after the ready event', t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
const payload = { hello: 'world' }
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send(payload)
|
||||
})
|
||||
|
||||
fastify.ready(err => {
|
||||
t.error(err)
|
||||
|
||||
const injectParams = {
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}
|
||||
fastify.inject(injectParams)
|
||||
.then(res => {
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
.catch(t.fail)
|
||||
})
|
||||
})
|
||||
|
||||
test('inject promisify - when the server is up', t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
const payload = { hello: 'world' }
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send(payload)
|
||||
})
|
||||
|
||||
fastify.ready(err => {
|
||||
t.error(err)
|
||||
|
||||
// setTimeout because the ready event don't set "started" flag
|
||||
// in this iteration of the 'event loop'
|
||||
setTimeout(() => {
|
||||
const injectParams = {
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}
|
||||
fastify.inject(injectParams)
|
||||
.then(res => {
|
||||
t.equal(res.statusCode, 200)
|
||||
})
|
||||
.catch(t.fail)
|
||||
}, 10)
|
||||
})
|
||||
})
|
||||
|
||||
test('should reject in error case', t => {
|
||||
t.plan(1)
|
||||
const fastify = Fastify()
|
||||
|
||||
const error = new Error('DOOM!')
|
||||
fastify.register((instance, opts, done) => {
|
||||
setTimeout(done, 500, error)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
})
|
||||
.catch(e => {
|
||||
t.equal(e, error)
|
||||
})
|
||||
})
|
||||
|
||||
test('inject a multipart request using form-body', t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.addContentTypeParser('*', function (req, payload, done) {
|
||||
let body = ''
|
||||
payload.on('data', d => {
|
||||
body += d
|
||||
})
|
||||
payload.on('end', () => {
|
||||
done(null, body)
|
||||
})
|
||||
})
|
||||
fastify.post('/', (req, reply) => {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
const form = new FormData()
|
||||
form.append('my_field', 'my value')
|
||||
|
||||
fastify.inject({
|
||||
method: 'POST',
|
||||
url: '/',
|
||||
payload: form
|
||||
})
|
||||
.then(response => {
|
||||
t.equal(response.statusCode, 200)
|
||||
t.ok(/Content-Disposition: form-data; name="my_field"/.test(response.payload))
|
||||
})
|
||||
})
|
||||
|
||||
// https://github.com/hapijs/shot/blob/master/test/index.js#L836
|
||||
function getStream () {
|
||||
const Read = function () {
|
||||
Stream.Readable.call(this)
|
||||
}
|
||||
util.inherits(Read, Stream.Readable)
|
||||
const word = '{"hello":"world"}'
|
||||
let i = 0
|
||||
|
||||
Read.prototype._read = function (size) {
|
||||
this.push(word[i] ? word[i++] : null)
|
||||
}
|
||||
|
||||
return new Read()
|
||||
}
|
||||
|
||||
test('should error the promise if ready errors', t => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.register((instance, opts) => {
|
||||
return Promise.reject(new Error('kaboom'))
|
||||
}).after(function () {
|
||||
t.pass('after is called')
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}).then(() => {
|
||||
t.fail('this should not be called')
|
||||
}).catch(err => {
|
||||
t.ok(err)
|
||||
t.equal(err.message, 'kaboom')
|
||||
})
|
||||
})
|
||||
|
||||
test('should throw error if callback specified and if ready errors', t => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
const error = new Error('kaboom')
|
||||
|
||||
fastify.register((instance, opts) => {
|
||||
return Promise.reject(error)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, err => {
|
||||
t.ok(err)
|
||||
t.equal(err, error)
|
||||
})
|
||||
})
|
||||
|
||||
test('should support builder-style injection with ready app', async (t) => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify()
|
||||
const payload = { hello: 'world' }
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send(payload)
|
||||
})
|
||||
|
||||
await fastify.ready()
|
||||
const res = await fastify.inject().get('/').end()
|
||||
t.same(payload, JSON.parse(res.payload))
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.headers['content-length'], '17')
|
||||
})
|
||||
|
||||
test('should support builder-style injection with non-ready app', async (t) => {
|
||||
t.plan(3)
|
||||
const fastify = Fastify()
|
||||
const payload = { hello: 'world' }
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.send(payload)
|
||||
})
|
||||
|
||||
const res = await fastify.inject().get('/').end()
|
||||
t.same(payload, JSON.parse(res.payload))
|
||||
t.equal(res.statusCode, 200)
|
||||
t.equal(res.headers['content-length'], '17')
|
||||
})
|
||||
|
||||
test('should handle errors in builder-style injection correctly', async (t) => {
|
||||
t.plan(2)
|
||||
const fastify = Fastify()
|
||||
fastify.register((instance, opts, done) => {
|
||||
done(new Error('Kaboom'))
|
||||
})
|
||||
|
||||
try {
|
||||
await fastify.inject().get('/')
|
||||
} catch (err) {
|
||||
t.ok(err)
|
||||
t.equal(err.message, 'Kaboom')
|
||||
}
|
||||
})
|
||||
|
||||
test('Should not throw on access to routeConfig frameworkErrors handler - FST_ERR_BAD_URL', t => {
|
||||
t.plan(5)
|
||||
|
||||
const fastify = Fastify({
|
||||
frameworkErrors: function (err, req, res) {
|
||||
t.ok(typeof req.id === 'string')
|
||||
t.ok(req.raw instanceof Readable)
|
||||
t.same(req.routerPath, undefined)
|
||||
res.send(`${err.message} - ${err.code}`)
|
||||
}
|
||||
})
|
||||
|
||||
fastify.get('/test/:id', (req, res) => {
|
||||
res.send('{ hello: \'world\' }')
|
||||
})
|
||||
|
||||
fastify.inject(
|
||||
{
|
||||
method: 'GET',
|
||||
url: '/test/%world'
|
||||
},
|
||||
(err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.body, '\'/test/%world\' is not a valid url component - FST_ERR_BAD_URL')
|
||||
}
|
||||
)
|
||||
})
|
||||
336
node_modules/fastify/test/input-validation.js
generated
vendored
Normal file
336
node_modules/fastify/test/input-validation.js
generated
vendored
Normal file
@@ -0,0 +1,336 @@
|
||||
'use strict'
|
||||
|
||||
const sget = require('simple-get').concat
|
||||
const Ajv = require('ajv')
|
||||
const Joi = require('joi')
|
||||
const yup = require('yup')
|
||||
|
||||
module.exports.payloadMethod = function (method, t) {
|
||||
const test = t.test
|
||||
const fastify = require('..')()
|
||||
const upMethod = method.toUpperCase()
|
||||
const loMethod = method.toLowerCase()
|
||||
|
||||
const opts = {
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ajv = new Ajv({ coerceTypes: true, removeAdditional: true })
|
||||
const optsWithCustomValidator = {
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: {
|
||||
type: 'integer'
|
||||
}
|
||||
},
|
||||
additionalProperties: false
|
||||
}
|
||||
},
|
||||
validatorCompiler: function ({ schema, method, url, httpPart }) {
|
||||
return ajv.compile(schema)
|
||||
}
|
||||
}
|
||||
|
||||
const optsWithJoiValidator = {
|
||||
schema: {
|
||||
body: Joi.object().keys({
|
||||
hello: Joi.string().required()
|
||||
}).required()
|
||||
},
|
||||
validatorCompiler: function ({ schema, method, url, httpPart }) {
|
||||
return schema.validate.bind(schema)
|
||||
}
|
||||
}
|
||||
|
||||
const yupOptions = {
|
||||
strict: true, // don't coerce
|
||||
abortEarly: false, // return all errors
|
||||
stripUnknown: true, // remove additional properties
|
||||
recursive: true
|
||||
}
|
||||
|
||||
const optsWithYupValidator = {
|
||||
schema: {
|
||||
body: yup.object().shape({
|
||||
hello: yup.string().required()
|
||||
}).required()
|
||||
},
|
||||
validatorCompiler: function ({ schema, method, url, httpPart }) {
|
||||
return data => {
|
||||
try {
|
||||
const result = schema.validateSync(data, yupOptions)
|
||||
return { value: result }
|
||||
} catch (e) {
|
||||
return { error: [e] }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test(`${upMethod} can be created`, t => {
|
||||
t.plan(1)
|
||||
try {
|
||||
fastify[loMethod]('/', opts, function (req, reply) {
|
||||
reply.send(req.body)
|
||||
})
|
||||
fastify[loMethod]('/custom', optsWithCustomValidator, function (req, reply) {
|
||||
reply.send(req.body)
|
||||
})
|
||||
fastify[loMethod]('/joi', optsWithJoiValidator, function (req, reply) {
|
||||
reply.send(req.body)
|
||||
})
|
||||
fastify[loMethod]('/yup', optsWithYupValidator, function (req, reply) {
|
||||
reply.send(req.body)
|
||||
})
|
||||
|
||||
fastify.register(function (fastify2, opts, done) {
|
||||
fastify2.setValidatorCompiler(function schema ({ schema, method, url, httpPart }) {
|
||||
return body => ({ error: new Error('From custom schema compiler!') })
|
||||
})
|
||||
const withInstanceCustomCompiler = {
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
properties: { },
|
||||
additionalProperties: false
|
||||
}
|
||||
}
|
||||
}
|
||||
fastify2[loMethod]('/plugin', withInstanceCustomCompiler, (req, reply) => reply.send({ hello: 'never here!' }))
|
||||
|
||||
const optsWithCustomValidator2 = {
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
properties: { },
|
||||
additionalProperties: false
|
||||
}
|
||||
},
|
||||
validatorCompiler: function ({ schema, method, url, httpPart }) {
|
||||
return function (body) {
|
||||
return { error: new Error('Always fail!') }
|
||||
}
|
||||
}
|
||||
}
|
||||
fastify2[loMethod]('/plugin/custom', optsWithCustomValidator2, (req, reply) => reply.send({ hello: 'never here!' }))
|
||||
|
||||
done()
|
||||
})
|
||||
t.pass()
|
||||
} catch (e) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, function (err) {
|
||||
if (err) {
|
||||
t.error(err)
|
||||
}
|
||||
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
test(`${upMethod} - correctly replies`, t => {
|
||||
if (upMethod === 'HEAD') {
|
||||
t.plan(2)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port
|
||||
}, (err, response) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
} else {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
body: {
|
||||
hello: 42
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body, { hello: 42 })
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test(`${upMethod} - 400 on bad parameters`, t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
body: {
|
||||
hello: 'world'
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 400)
|
||||
t.same(body, {
|
||||
error: 'Bad Request',
|
||||
message: 'body/hello must be integer',
|
||||
statusCode: 400,
|
||||
code: 'FST_ERR_VALIDATION'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} - input-validation coerce`, t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
body: {
|
||||
hello: '42'
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body, { hello: 42 })
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} - input-validation custom schema compiler`, t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/custom',
|
||||
body: {
|
||||
hello: '42',
|
||||
world: 55
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body, { hello: 42 })
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} - input-validation joi schema compiler ok`, t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/joi',
|
||||
body: {
|
||||
hello: '42'
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body, { hello: 42 })
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} - input-validation joi schema compiler ko`, t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/joi',
|
||||
body: {
|
||||
hello: 44
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 400)
|
||||
t.same(body, {
|
||||
error: 'Bad Request',
|
||||
message: '"hello" must be a string',
|
||||
statusCode: 400,
|
||||
code: 'FST_ERR_VALIDATION'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} - input-validation yup schema compiler ok`, t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/yup',
|
||||
body: {
|
||||
hello: '42'
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 200)
|
||||
t.same(body, { hello: 42 })
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} - input-validation yup schema compiler ko`, t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/yup',
|
||||
body: {
|
||||
hello: 44
|
||||
},
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 400)
|
||||
t.match(body, {
|
||||
error: 'Bad Request',
|
||||
message: /body hello must be a `string` type, but the final value was: `44`./,
|
||||
statusCode: 400,
|
||||
code: 'FST_ERR_VALIDATION'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} - input-validation instance custom schema compiler encapsulated`, t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/plugin',
|
||||
body: { },
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 400)
|
||||
t.same(body, {
|
||||
error: 'Bad Request',
|
||||
message: 'From custom schema compiler!',
|
||||
statusCode: '400',
|
||||
code: 'FST_ERR_VALIDATION'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test(`${upMethod} - input-validation custom schema compiler encapsulated`, t => {
|
||||
t.plan(3)
|
||||
sget({
|
||||
method: upMethod,
|
||||
url: 'http://localhost:' + fastify.server.address().port + '/plugin/custom',
|
||||
body: { },
|
||||
json: true
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
t.equal(response.statusCode, 400)
|
||||
t.same(body, {
|
||||
error: 'Bad Request',
|
||||
message: 'Always fail!',
|
||||
statusCode: '400',
|
||||
code: 'FST_ERR_VALIDATION'
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
41
node_modules/fastify/test/internals/all.test.js
generated
vendored
Normal file
41
node_modules/fastify/test/internals/all.test.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('../..')
|
||||
const { supportedMethods } = require('../../lib/httpMethods')
|
||||
|
||||
test('fastify.all should add all the methods to the same url', t => {
|
||||
const requirePayload = [
|
||||
'POST',
|
||||
'PUT',
|
||||
'PATCH'
|
||||
]
|
||||
|
||||
t.plan(supportedMethods.length * 2)
|
||||
|
||||
const fastify = Fastify()
|
||||
|
||||
fastify.all('/', (req, reply) => {
|
||||
reply.send({ method: req.raw.method })
|
||||
})
|
||||
|
||||
supportedMethods.forEach(injectRequest)
|
||||
|
||||
function injectRequest (method) {
|
||||
const options = {
|
||||
url: '/',
|
||||
method
|
||||
}
|
||||
|
||||
if (requirePayload.includes(method)) {
|
||||
options.payload = { hello: 'world' }
|
||||
}
|
||||
|
||||
fastify.inject(options, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.same(payload, { method })
|
||||
})
|
||||
}
|
||||
})
|
||||
112
node_modules/fastify/test/internals/contentTypeParser.test.js
generated
vendored
Normal file
112
node_modules/fastify/test/internals/contentTypeParser.test.js
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const proxyquire = require('proxyquire')
|
||||
const test = t.test
|
||||
const { Readable } = require('node:stream')
|
||||
const { kTestInternals, kRouteContext } = require('../../lib/symbols')
|
||||
const Request = require('../../lib/request')
|
||||
const Reply = require('../../lib/reply')
|
||||
|
||||
test('rawBody function', t => {
|
||||
t.plan(2)
|
||||
|
||||
const internals = require('../../lib/contentTypeParser')[kTestInternals]
|
||||
const body = Buffer.from('你好 世界')
|
||||
const parser = {
|
||||
asString: true,
|
||||
asBuffer: false,
|
||||
fn (req, bodyInString, done) {
|
||||
t.equal(bodyInString, body.toString())
|
||||
t.equal(typeof done, 'function')
|
||||
return {
|
||||
then (cb) {
|
||||
cb()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const res = {}
|
||||
res.end = () => { }
|
||||
res.writeHead = () => { }
|
||||
|
||||
res.log = { error: () => { }, info: () => { } }
|
||||
const context = {
|
||||
Reply,
|
||||
Request,
|
||||
preHandler: [],
|
||||
onSend: [],
|
||||
_parserOptions: {
|
||||
limit: 1024
|
||||
}
|
||||
}
|
||||
const rs = new Readable()
|
||||
rs._read = function () { }
|
||||
rs.headers = { 'content-length': body.length }
|
||||
const request = new Request('id', 'params', rs, 'query', 'log', context)
|
||||
const reply = new Reply(res, request)
|
||||
const done = () => { }
|
||||
|
||||
internals.rawBody(
|
||||
request,
|
||||
reply,
|
||||
reply[kRouteContext]._parserOptions,
|
||||
parser,
|
||||
done
|
||||
)
|
||||
rs.emit('data', body.toString())
|
||||
rs.emit('end')
|
||||
})
|
||||
|
||||
test('Should support Webpack and faux modules', t => {
|
||||
t.plan(2)
|
||||
|
||||
const internals = proxyquire('../../lib/contentTypeParser', {
|
||||
'tiny-lru': { default: () => { } }
|
||||
})[kTestInternals]
|
||||
|
||||
const body = Buffer.from('你好 世界')
|
||||
const parser = {
|
||||
asString: true,
|
||||
asBuffer: false,
|
||||
fn (req, bodyInString, done) {
|
||||
t.equal(bodyInString, body.toString())
|
||||
t.equal(typeof done, 'function')
|
||||
return {
|
||||
then (cb) {
|
||||
cb()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const res = {}
|
||||
res.end = () => { }
|
||||
res.writeHead = () => { }
|
||||
|
||||
res.log = { error: () => { }, info: () => { } }
|
||||
const context = {
|
||||
Reply,
|
||||
Request,
|
||||
preHandler: [],
|
||||
onSend: [],
|
||||
_parserOptions: {
|
||||
limit: 1024
|
||||
}
|
||||
}
|
||||
const rs = new Readable()
|
||||
rs._read = function () { }
|
||||
rs.headers = { 'content-length': body.length }
|
||||
const request = new Request('id', 'params', rs, 'query', 'log', context)
|
||||
const reply = new Reply(res, request)
|
||||
const done = () => { }
|
||||
|
||||
internals.rawBody(
|
||||
request,
|
||||
reply,
|
||||
reply[kRouteContext]._parserOptions,
|
||||
parser,
|
||||
done
|
||||
)
|
||||
rs.emit('data', body.toString())
|
||||
rs.emit('end')
|
||||
})
|
||||
33
node_modules/fastify/test/internals/context.test.js
generated
vendored
Normal file
33
node_modules/fastify/test/internals/context.test.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
|
||||
const { kRouteContext } = require('../../lib/symbols')
|
||||
const Context = require('../../lib/context')
|
||||
|
||||
const Fastify = require('../..')
|
||||
|
||||
test('context', context => {
|
||||
context.plan(1)
|
||||
|
||||
context.test('Should not contain undefined as key prop', async t => {
|
||||
const app = Fastify()
|
||||
|
||||
app.get('/', (req, reply) => {
|
||||
t.type(req[kRouteContext], Context)
|
||||
t.type(reply[kRouteContext], Context)
|
||||
t.notOk('undefined' in reply[kRouteContext])
|
||||
t.notOk('undefined' in req[kRouteContext])
|
||||
|
||||
reply.send('hello world!')
|
||||
})
|
||||
|
||||
try {
|
||||
await app.inject('/')
|
||||
} catch (e) {
|
||||
t.fail(e)
|
||||
}
|
||||
|
||||
t.plan(4)
|
||||
})
|
||||
})
|
||||
159
node_modules/fastify/test/internals/decorator.test.js
generated
vendored
Normal file
159
node_modules/fastify/test/internals/decorator.test.js
generated
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
'use strict'
|
||||
|
||||
/* eslint no-prototype-builtins: 0 */
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const decorator = require('../../lib/decorate')
|
||||
const {
|
||||
kState
|
||||
} = require('../../lib/symbols')
|
||||
|
||||
test('decorate should add the given method to its instance', t => {
|
||||
t.plan(1)
|
||||
function build () {
|
||||
server.add = decorator.add
|
||||
server[kState] = {
|
||||
listening: false,
|
||||
closing: false,
|
||||
started: false
|
||||
}
|
||||
return server
|
||||
function server () {}
|
||||
}
|
||||
|
||||
const server = build()
|
||||
server.add('test', () => {})
|
||||
t.ok(server.test)
|
||||
})
|
||||
|
||||
test('decorate is chainable', t => {
|
||||
t.plan(3)
|
||||
function build () {
|
||||
server.add = decorator.add
|
||||
server[kState] = {
|
||||
listening: false,
|
||||
closing: false,
|
||||
started: false
|
||||
}
|
||||
return server
|
||||
function server () {}
|
||||
}
|
||||
|
||||
const server = build()
|
||||
server
|
||||
.add('test1', () => {})
|
||||
.add('test2', () => {})
|
||||
.add('test3', () => {})
|
||||
|
||||
t.ok(server.test1)
|
||||
t.ok(server.test2)
|
||||
t.ok(server.test3)
|
||||
})
|
||||
|
||||
test('checkExistence should check if a property is part of the given instance', t => {
|
||||
t.plan(1)
|
||||
const instance = { test: () => {} }
|
||||
t.ok(decorator.exist(instance, 'test'))
|
||||
})
|
||||
|
||||
test('checkExistence should find the instance if not given', t => {
|
||||
t.plan(1)
|
||||
function build () {
|
||||
server.add = decorator.add
|
||||
server.check = decorator.exist
|
||||
server[kState] = {
|
||||
listening: false,
|
||||
closing: false,
|
||||
started: false
|
||||
}
|
||||
return server
|
||||
function server () {}
|
||||
}
|
||||
|
||||
const server = build()
|
||||
server.add('test', () => {})
|
||||
t.ok(server.check('test'))
|
||||
})
|
||||
|
||||
test('checkExistence should check the prototype as well', t => {
|
||||
t.plan(1)
|
||||
function Instance () {}
|
||||
Instance.prototype.test = () => {}
|
||||
|
||||
const instance = new Instance()
|
||||
t.ok(decorator.exist(instance, 'test'))
|
||||
})
|
||||
|
||||
test('checkDependencies should throw if a dependency is not present', t => {
|
||||
t.plan(2)
|
||||
const instance = {}
|
||||
try {
|
||||
decorator.dependencies(instance, 'foo', ['test'])
|
||||
t.fail()
|
||||
} catch (e) {
|
||||
t.equal(e.code, 'FST_ERR_DEC_MISSING_DEPENDENCY')
|
||||
t.equal(e.message, 'The decorator is missing dependency \'test\'.')
|
||||
}
|
||||
})
|
||||
|
||||
test('decorate should internally call checkDependencies', t => {
|
||||
t.plan(2)
|
||||
function build () {
|
||||
server.add = decorator.add
|
||||
server[kState] = {
|
||||
listening: false,
|
||||
closing: false,
|
||||
started: false
|
||||
}
|
||||
return server
|
||||
function server () {}
|
||||
}
|
||||
|
||||
const server = build()
|
||||
|
||||
try {
|
||||
server.add('method', () => {}, ['test'])
|
||||
t.fail()
|
||||
} catch (e) {
|
||||
t.equal(e.code, 'FST_ERR_DEC_MISSING_DEPENDENCY')
|
||||
t.equal(e.message, 'The decorator is missing dependency \'test\'.')
|
||||
}
|
||||
})
|
||||
|
||||
test('decorate should recognize getter/setter objects', t => {
|
||||
t.plan(6)
|
||||
|
||||
const one = {
|
||||
[kState]: {
|
||||
listening: false,
|
||||
closing: false,
|
||||
started: false
|
||||
}
|
||||
}
|
||||
decorator.add.call(one, 'foo', {
|
||||
getter: () => this._a,
|
||||
setter: (val) => {
|
||||
t.pass()
|
||||
this._a = val
|
||||
}
|
||||
})
|
||||
t.equal(Object.prototype.hasOwnProperty.call(one, 'foo'), true)
|
||||
t.equal(one.foo, undefined)
|
||||
one.foo = 'a'
|
||||
t.equal(one.foo, 'a')
|
||||
|
||||
// getter only
|
||||
const two = {
|
||||
[kState]: {
|
||||
listening: false,
|
||||
closing: false,
|
||||
started: false
|
||||
}
|
||||
}
|
||||
decorator.add.call(two, 'foo', {
|
||||
getter: () => 'a getter'
|
||||
})
|
||||
t.equal(Object.prototype.hasOwnProperty.call(two, 'foo'), true)
|
||||
t.equal(two.foo, 'a getter')
|
||||
})
|
||||
888
node_modules/fastify/test/internals/errors.test.js
generated
vendored
Normal file
888
node_modules/fastify/test/internals/errors.test.js
generated
vendored
Normal file
@@ -0,0 +1,888 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const errors = require('../../lib/errors')
|
||||
const { readFileSync } = require('node:fs')
|
||||
const { resolve } = require('node:path')
|
||||
|
||||
test('should expose 80 errors', t => {
|
||||
t.plan(1)
|
||||
const exportedKeys = Object.keys(errors)
|
||||
let counter = 0
|
||||
for (const key of exportedKeys) {
|
||||
if (errors[key].name === 'FastifyError') {
|
||||
counter++
|
||||
}
|
||||
}
|
||||
t.equal(counter, 80)
|
||||
})
|
||||
|
||||
test('ensure name and codes of Errors are identical', t => {
|
||||
t.plan(80)
|
||||
const exportedKeys = Object.keys(errors)
|
||||
for (const key of exportedKeys) {
|
||||
if (errors[key].name === 'FastifyError') {
|
||||
t.equal(key, new errors[key]().code, key)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('FST_ERR_NOT_FOUND', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_NOT_FOUND()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_NOT_FOUND')
|
||||
t.equal(error.message, 'Not Found')
|
||||
t.equal(error.statusCode, 404)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_OPTIONS_NOT_OBJ', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_OPTIONS_NOT_OBJ()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_OPTIONS_NOT_OBJ')
|
||||
t.equal(error.message, 'Options must be an object')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_QSP_NOT_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_QSP_NOT_FN()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_QSP_NOT_FN')
|
||||
t.equal(error.message, "querystringParser option should be a function, instead got '%s'")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_SCHEMA_CONTROLLER_BUCKET_OPT_NOT_FN')
|
||||
t.equal(error.message, "schemaController.bucket option should be a function, instead got '%s'")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_SCHEMA_ERROR_FORMATTER_NOT_FN')
|
||||
t.equal(error.message, "schemaErrorFormatter option should be a non async function. Instead got '%s'.")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_OBJ')
|
||||
t.equal(error.message, "ajv.customOptions option should be an object, instead got '%s'")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_AJV_CUSTOM_OPTIONS_OPT_NOT_ARR')
|
||||
t.equal(error.message, "ajv.plugins option should be an array, instead got '%s'")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_VERSION_CONSTRAINT_NOT_STR', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_VERSION_CONSTRAINT_NOT_STR()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_VERSION_CONSTRAINT_NOT_STR')
|
||||
t.equal(error.message, 'Version constraint should be a string.')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_ALREADY_PRESENT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_ALREADY_PRESENT()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_CTP_ALREADY_PRESENT')
|
||||
t.equal(error.message, "Content type parser '%s' already present.")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_INVALID_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_INVALID_TYPE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_CTP_INVALID_TYPE')
|
||||
t.equal(error.message, 'The content type should be a string or a RegExp')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_EMPTY_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_EMPTY_TYPE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_CTP_EMPTY_TYPE')
|
||||
t.equal(error.message, 'The content type cannot be an empty string')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_INVALID_HANDLER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_INVALID_HANDLER()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_CTP_INVALID_HANDLER')
|
||||
t.equal(error.message, 'The content type handler should be a function')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_INVALID_PARSE_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_INVALID_PARSE_TYPE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_CTP_INVALID_PARSE_TYPE')
|
||||
t.equal(error.message, "The body parser can only parse your data as 'string' or 'buffer', you asked '%s' which is not supported.")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_BODY_TOO_LARGE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_BODY_TOO_LARGE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_CTP_BODY_TOO_LARGE')
|
||||
t.equal(error.message, 'Request body is too large')
|
||||
t.equal(error.statusCode, 413)
|
||||
t.ok(error instanceof RangeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_INVALID_MEDIA_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_INVALID_MEDIA_TYPE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_CTP_INVALID_MEDIA_TYPE')
|
||||
t.equal(error.message, 'Unsupported Media Type: %s')
|
||||
t.equal(error.statusCode, 415)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_INVALID_CONTENT_LENGTH', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_INVALID_CONTENT_LENGTH()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_CTP_INVALID_CONTENT_LENGTH')
|
||||
t.equal(error.message, 'Request body size did not match Content-Length')
|
||||
t.equal(error.statusCode, 400)
|
||||
t.ok(error instanceof RangeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_EMPTY_JSON_BODY', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_EMPTY_JSON_BODY()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_CTP_EMPTY_JSON_BODY')
|
||||
t.equal(error.message, "Body cannot be empty when content-type is set to 'application/json'")
|
||||
t.equal(error.statusCode, 400)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_CTP_INSTANCE_ALREADY_STARTED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_CTP_INSTANCE_ALREADY_STARTED()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_CTP_INSTANCE_ALREADY_STARTED')
|
||||
t.equal(error.message, 'Cannot call "%s" when fastify instance is already started!')
|
||||
t.equal(error.statusCode, 400)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_DEC_ALREADY_PRESENT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_DEC_ALREADY_PRESENT()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_DEC_ALREADY_PRESENT')
|
||||
t.equal(error.message, "The decorator '%s' has already been added!")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_DEC_DEPENDENCY_INVALID_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_DEC_DEPENDENCY_INVALID_TYPE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_DEC_DEPENDENCY_INVALID_TYPE')
|
||||
t.equal(error.message, "The dependencies of decorator '%s' must be of type Array.")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_DEC_MISSING_DEPENDENCY', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_DEC_MISSING_DEPENDENCY()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_DEC_MISSING_DEPENDENCY')
|
||||
t.equal(error.message, "The decorator is missing dependency '%s'.")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_DEC_AFTER_START', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_DEC_AFTER_START()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_DEC_AFTER_START')
|
||||
t.equal(error.message, "The decorator '%s' has been added after start!")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_HOOK_INVALID_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_HOOK_INVALID_TYPE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_HOOK_INVALID_TYPE')
|
||||
t.equal(error.message, 'The hook name must be a string')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_HOOK_INVALID_HANDLER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_HOOK_INVALID_HANDLER()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_HOOK_INVALID_HANDLER')
|
||||
t.equal(error.message, '%s hook should be a function, instead got %s')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_HOOK_INVALID_ASYNC_HANDLER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_HOOK_INVALID_ASYNC_HANDLER()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_HOOK_INVALID_ASYNC_HANDLER')
|
||||
t.equal(error.message, "Async function has too many arguments. Async hooks should not use the 'done' argument.")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_HOOK_NOT_SUPPORTED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_HOOK_NOT_SUPPORTED()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_HOOK_NOT_SUPPORTED')
|
||||
t.equal(error.message, '%s hook not supported!')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_MISSING_MIDDLEWARE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_MISSING_MIDDLEWARE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_MISSING_MIDDLEWARE')
|
||||
t.equal(error.message, 'You must register a plugin for handling middlewares, visit fastify.dev/docs/latest/Reference/Middleware/ for more info.')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_HOOK_TIMEOUT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_HOOK_TIMEOUT()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_HOOK_TIMEOUT')
|
||||
t.equal(error.message, "A callback for '%s' hook timed out. You may have forgotten to call 'done' function or to resolve a Promise")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_LOG_INVALID_DESTINATION', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_LOG_INVALID_DESTINATION()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_LOG_INVALID_DESTINATION')
|
||||
t.equal(error.message, 'Cannot specify both logger.stream and logger.file options')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_LOG_INVALID_LOGGER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_LOG_INVALID_LOGGER()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_LOG_INVALID_LOGGER')
|
||||
t.equal(error.message, "Invalid logger object provided. The logger instance should have these functions(s): '%s'.")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_REP_INVALID_PAYLOAD_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_REP_INVALID_PAYLOAD_TYPE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_REP_INVALID_PAYLOAD_TYPE')
|
||||
t.equal(error.message, "Attempted to send payload of invalid type '%s'. Expected a string or Buffer.")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_REP_RESPONSE_BODY_CONSUMED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_REP_RESPONSE_BODY_CONSUMED()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_REP_RESPONSE_BODY_CONSUMED')
|
||||
t.equal(error.message, 'Response.body is already consumed.')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_REP_ALREADY_SENT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_REP_ALREADY_SENT('/hello', 'GET')
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_REP_ALREADY_SENT')
|
||||
t.equal(error.message, 'Reply was already sent, did you forget to "return reply" in "/hello" (GET)?')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_REP_SENT_VALUE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_REP_SENT_VALUE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_REP_SENT_VALUE')
|
||||
t.equal(error.message, 'The only possible value for reply.sent is true.')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_SEND_INSIDE_ONERR', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SEND_INSIDE_ONERR()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_SEND_INSIDE_ONERR')
|
||||
t.equal(error.message, 'You cannot use `send` inside the `onError` hook')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SEND_UNDEFINED_ERR', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SEND_UNDEFINED_ERR()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_SEND_UNDEFINED_ERR')
|
||||
t.equal(error.message, 'Undefined error has occurred')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_BAD_STATUS_CODE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_BAD_STATUS_CODE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_BAD_STATUS_CODE')
|
||||
t.equal(error.message, 'Called reply with an invalid status code: %s')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_BAD_TRAILER_NAME', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_BAD_TRAILER_NAME()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_BAD_TRAILER_NAME')
|
||||
t.equal(error.message, 'Called reply.trailer with an invalid header name: %s')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_BAD_TRAILER_VALUE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_BAD_TRAILER_VALUE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_BAD_TRAILER_VALUE')
|
||||
t.equal(error.message, "Called reply.trailer('%s', fn) with an invalid type: %s. Expected a function.")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_FAILED_ERROR_SERIALIZATION', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_FAILED_ERROR_SERIALIZATION()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_FAILED_ERROR_SERIALIZATION')
|
||||
t.equal(error.message, 'Failed to serialize an error. Error: %s. Original error: %s')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_MISSING_SERIALIZATION_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_MISSING_SERIALIZATION_FN()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_MISSING_SERIALIZATION_FN')
|
||||
t.equal(error.message, 'Missing serialization function. Key "%s"')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN')
|
||||
t.equal(error.message, 'Missing serialization function. Key "%s:%s"')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_REQ_INVALID_VALIDATION_INVOCATION', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_REQ_INVALID_VALIDATION_INVOCATION()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_REQ_INVALID_VALIDATION_INVOCATION')
|
||||
t.equal(error.message, 'Invalid validation invocation. Missing validation function for HTTP part "%s" nor schema provided.')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCH_MISSING_ID', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCH_MISSING_ID()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_SCH_MISSING_ID')
|
||||
t.equal(error.message, 'Missing schema $id property')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCH_ALREADY_PRESENT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCH_ALREADY_PRESENT()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_SCH_ALREADY_PRESENT')
|
||||
t.equal(error.message, "Schema with id '%s' already declared!")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCH_CONTENT_MISSING_SCHEMA', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCH_CONTENT_MISSING_SCHEMA()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_SCH_CONTENT_MISSING_SCHEMA')
|
||||
t.equal(error.message, "Schema is missing for the content type '%s'")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCH_DUPLICATE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCH_DUPLICATE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_SCH_DUPLICATE')
|
||||
t.equal(error.message, "Schema with '%s' already present!")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCH_VALIDATION_BUILD', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCH_VALIDATION_BUILD()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_SCH_VALIDATION_BUILD')
|
||||
t.equal(error.message, 'Failed building the validation schema for %s: %s, due to error %s')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCH_SERIALIZATION_BUILD', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCH_SERIALIZATION_BUILD()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_SCH_SERIALIZATION_BUILD')
|
||||
t.equal(error.message, 'Failed building the serialization schema for %s: %s, due to error %s')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_SCH_RESPONSE_SCHEMA_NOT_NESTED_2XX')
|
||||
t.equal(error.message, 'response schemas should be nested under a valid status code, e.g { 2xx: { type: "object" } }')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_HTTP2_INVALID_VERSION', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_HTTP2_INVALID_VERSION()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_HTTP2_INVALID_VERSION')
|
||||
t.equal(error.message, 'HTTP2 is available only from node >= 8.8.1')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_INIT_OPTS_INVALID', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_INIT_OPTS_INVALID()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_INIT_OPTS_INVALID')
|
||||
t.equal(error.message, "Invalid initialization options: '%s'")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_FORCE_CLOSE_CONNECTIONS_IDLE_NOT_AVAILABLE')
|
||||
t.equal(error.message, "Cannot set forceCloseConnections to 'idle' as your HTTP server does not support closeIdleConnections method")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_DUPLICATED_ROUTE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_DUPLICATED_ROUTE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_DUPLICATED_ROUTE')
|
||||
t.equal(error.message, "Method '%s' already declared for route '%s'")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_BAD_URL', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_BAD_URL()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_BAD_URL')
|
||||
t.equal(error.message, "'%s' is not a valid url component")
|
||||
t.equal(error.statusCode, 400)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_ASYNC_CONSTRAINT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ASYNC_CONSTRAINT()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_ASYNC_CONSTRAINT')
|
||||
t.equal(error.message, 'Unexpected error from async constraint')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_DEFAULT_ROUTE_INVALID_TYPE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_DEFAULT_ROUTE_INVALID_TYPE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_DEFAULT_ROUTE_INVALID_TYPE')
|
||||
t.equal(error.message, 'The defaultRoute type should be a function')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_INVALID_URL', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_INVALID_URL()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_INVALID_URL')
|
||||
t.equal(error.message, "URL must be a string. Received '%s'")
|
||||
t.equal(error.statusCode, 400)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_OPTIONS_NOT_OBJ', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_OPTIONS_NOT_OBJ()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_ROUTE_OPTIONS_NOT_OBJ')
|
||||
t.equal(error.message, 'Options for "%s:%s" route must be an object')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_DUPLICATED_HANDLER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_DUPLICATED_HANDLER()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_ROUTE_DUPLICATED_HANDLER')
|
||||
t.equal(error.message, 'Duplicate handler for "%s:%s" route is not allowed!')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_HANDLER_NOT_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_HANDLER_NOT_FN()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_ROUTE_HANDLER_NOT_FN')
|
||||
t.equal(error.message, 'Error Handler for %s:%s route, if defined, must be a function')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_MISSING_HANDLER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_MISSING_HANDLER()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_ROUTE_MISSING_HANDLER')
|
||||
t.equal(error.message, 'Missing handler function for "%s:%s" route.')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_METHOD_INVALID', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_METHOD_INVALID()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_ROUTE_METHOD_INVALID')
|
||||
t.equal(error.message, 'Provided method is invalid!')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_METHOD_NOT_SUPPORTED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_METHOD_NOT_SUPPORTED()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_ROUTE_METHOD_NOT_SUPPORTED')
|
||||
t.equal(error.message, '%s method is not supported.')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_ROUTE_BODY_VALIDATION_SCHEMA_NOT_SUPPORTED')
|
||||
t.equal(error.message, 'Body validation schema for %s:%s route is not supported!')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT')
|
||||
t.equal(error.message, "'bodyLimit' option must be an integer > 0. Got '%s'")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_ROUTE_BODY_LIMIT_OPTION_NOT_INT')
|
||||
t.equal(error.message, "'bodyLimit' option must be an integer > 0. Got '%s'")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROUTE_REWRITE_NOT_STR', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROUTE_REWRITE_NOT_STR()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_ROUTE_REWRITE_NOT_STR')
|
||||
t.equal(error.message, 'Rewrite url for "%s" needs to be of type "string" but received "%s"')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_REOPENED_CLOSE_SERVER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_REOPENED_CLOSE_SERVER()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_REOPENED_CLOSE_SERVER')
|
||||
t.equal(error.message, 'Fastify has already been closed and cannot be reopened')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_REOPENED_SERVER', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_REOPENED_SERVER()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_REOPENED_SERVER')
|
||||
t.equal(error.message, 'Fastify is already listening')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_INSTANCE_ALREADY_LISTENING', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_INSTANCE_ALREADY_LISTENING()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_INSTANCE_ALREADY_LISTENING')
|
||||
t.equal(error.message, 'Fastify instance is already listening. %s')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_PLUGIN_VERSION_MISMATCH', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_PLUGIN_VERSION_MISMATCH()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_PLUGIN_VERSION_MISMATCH')
|
||||
t.equal(error.message, "fastify-plugin: %s - expected '%s' fastify version, '%s' is installed")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_PLUGIN_NOT_PRESENT_IN_INSTANCE')
|
||||
t.equal(error.message, "The decorator '%s'%s is not present in %s")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_PLUGIN_CALLBACK_NOT_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_PLUGIN_CALLBACK_NOT_FN()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_PLUGIN_CALLBACK_NOT_FN')
|
||||
t.equal(error.message, 'fastify-plugin: %s')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_PLUGIN_NOT_VALID', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_PLUGIN_NOT_VALID()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_PLUGIN_NOT_VALID')
|
||||
t.equal(error.message, 'fastify-plugin: %s')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_ROOT_PLG_BOOTED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ROOT_PLG_BOOTED()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_ROOT_PLG_BOOTED')
|
||||
t.equal(error.message, 'fastify-plugin: %s')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_PARENT_PLUGIN_BOOTED', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_PARENT_PLUGIN_BOOTED()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_PARENT_PLUGIN_BOOTED')
|
||||
t.equal(error.message, 'fastify-plugin: %s')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_PLUGIN_TIMEOUT', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_PLUGIN_TIMEOUT()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_PLUGIN_TIMEOUT')
|
||||
t.equal(error.message, 'fastify-plugin: %s')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_VALIDATION', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_VALIDATION()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_VALIDATION')
|
||||
t.equal(error.message, '%s')
|
||||
t.equal(error.statusCode, 400)
|
||||
t.ok(error instanceof Error)
|
||||
})
|
||||
|
||||
test('FST_ERR_LISTEN_OPTIONS_INVALID', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_LISTEN_OPTIONS_INVALID()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_LISTEN_OPTIONS_INVALID')
|
||||
t.equal(error.message, "Invalid listen options: '%s'")
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('FST_ERR_ERROR_HANDLER_NOT_FN', t => {
|
||||
t.plan(5)
|
||||
const error = new errors.FST_ERR_ERROR_HANDLER_NOT_FN()
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.code, 'FST_ERR_ERROR_HANDLER_NOT_FN')
|
||||
t.equal(error.message, 'Error Handler must be a function')
|
||||
t.equal(error.statusCode, 500)
|
||||
t.ok(error instanceof TypeError)
|
||||
})
|
||||
|
||||
test('Ensure that all errors are in Errors.md TOC', t => {
|
||||
t.plan(80)
|
||||
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')
|
||||
|
||||
const exportedKeys = Object.keys(errors)
|
||||
for (const key of exportedKeys) {
|
||||
if (errors[key].name === 'FastifyError') {
|
||||
t.ok(errorsMd.includes(` - [${key.toUpperCase()}](#${key.toLowerCase()})`), key)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('Ensure that non-existing errors are not in Errors.md TOC', t => {
|
||||
t.plan(80)
|
||||
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')
|
||||
|
||||
const matchRE = / {4}- \[([A-Z0-9_]+)\]\(#[a-z0-9_]+\)/g
|
||||
const matches = errorsMd.matchAll(matchRE)
|
||||
const exportedKeys = Object.keys(errors)
|
||||
|
||||
for (const match of matches) {
|
||||
t.ok(exportedKeys.indexOf(match[1]) !== -1, match[1])
|
||||
}
|
||||
})
|
||||
|
||||
test('Ensure that all errors are in Errors.md documented', t => {
|
||||
t.plan(80)
|
||||
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')
|
||||
|
||||
const exportedKeys = Object.keys(errors)
|
||||
for (const key of exportedKeys) {
|
||||
if (errors[key].name === 'FastifyError') {
|
||||
t.ok(errorsMd.includes(`<a id="${key.toLowerCase()}">${key.toUpperCase()}</a>`), key)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
test('Ensure that non-existing errors are not in Errors.md documented', t => {
|
||||
t.plan(80)
|
||||
const errorsMd = readFileSync(resolve(__dirname, '../../docs/Reference/Errors.md'), 'utf8')
|
||||
|
||||
const matchRE = /<a id="[0-9a-zA-Z_]+">([0-9a-zA-Z_]+)<\/a>/g
|
||||
const matches = errorsMd.matchAll(matchRE)
|
||||
const exportedKeys = Object.keys(errors)
|
||||
|
||||
for (const match of matches) {
|
||||
t.ok(exportedKeys.indexOf(match[1]) !== -1, match[1])
|
||||
}
|
||||
})
|
||||
248
node_modules/fastify/test/internals/handleRequest.test.js
generated
vendored
Normal file
248
node_modules/fastify/test/internals/handleRequest.test.js
generated
vendored
Normal file
@@ -0,0 +1,248 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const handleRequest = require('../../lib/handleRequest')
|
||||
const internals = require('../../lib/handleRequest')[Symbol.for('internals')]
|
||||
const Request = require('../../lib/request')
|
||||
const Reply = require('../../lib/reply')
|
||||
const { kRouteContext } = require('../../lib/symbols')
|
||||
const buildSchema = require('../../lib/validation').compileSchemasForValidation
|
||||
const sget = require('simple-get').concat
|
||||
|
||||
const Ajv = require('ajv')
|
||||
const ajv = new Ajv({ coerceTypes: true })
|
||||
|
||||
function schemaValidator ({ schema, method, url, httpPart }) {
|
||||
const validateFunction = ajv.compile(schema)
|
||||
const fn = function (body) {
|
||||
const isOk = validateFunction(body)
|
||||
if (isOk) return
|
||||
return false
|
||||
}
|
||||
fn.errors = []
|
||||
return fn
|
||||
}
|
||||
|
||||
test('handleRequest function - sent reply', t => {
|
||||
t.plan(1)
|
||||
const request = {}
|
||||
const reply = { sent: true }
|
||||
const res = handleRequest(null, request, reply)
|
||||
t.equal(res, undefined)
|
||||
})
|
||||
|
||||
test('handleRequest function - invoke with error', t => {
|
||||
t.plan(1)
|
||||
const request = {}
|
||||
const reply = {}
|
||||
reply.send = (err) => t.equal(err.message, 'Kaboom')
|
||||
handleRequest(new Error('Kaboom'), request, reply)
|
||||
})
|
||||
|
||||
test('handler function - invalid schema', t => {
|
||||
t.plan(1)
|
||||
const res = {}
|
||||
res.log = { error: () => {}, info: () => {} }
|
||||
const context = {
|
||||
config: {
|
||||
method: 'GET',
|
||||
url: '/an-url'
|
||||
},
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
hello: { type: 'number' }
|
||||
}
|
||||
}
|
||||
},
|
||||
errorHandler: { func: () => { t.pass('errorHandler called') } },
|
||||
handler: () => {},
|
||||
Reply,
|
||||
Request,
|
||||
preValidation: [],
|
||||
preHandler: [],
|
||||
onSend: [],
|
||||
onError: [],
|
||||
attachValidation: false,
|
||||
schemaErrorFormatter: () => new Error()
|
||||
}
|
||||
buildSchema(context, schemaValidator)
|
||||
const request = {
|
||||
body: { hello: 'world' },
|
||||
[kRouteContext]: context
|
||||
}
|
||||
internals.handler(request, new Reply(res, request))
|
||||
})
|
||||
|
||||
test('handler function - reply', t => {
|
||||
t.plan(3)
|
||||
const res = {}
|
||||
res.end = () => {
|
||||
t.equal(res.statusCode, 204)
|
||||
t.pass()
|
||||
}
|
||||
res.writeHead = () => {}
|
||||
const context = {
|
||||
handler: (req, reply) => {
|
||||
t.equal(typeof reply, 'object')
|
||||
reply.code(204)
|
||||
reply.send(undefined)
|
||||
},
|
||||
Reply,
|
||||
Request,
|
||||
preValidation: [],
|
||||
preHandler: [],
|
||||
onSend: [],
|
||||
onError: []
|
||||
}
|
||||
buildSchema(context, schemaValidator)
|
||||
internals.handler({ [kRouteContext]: context }, new Reply(res, { [kRouteContext]: context }))
|
||||
})
|
||||
|
||||
test('handler function - preValidationCallback with finished response', t => {
|
||||
t.plan(0)
|
||||
const res = {}
|
||||
// Be sure to check only `writableEnded` where is available
|
||||
res.writableEnded = true
|
||||
res.end = () => {
|
||||
t.fail()
|
||||
}
|
||||
res.writeHead = () => {}
|
||||
const context = {
|
||||
handler: (req, reply) => {
|
||||
t.fail()
|
||||
reply.send(undefined)
|
||||
},
|
||||
Reply,
|
||||
Request,
|
||||
preValidation: null,
|
||||
preHandler: [],
|
||||
onSend: [],
|
||||
onError: []
|
||||
}
|
||||
buildSchema(context, schemaValidator)
|
||||
internals.handler({ [kRouteContext]: context }, new Reply(res, { [kRouteContext]: context }))
|
||||
})
|
||||
|
||||
test('request should be defined in onSend Hook on post request with content type application/json', t => {
|
||||
t.plan(8)
|
||||
const fastify = require('../..')()
|
||||
|
||||
fastify.addHook('onSend', (request, reply, payload, done) => {
|
||||
t.ok(request)
|
||||
t.ok(request.raw)
|
||||
t.ok(request.id)
|
||||
t.ok(request.params)
|
||||
t.ok(request.query)
|
||||
done()
|
||||
})
|
||||
fastify.post('/', (request, reply) => {
|
||||
reply.send(200)
|
||||
})
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
// a 400 error is expected because of no body
|
||||
t.equal(response.statusCode, 400)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('request should be defined in onSend Hook on post request with content type application/x-www-form-urlencoded', t => {
|
||||
t.plan(7)
|
||||
const fastify = require('../..')()
|
||||
|
||||
fastify.addHook('onSend', (request, reply, payload, done) => {
|
||||
t.ok(request)
|
||||
t.ok(request.raw)
|
||||
t.ok(request.params)
|
||||
t.ok(request.query)
|
||||
done()
|
||||
})
|
||||
fastify.post('/', (request, reply) => {
|
||||
reply.send(200)
|
||||
})
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
sget({
|
||||
method: 'POST',
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
headers: {
|
||||
'content-type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
// a 415 error is expected because of missing content type parser
|
||||
t.equal(response.statusCode, 415)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('request should be defined in onSend Hook on options request with content type application/x-www-form-urlencoded', t => {
|
||||
t.plan(7)
|
||||
const fastify = require('../..')()
|
||||
|
||||
fastify.addHook('onSend', (request, reply, payload, done) => {
|
||||
t.ok(request)
|
||||
t.ok(request.raw)
|
||||
t.ok(request.params)
|
||||
t.ok(request.query)
|
||||
done()
|
||||
})
|
||||
fastify.options('/', (request, reply) => {
|
||||
reply.send(200)
|
||||
})
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
sget({
|
||||
method: 'OPTIONS',
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
headers: {
|
||||
'content-type': 'application/x-www-form-urlencoded'
|
||||
}
|
||||
}, (err, response, body) => {
|
||||
t.error(err)
|
||||
// Body parsing skipped, so no body sent
|
||||
t.equal(response.statusCode, 200)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('request should respond with an error if an unserialized payload is sent inside an async handler', t => {
|
||||
t.plan(3)
|
||||
|
||||
const fastify = require('../..')()
|
||||
|
||||
fastify.get('/', (request, reply) => {
|
||||
reply.type('text/html')
|
||||
return Promise.resolve(request.headers)
|
||||
})
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: '/'
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
t.equal(res.statusCode, 500)
|
||||
t.strictSame(JSON.parse(res.payload), {
|
||||
error: 'Internal Server Error',
|
||||
code: 'FST_ERR_REP_INVALID_PAYLOAD_TYPE',
|
||||
message: 'Attempted to send payload of invalid type \'object\'. Expected a string or Buffer.',
|
||||
statusCode: 500
|
||||
})
|
||||
})
|
||||
})
|
||||
450
node_modules/fastify/test/internals/hookRunner.test.js
generated
vendored
Normal file
450
node_modules/fastify/test/internals/hookRunner.test.js
generated
vendored
Normal file
@@ -0,0 +1,450 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const { hookRunnerGenerator, onSendHookRunner } = require('../../lib/hooks')
|
||||
|
||||
test('hookRunner - Basic', t => {
|
||||
t.plan(9)
|
||||
|
||||
const hookRunner = hookRunnerGenerator(iterator)
|
||||
|
||||
hookRunner([fn1, fn2, fn3], 'a', 'b', done)
|
||||
|
||||
function iterator (fn, a, b, done) {
|
||||
return fn(a, b, done)
|
||||
}
|
||||
|
||||
function fn1 (a, b, done) {
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
done()
|
||||
}
|
||||
|
||||
function fn2 (a, b, done) {
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
done()
|
||||
}
|
||||
|
||||
function fn3 (a, b, done) {
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
done()
|
||||
}
|
||||
|
||||
function done (err, a, b) {
|
||||
t.error(err)
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
}
|
||||
})
|
||||
|
||||
test('hookRunner - In case of error should skip to done', t => {
|
||||
t.plan(7)
|
||||
|
||||
const hookRunner = hookRunnerGenerator(iterator)
|
||||
|
||||
hookRunner([fn1, fn2, fn3], 'a', 'b', done)
|
||||
|
||||
function iterator (fn, a, b, done) {
|
||||
return fn(a, b, done)
|
||||
}
|
||||
|
||||
function fn1 (a, b, done) {
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
done()
|
||||
}
|
||||
|
||||
function fn2 (a, b, done) {
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
done(new Error('kaboom'))
|
||||
}
|
||||
|
||||
function fn3 () {
|
||||
t.fail('We should not be here')
|
||||
}
|
||||
|
||||
function done (err, a, b) {
|
||||
t.equal(err.message, 'kaboom')
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
}
|
||||
})
|
||||
|
||||
test('hookRunner - Should handle throw', t => {
|
||||
t.plan(7)
|
||||
|
||||
const hookRunner = hookRunnerGenerator(iterator)
|
||||
|
||||
hookRunner([fn1, fn2, fn3], 'a', 'b', done)
|
||||
|
||||
function iterator (fn, a, b, done) {
|
||||
return fn(a, b, done)
|
||||
}
|
||||
|
||||
function fn1 (a, b, done) {
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
done()
|
||||
}
|
||||
|
||||
function fn2 (a, b, done) {
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
throw new Error('kaboom')
|
||||
}
|
||||
|
||||
function fn3 () {
|
||||
t.fail('We should not be here')
|
||||
}
|
||||
|
||||
function done (err, a, b) {
|
||||
t.equal(err.message, 'kaboom')
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
}
|
||||
})
|
||||
|
||||
test('hookRunner - Should handle promises', t => {
|
||||
t.plan(9)
|
||||
|
||||
const hookRunner = hookRunnerGenerator(iterator)
|
||||
|
||||
hookRunner([fn1, fn2, fn3], 'a', 'b', done)
|
||||
|
||||
function iterator (fn, a, b, done) {
|
||||
return fn(a, b, done)
|
||||
}
|
||||
|
||||
function fn1 (a, b) {
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function fn2 (a, b) {
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function fn3 (a, b) {
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function done (err, a, b) {
|
||||
t.error(err)
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
}
|
||||
})
|
||||
|
||||
test('hookRunner - In case of error should skip to done (with promises)', t => {
|
||||
t.plan(7)
|
||||
|
||||
const hookRunner = hookRunnerGenerator(iterator)
|
||||
|
||||
hookRunner([fn1, fn2, fn3], 'a', 'b', done)
|
||||
|
||||
function iterator (fn, a, b, done) {
|
||||
return fn(a, b, done)
|
||||
}
|
||||
|
||||
function fn1 (a, b) {
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function fn2 (a, b) {
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
return Promise.reject(new Error('kaboom'))
|
||||
}
|
||||
|
||||
function fn3 () {
|
||||
t.fail('We should not be here')
|
||||
}
|
||||
|
||||
function done (err, a, b) {
|
||||
t.equal(err.message, 'kaboom')
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
}
|
||||
})
|
||||
|
||||
test('hookRunner - Be able to exit before its natural end', t => {
|
||||
t.plan(4)
|
||||
|
||||
const hookRunner = hookRunnerGenerator(iterator)
|
||||
|
||||
let shouldStop = false
|
||||
hookRunner([fn1, fn2, fn3], 'a', 'b', done)
|
||||
|
||||
function iterator (fn, a, b, done) {
|
||||
if (shouldStop) {
|
||||
return undefined
|
||||
}
|
||||
return fn(a, b, done)
|
||||
}
|
||||
|
||||
function fn1 (a, b, done) {
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
done()
|
||||
}
|
||||
|
||||
function fn2 (a, b) {
|
||||
t.equal(a, 'a')
|
||||
t.equal(b, 'b')
|
||||
shouldStop = true
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
function fn3 () {
|
||||
t.fail('this should not be called')
|
||||
}
|
||||
|
||||
function done () {
|
||||
t.fail('this should not be called')
|
||||
}
|
||||
})
|
||||
|
||||
test('hookRunner - Promises that resolve to a value do not change the state', t => {
|
||||
t.plan(5)
|
||||
|
||||
const originalState = { a: 'a', b: 'b' }
|
||||
|
||||
const hookRunner = hookRunnerGenerator(iterator)
|
||||
|
||||
hookRunner([fn1, fn2, fn3], originalState, 'b', done)
|
||||
|
||||
function iterator (fn, state, b, done) {
|
||||
return fn(state, b, done)
|
||||
}
|
||||
|
||||
function fn1 (state, b, done) {
|
||||
t.equal(state, originalState)
|
||||
return Promise.resolve(null)
|
||||
}
|
||||
|
||||
function fn2 (state, b, done) {
|
||||
t.equal(state, originalState)
|
||||
return Promise.resolve('string')
|
||||
}
|
||||
|
||||
function fn3 (state, b, done) {
|
||||
t.equal(state, originalState)
|
||||
return Promise.resolve({ object: true })
|
||||
}
|
||||
|
||||
function done (err, state, b) {
|
||||
t.error(err)
|
||||
t.equal(state, originalState)
|
||||
}
|
||||
})
|
||||
|
||||
test('onSendHookRunner - Basic', t => {
|
||||
t.plan(13)
|
||||
|
||||
const originalRequest = { body: null }
|
||||
const originalReply = { request: originalRequest }
|
||||
const originalPayload = 'payload'
|
||||
|
||||
onSendHookRunner([fn1, fn2, fn3], originalRequest, originalReply, originalPayload, done)
|
||||
|
||||
function fn1 (request, reply, payload, done) {
|
||||
t.same(request, originalRequest)
|
||||
t.same(reply, originalReply)
|
||||
t.equal(payload, originalPayload)
|
||||
done()
|
||||
}
|
||||
|
||||
function fn2 (request, reply, payload, done) {
|
||||
t.same(request, originalRequest)
|
||||
t.same(reply, originalReply)
|
||||
t.equal(payload, originalPayload)
|
||||
done()
|
||||
}
|
||||
|
||||
function fn3 (request, reply, payload, done) {
|
||||
t.same(request, originalRequest)
|
||||
t.same(reply, originalReply)
|
||||
t.equal(payload, originalPayload)
|
||||
done()
|
||||
}
|
||||
|
||||
function done (err, request, reply, payload) {
|
||||
t.error(err)
|
||||
t.same(request, originalRequest)
|
||||
t.same(reply, originalReply)
|
||||
t.equal(payload, originalPayload)
|
||||
}
|
||||
})
|
||||
|
||||
test('onSendHookRunner - Can change the payload', t => {
|
||||
t.plan(7)
|
||||
|
||||
const originalRequest = { body: null }
|
||||
const originalReply = { request: originalRequest }
|
||||
const v1 = { hello: 'world' }
|
||||
const v2 = { ciao: 'mondo' }
|
||||
const v3 = { winter: 'is coming' }
|
||||
const v4 = { winter: 'has come' }
|
||||
|
||||
onSendHookRunner([fn1, fn2, fn3], originalRequest, originalReply, v1, done)
|
||||
|
||||
function fn1 (request, reply, payload, done) {
|
||||
t.same(payload, v1)
|
||||
done(null, v2)
|
||||
}
|
||||
|
||||
function fn2 (request, reply, payload, done) {
|
||||
t.same(payload, v2)
|
||||
done(null, v3)
|
||||
}
|
||||
|
||||
function fn3 (request, reply, payload, done) {
|
||||
t.same(payload, v3)
|
||||
done(null, v4)
|
||||
}
|
||||
|
||||
function done (err, request, reply, payload) {
|
||||
t.error(err)
|
||||
t.same(request, originalRequest)
|
||||
t.same(reply, originalReply)
|
||||
t.same(payload, v4)
|
||||
}
|
||||
})
|
||||
|
||||
test('onSendHookRunner - In case of error should skip to done', t => {
|
||||
t.plan(6)
|
||||
|
||||
const originalRequest = { body: null }
|
||||
const originalReply = { request: originalRequest }
|
||||
const v1 = { hello: 'world' }
|
||||
const v2 = { ciao: 'mondo' }
|
||||
|
||||
onSendHookRunner([fn1, fn2, fn3], originalRequest, originalReply, v1, done)
|
||||
|
||||
function fn1 (request, reply, payload, done) {
|
||||
t.same(payload, v1)
|
||||
done(null, v2)
|
||||
}
|
||||
|
||||
function fn2 (request, reply, payload, done) {
|
||||
t.same(payload, v2)
|
||||
done(new Error('kaboom'))
|
||||
}
|
||||
|
||||
function fn3 () {
|
||||
t.fail('We should not be here')
|
||||
}
|
||||
|
||||
function done (err, request, reply, payload) {
|
||||
t.equal(err.message, 'kaboom')
|
||||
t.same(request, originalRequest)
|
||||
t.same(reply, originalReply)
|
||||
t.same(payload, v2)
|
||||
}
|
||||
})
|
||||
|
||||
test('onSendHookRunner - Should handle promises', t => {
|
||||
t.plan(7)
|
||||
|
||||
const originalRequest = { body: null }
|
||||
const originalReply = { request: originalRequest }
|
||||
const v1 = { hello: 'world' }
|
||||
const v2 = { ciao: 'mondo' }
|
||||
const v3 = { winter: 'is coming' }
|
||||
const v4 = { winter: 'has come' }
|
||||
|
||||
onSendHookRunner([fn1, fn2, fn3], originalRequest, originalReply, v1, done)
|
||||
|
||||
function fn1 (request, reply, payload) {
|
||||
t.same(payload, v1)
|
||||
return Promise.resolve(v2)
|
||||
}
|
||||
|
||||
function fn2 (request, reply, payload) {
|
||||
t.same(payload, v2)
|
||||
return Promise.resolve(v3)
|
||||
}
|
||||
|
||||
function fn3 (request, reply, payload) {
|
||||
t.same(payload, v3)
|
||||
return Promise.resolve(v4)
|
||||
}
|
||||
|
||||
function done (err, request, reply, payload) {
|
||||
t.error(err)
|
||||
t.same(request, originalRequest)
|
||||
t.same(reply, originalReply)
|
||||
t.same(payload, v4)
|
||||
}
|
||||
})
|
||||
|
||||
test('onSendHookRunner - In case of error should skip to done (with promises)', t => {
|
||||
t.plan(6)
|
||||
|
||||
const originalRequest = { body: null }
|
||||
const originalReply = { request: originalRequest }
|
||||
const v1 = { hello: 'world' }
|
||||
const v2 = { ciao: 'mondo' }
|
||||
|
||||
onSendHookRunner([fn1, fn2, fn3], originalRequest, originalReply, v1, done)
|
||||
|
||||
function fn1 (request, reply, payload) {
|
||||
t.same(payload, v1)
|
||||
return Promise.resolve(v2)
|
||||
}
|
||||
|
||||
function fn2 (request, reply, payload) {
|
||||
t.same(payload, v2)
|
||||
return Promise.reject(new Error('kaboom'))
|
||||
}
|
||||
|
||||
function fn3 () {
|
||||
t.fail('We should not be here')
|
||||
}
|
||||
|
||||
function done (err, request, reply, payload) {
|
||||
t.equal(err.message, 'kaboom')
|
||||
t.same(request, originalRequest)
|
||||
t.same(reply, originalReply)
|
||||
t.same(payload, v2)
|
||||
}
|
||||
})
|
||||
|
||||
test('onSendHookRunner - Be able to exit before its natural end', t => {
|
||||
t.plan(2)
|
||||
|
||||
const originalRequest = { body: null }
|
||||
const originalReply = { request: originalRequest }
|
||||
const v1 = { hello: 'world' }
|
||||
const v2 = { ciao: 'mondo' }
|
||||
|
||||
onSendHookRunner([fn1, fn2, fn3], originalRequest, originalReply, v1, done)
|
||||
|
||||
function fn1 (request, reply, payload, done) {
|
||||
t.same(payload, v1)
|
||||
done(null, v2)
|
||||
}
|
||||
|
||||
function fn2 (request, reply, payload) {
|
||||
t.same(payload, v2)
|
||||
}
|
||||
|
||||
function fn3 () {
|
||||
t.fail('this should not be called')
|
||||
}
|
||||
|
||||
function done () {
|
||||
t.fail('this should not be called')
|
||||
}
|
||||
})
|
||||
83
node_modules/fastify/test/internals/hooks.test.js
generated
vendored
Normal file
83
node_modules/fastify/test/internals/hooks.test.js
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
|
||||
const { Hooks } = require('../../lib/hooks')
|
||||
const noop = () => {}
|
||||
|
||||
test('hooks should have 4 array with the registered hooks', t => {
|
||||
const hooks = new Hooks()
|
||||
t.equal(typeof hooks, 'object')
|
||||
t.ok(Array.isArray(hooks.onRequest))
|
||||
t.ok(Array.isArray(hooks.onSend))
|
||||
t.ok(Array.isArray(hooks.preParsing))
|
||||
t.ok(Array.isArray(hooks.preValidation))
|
||||
t.ok(Array.isArray(hooks.preHandler))
|
||||
t.ok(Array.isArray(hooks.onResponse))
|
||||
t.ok(Array.isArray(hooks.onError))
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('hooks.add should add a hook to the given hook', t => {
|
||||
const hooks = new Hooks()
|
||||
hooks.add('onRequest', noop)
|
||||
t.equal(hooks.onRequest.length, 1)
|
||||
t.equal(typeof hooks.onRequest[0], 'function')
|
||||
|
||||
hooks.add('preParsing', noop)
|
||||
t.equal(hooks.preParsing.length, 1)
|
||||
t.equal(typeof hooks.preParsing[0], 'function')
|
||||
|
||||
hooks.add('preValidation', noop)
|
||||
t.equal(hooks.preValidation.length, 1)
|
||||
t.equal(typeof hooks.preValidation[0], 'function')
|
||||
|
||||
hooks.add('preHandler', noop)
|
||||
t.equal(hooks.preHandler.length, 1)
|
||||
t.equal(typeof hooks.preHandler[0], 'function')
|
||||
|
||||
hooks.add('onResponse', noop)
|
||||
t.equal(hooks.onResponse.length, 1)
|
||||
t.equal(typeof hooks.onResponse[0], 'function')
|
||||
|
||||
hooks.add('onSend', noop)
|
||||
t.equal(hooks.onSend.length, 1)
|
||||
t.equal(typeof hooks.onSend[0], 'function')
|
||||
|
||||
hooks.add('onError', noop)
|
||||
t.equal(hooks.onError.length, 1)
|
||||
t.equal(typeof hooks.onError[0], 'function')
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('hooks should throw on unexisting handler', t => {
|
||||
t.plan(1)
|
||||
const hooks = new Hooks()
|
||||
try {
|
||||
hooks.add('onUnexistingHook', noop)
|
||||
t.fail()
|
||||
} catch (e) {
|
||||
t.pass()
|
||||
}
|
||||
})
|
||||
|
||||
test('should throw on wrong parameters', t => {
|
||||
const hooks = new Hooks()
|
||||
t.plan(4)
|
||||
try {
|
||||
hooks.add(null, () => {})
|
||||
t.fail()
|
||||
} catch (e) {
|
||||
t.equal(e.code, 'FST_ERR_HOOK_INVALID_TYPE')
|
||||
t.equal(e.message, 'The hook name must be a string')
|
||||
}
|
||||
|
||||
try {
|
||||
hooks.add('onSend', null)
|
||||
t.fail()
|
||||
} catch (e) {
|
||||
t.equal(e.code, 'FST_ERR_HOOK_INVALID_HANDLER')
|
||||
t.equal(e.message, 'onSend hook should be a function, instead got [object Null]')
|
||||
}
|
||||
})
|
||||
400
node_modules/fastify/test/internals/initialConfig.test.js
generated
vendored
Normal file
400
node_modules/fastify/test/internals/initialConfig.test.js
generated
vendored
Normal file
@@ -0,0 +1,400 @@
|
||||
'use strict'
|
||||
|
||||
const { test, before } = require('tap')
|
||||
const Fastify = require('../..')
|
||||
const helper = require('../helper')
|
||||
const http = require('node:http')
|
||||
const pino = require('pino')
|
||||
const split = require('split2')
|
||||
const deepClone = require('rfdc')({ circles: true, proto: false })
|
||||
const { deepFreezeObject } = require('../../lib/initialConfigValidation').utils
|
||||
|
||||
const { buildCertificate } = require('../build-certificate')
|
||||
|
||||
process.removeAllListeners('warning')
|
||||
|
||||
let localhost
|
||||
let localhostForURL
|
||||
|
||||
before(async function () {
|
||||
await buildCertificate();
|
||||
[localhost, localhostForURL] = await helper.getLoopbackHost()
|
||||
})
|
||||
|
||||
test('Fastify.initialConfig is an object', t => {
|
||||
t.plan(1)
|
||||
t.type(Fastify().initialConfig, 'object')
|
||||
})
|
||||
|
||||
test('without options passed to Fastify, initialConfig should expose default values', t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastifyDefaultOptions = {
|
||||
connectionTimeout: 0,
|
||||
keepAliveTimeout: 72000,
|
||||
maxRequestsPerSocket: 0,
|
||||
requestTimeout: 0,
|
||||
bodyLimit: 1024 * 1024,
|
||||
caseSensitive: true,
|
||||
allowUnsafeRegex: false,
|
||||
disableRequestLogging: false,
|
||||
jsonShorthand: true,
|
||||
ignoreTrailingSlash: false,
|
||||
ignoreDuplicateSlashes: false,
|
||||
maxParamLength: 100,
|
||||
onProtoPoisoning: 'error',
|
||||
onConstructorPoisoning: 'error',
|
||||
pluginTimeout: 10000,
|
||||
requestIdHeader: 'request-id',
|
||||
requestIdLogLabel: 'reqId',
|
||||
http2SessionTimeout: 72000,
|
||||
exposeHeadRoutes: true,
|
||||
useSemicolonDelimiter: true
|
||||
}
|
||||
|
||||
t.same(Fastify().initialConfig, fastifyDefaultOptions)
|
||||
})
|
||||
|
||||
test('Fastify.initialConfig should expose all options', t => {
|
||||
t.plan(22)
|
||||
|
||||
const serverFactory = (handler, opts) => {
|
||||
const server = http.createServer((req, res) => {
|
||||
handler(req, res)
|
||||
})
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
const versionStrategy = {
|
||||
name: 'version',
|
||||
storage: function () {
|
||||
const versions = {}
|
||||
return {
|
||||
get: (version) => { return versions[version] || null },
|
||||
set: (version, store) => { versions[version] = store }
|
||||
}
|
||||
},
|
||||
deriveConstraint: (req, ctx) => {
|
||||
return req.headers.accept
|
||||
},
|
||||
validate () { return true }
|
||||
}
|
||||
|
||||
let reqId = 0
|
||||
const options = {
|
||||
http2: true,
|
||||
https: {
|
||||
key: global.context.key,
|
||||
cert: global.context.cert
|
||||
},
|
||||
ignoreTrailingSlash: true,
|
||||
ignoreDuplicateSlashes: true,
|
||||
maxParamLength: 200,
|
||||
connectionTimeout: 0,
|
||||
keepAliveTimeout: 72000,
|
||||
bodyLimit: 1049600,
|
||||
onProtoPoisoning: 'remove',
|
||||
serverFactory,
|
||||
caseSensitive: true,
|
||||
allowUnsafeRegex: false,
|
||||
requestIdHeader: 'request-id-alt',
|
||||
pluginTimeout: 20000,
|
||||
useSemicolonDelimiter: false,
|
||||
querystringParser: str => str,
|
||||
genReqId: function (req) {
|
||||
return reqId++
|
||||
},
|
||||
logger: pino({ level: 'info' }),
|
||||
constraints: {
|
||||
version: versionStrategy
|
||||
},
|
||||
trustProxy: function myTrustFn (address, hop) {
|
||||
return address === '1.2.3.4' || hop === 1
|
||||
}
|
||||
}
|
||||
|
||||
const fastify = Fastify(options)
|
||||
t.equal(fastify.initialConfig.http2, true)
|
||||
t.equal(fastify.initialConfig.https, true, 'for security reason the key cert is hidden')
|
||||
t.equal(fastify.initialConfig.ignoreTrailingSlash, true)
|
||||
t.equal(fastify.initialConfig.ignoreDuplicateSlashes, true)
|
||||
t.equal(fastify.initialConfig.maxParamLength, 200)
|
||||
t.equal(fastify.initialConfig.connectionTimeout, 0)
|
||||
t.equal(fastify.initialConfig.keepAliveTimeout, 72000)
|
||||
t.equal(fastify.initialConfig.bodyLimit, 1049600)
|
||||
t.equal(fastify.initialConfig.onProtoPoisoning, 'remove')
|
||||
t.equal(fastify.initialConfig.caseSensitive, true)
|
||||
t.equal(fastify.initialConfig.useSemicolonDelimiter, false)
|
||||
t.equal(fastify.initialConfig.allowUnsafeRegex, false)
|
||||
t.equal(fastify.initialConfig.requestIdHeader, 'request-id-alt')
|
||||
t.equal(fastify.initialConfig.pluginTimeout, 20000)
|
||||
t.ok(fastify.initialConfig.constraints.version)
|
||||
|
||||
// obfuscated options:
|
||||
t.equal(fastify.initialConfig.serverFactory, undefined)
|
||||
t.equal(fastify.initialConfig.trustProxy, undefined)
|
||||
t.equal(fastify.initialConfig.genReqId, undefined)
|
||||
t.equal(fastify.initialConfig.childLoggerFactory, undefined)
|
||||
t.equal(fastify.initialConfig.querystringParser, undefined)
|
||||
t.equal(fastify.initialConfig.logger, undefined)
|
||||
t.equal(fastify.initialConfig.trustProxy, undefined)
|
||||
})
|
||||
|
||||
test('Should throw if you try to modify Fastify.initialConfig', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify({ ignoreTrailingSlash: true })
|
||||
try {
|
||||
fastify.initialConfig.ignoreTrailingSlash = false
|
||||
t.fail()
|
||||
} catch (error) {
|
||||
t.type(error, TypeError)
|
||||
t.equal(error.message, "Cannot assign to read only property 'ignoreTrailingSlash' of object '#<Object>'")
|
||||
t.ok(error.stack)
|
||||
t.pass()
|
||||
}
|
||||
})
|
||||
|
||||
test('We must avoid shallow freezing and ensure that the whole object is freezed', t => {
|
||||
t.plan(4)
|
||||
|
||||
const fastify = Fastify({
|
||||
https: {
|
||||
allowHTTP1: true,
|
||||
key: global.context.key,
|
||||
cert: global.context.cert
|
||||
}
|
||||
})
|
||||
|
||||
try {
|
||||
fastify.initialConfig.https.allowHTTP1 = false
|
||||
t.fail()
|
||||
} catch (error) {
|
||||
t.type(error, TypeError)
|
||||
t.equal(error.message, "Cannot assign to read only property 'allowHTTP1' of object '#<Object>'")
|
||||
t.ok(error.stack)
|
||||
t.same(fastify.initialConfig.https, {
|
||||
allowHTTP1: true
|
||||
}, 'key cert removed')
|
||||
}
|
||||
})
|
||||
|
||||
test('https value check', t => {
|
||||
t.plan(1)
|
||||
|
||||
const fastify = Fastify({})
|
||||
t.notOk(fastify.initialConfig.https)
|
||||
})
|
||||
|
||||
test('Return an error if options do not match the validation schema', t => {
|
||||
t.plan(6)
|
||||
|
||||
try {
|
||||
Fastify({ ignoreTrailingSlash: 'string instead of boolean' })
|
||||
|
||||
t.fail()
|
||||
} catch (error) {
|
||||
t.type(error, Error)
|
||||
t.equal(error.name, 'FastifyError')
|
||||
t.equal(error.message, 'Invalid initialization options: \'["must be boolean"]\'')
|
||||
t.equal(error.code, 'FST_ERR_INIT_OPTS_INVALID')
|
||||
t.ok(error.stack)
|
||||
t.pass()
|
||||
}
|
||||
})
|
||||
|
||||
test('Original options must not be frozen', t => {
|
||||
t.plan(4)
|
||||
|
||||
const originalOptions = {
|
||||
https: {
|
||||
allowHTTP1: true,
|
||||
key: global.context.key,
|
||||
cert: global.context.cert
|
||||
}
|
||||
}
|
||||
|
||||
const fastify = Fastify(originalOptions)
|
||||
|
||||
t.equal(Object.isFrozen(originalOptions), false)
|
||||
t.equal(Object.isFrozen(originalOptions.https), false)
|
||||
t.equal(Object.isFrozen(fastify.initialConfig), true)
|
||||
t.equal(Object.isFrozen(fastify.initialConfig.https), true)
|
||||
})
|
||||
|
||||
test('Original options must not be altered (test deep cloning)', t => {
|
||||
t.plan(3)
|
||||
|
||||
const originalOptions = {
|
||||
https: {
|
||||
allowHTTP1: true,
|
||||
key: global.context.key,
|
||||
cert: global.context.cert
|
||||
}
|
||||
}
|
||||
|
||||
const originalOptionsClone = deepClone(originalOptions)
|
||||
|
||||
const fastify = Fastify(originalOptions)
|
||||
|
||||
// initialConfig has been triggered
|
||||
t.equal(Object.isFrozen(fastify.initialConfig), true)
|
||||
|
||||
// originalOptions must not have been altered
|
||||
t.same(originalOptions.https.key, originalOptionsClone.https.key)
|
||||
t.same(originalOptions.https.cert, originalOptionsClone.https.cert)
|
||||
})
|
||||
|
||||
test('Should not have issues when passing stream options to Pino.js', t => {
|
||||
t.plan(17)
|
||||
|
||||
const stream = split(JSON.parse)
|
||||
|
||||
const originalOptions = {
|
||||
ignoreTrailingSlash: true,
|
||||
logger: {
|
||||
level: 'trace',
|
||||
stream
|
||||
}
|
||||
}
|
||||
|
||||
let fastify
|
||||
|
||||
try {
|
||||
fastify = Fastify(originalOptions)
|
||||
fastify.setChildLoggerFactory(function (logger, bindings, opts) {
|
||||
bindings.someBinding = 'value'
|
||||
return logger.child(bindings, opts)
|
||||
})
|
||||
|
||||
t.type(fastify, 'object')
|
||||
t.same(fastify.initialConfig, {
|
||||
connectionTimeout: 0,
|
||||
keepAliveTimeout: 72000,
|
||||
maxRequestsPerSocket: 0,
|
||||
requestTimeout: 0,
|
||||
bodyLimit: 1024 * 1024,
|
||||
caseSensitive: true,
|
||||
allowUnsafeRegex: false,
|
||||
disableRequestLogging: false,
|
||||
jsonShorthand: true,
|
||||
ignoreTrailingSlash: true,
|
||||
ignoreDuplicateSlashes: false,
|
||||
maxParamLength: 100,
|
||||
onProtoPoisoning: 'error',
|
||||
onConstructorPoisoning: 'error',
|
||||
pluginTimeout: 10000,
|
||||
requestIdHeader: 'request-id',
|
||||
requestIdLogLabel: 'reqId',
|
||||
http2SessionTimeout: 72000,
|
||||
exposeHeadRoutes: true,
|
||||
useSemicolonDelimiter: true
|
||||
})
|
||||
} catch (error) {
|
||||
t.fail()
|
||||
}
|
||||
|
||||
fastify.get('/', function (req, reply) {
|
||||
t.ok(req.log)
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
stream.once('data', listenAtLogLine => {
|
||||
t.ok(listenAtLogLine, 'listen at log message is ok')
|
||||
|
||||
stream.once('data', line => {
|
||||
const id = line.reqId
|
||||
t.ok(line.reqId, 'reqId is defined')
|
||||
t.equal(line.someBinding, 'value', 'child logger binding is set')
|
||||
t.ok(line.req, 'req is defined')
|
||||
t.equal(line.msg, 'incoming request', 'message is set')
|
||||
t.equal(line.req.method, 'GET', 'method is get')
|
||||
|
||||
stream.once('data', line => {
|
||||
t.equal(line.reqId, id)
|
||||
t.ok(line.reqId, 'reqId is defined')
|
||||
t.equal(line.someBinding, 'value', 'child logger binding is set')
|
||||
t.ok(line.res, 'res is defined')
|
||||
t.equal(line.msg, 'request completed', 'message is set')
|
||||
t.equal(line.res.statusCode, 200, 'statusCode is 200')
|
||||
t.ok(line.responseTime, 'responseTime is defined')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0, host: localhost }, err => {
|
||||
t.error(err)
|
||||
t.teardown(() => { fastify.close() })
|
||||
|
||||
http.get(`http://${localhostForURL}:${fastify.server.address().port}`)
|
||||
})
|
||||
})
|
||||
|
||||
test('deepFreezeObject() should not throw on TypedArray', t => {
|
||||
t.plan(5)
|
||||
|
||||
const object = {
|
||||
buffer: Buffer.from(global.context.key),
|
||||
dataView: new DataView(new ArrayBuffer(16)),
|
||||
float: 1.1,
|
||||
integer: 1,
|
||||
object: {
|
||||
nested: { string: 'string' }
|
||||
},
|
||||
stream: split(JSON.parse),
|
||||
string: 'string'
|
||||
}
|
||||
|
||||
try {
|
||||
const frozenObject = deepFreezeObject(object)
|
||||
|
||||
// Buffers should not be frozen, as they are Uint8Array inherited instances
|
||||
t.equal(Object.isFrozen(frozenObject.buffer), false)
|
||||
|
||||
t.equal(Object.isFrozen(frozenObject), true)
|
||||
t.equal(Object.isFrozen(frozenObject.object), true)
|
||||
t.equal(Object.isFrozen(frozenObject.object.nested), true)
|
||||
|
||||
t.pass()
|
||||
} catch (error) {
|
||||
t.fail()
|
||||
}
|
||||
})
|
||||
|
||||
test('Fastify.initialConfig should accept the deprecated versioning option', t => {
|
||||
t.plan(1)
|
||||
|
||||
function onWarning (warning) {
|
||||
t.equal(warning.code, 'FSTDEP009')
|
||||
}
|
||||
|
||||
process.on('warning', onWarning)
|
||||
|
||||
const versioning = {
|
||||
storage: function () {
|
||||
const versions = {}
|
||||
return {
|
||||
get: (version) => { return versions[version] || null },
|
||||
set: (version, store) => { versions[version] = store }
|
||||
}
|
||||
},
|
||||
deriveVersion: (req, ctx) => {
|
||||
return req.headers.accept
|
||||
}
|
||||
}
|
||||
|
||||
Fastify({ versioning })
|
||||
setImmediate(function () {
|
||||
process.removeListener('warning', onWarning)
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
test('pluginTimeout should be parsed correctly', t => {
|
||||
const withDisabledTimeout = Fastify({ pluginTimeout: '0' })
|
||||
t.equal(withDisabledTimeout.initialConfig.pluginTimeout, 0)
|
||||
const withInvalidTimeout = Fastify({ pluginTimeout: undefined })
|
||||
t.equal(withInvalidTimeout.initialConfig.pluginTimeout, 10000)
|
||||
t.end()
|
||||
})
|
||||
134
node_modules/fastify/test/internals/logger.test.js
generated
vendored
Normal file
134
node_modules/fastify/test/internals/logger.test.js
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
const Fastify = require('../..')
|
||||
const loggerUtils = require('../../lib/logger')
|
||||
|
||||
test('time resolution', t => {
|
||||
t.plan(2)
|
||||
t.equal(typeof loggerUtils.now, 'function')
|
||||
t.equal(typeof loggerUtils.now(), 'number')
|
||||
})
|
||||
|
||||
test('The logger should add a unique id for every request', t => {
|
||||
const ids = []
|
||||
|
||||
const fastify = Fastify()
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
const queue = new Queue()
|
||||
for (let i = 0; i < 10; i++) {
|
||||
queue.add(checkId)
|
||||
}
|
||||
queue.add(() => {
|
||||
fastify.close()
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
|
||||
function checkId (done) {
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.ok(ids.indexOf(payload.id) === -1, 'the id should not be duplicated')
|
||||
ids.push(payload.id)
|
||||
done()
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
test('The logger should reuse request id header for req.id', t => {
|
||||
const fastify = Fastify()
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.ok(req.id)
|
||||
reply.send({ id: req.id })
|
||||
})
|
||||
|
||||
fastify.listen({ port: 0 }, err => {
|
||||
t.error(err)
|
||||
|
||||
fastify.inject({
|
||||
method: 'GET',
|
||||
url: 'http://localhost:' + fastify.server.address().port,
|
||||
headers: {
|
||||
'Request-Id': 'request-id-1'
|
||||
}
|
||||
}, (err, res) => {
|
||||
t.error(err)
|
||||
const payload = JSON.parse(res.payload)
|
||||
t.ok(payload.id === 'request-id-1', 'the request id from the header should be returned')
|
||||
fastify.close()
|
||||
t.end()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
function Queue () {
|
||||
this.q = []
|
||||
this.running = false
|
||||
}
|
||||
|
||||
Queue.prototype.add = function add (job) {
|
||||
this.q.push(job)
|
||||
if (!this.running) this.run()
|
||||
}
|
||||
|
||||
Queue.prototype.run = function run () {
|
||||
this.running = true
|
||||
const job = this.q.shift()
|
||||
job(() => {
|
||||
if (this.q.length) {
|
||||
this.run()
|
||||
} else {
|
||||
this.running = false
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
test('The logger should error if both stream and file destination are given', t => {
|
||||
t.plan(2)
|
||||
|
||||
const stream = require('node:stream').Writable
|
||||
|
||||
try {
|
||||
Fastify({
|
||||
logger: {
|
||||
level: 'info',
|
||||
stream,
|
||||
file: '/test'
|
||||
}
|
||||
})
|
||||
} catch (err) {
|
||||
t.equal(err.code, 'FST_ERR_LOG_INVALID_DESTINATION')
|
||||
t.equal(err.message, 'Cannot specify both logger.stream and logger.file options')
|
||||
}
|
||||
})
|
||||
|
||||
test('The serializer prevent fails if the request socket is undefined', t => {
|
||||
t.plan(1)
|
||||
|
||||
const serialized = loggerUtils.serializers.req({
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: undefined,
|
||||
headers: {}
|
||||
})
|
||||
|
||||
t.same(serialized, {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
version: undefined,
|
||||
hostname: undefined,
|
||||
remoteAddress: undefined,
|
||||
remotePort: undefined
|
||||
})
|
||||
})
|
||||
171
node_modules/fastify/test/internals/plugin.test.js
generated
vendored
Normal file
171
node_modules/fastify/test/internals/plugin.test.js
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
'use strict'
|
||||
|
||||
const t = require('tap')
|
||||
const test = t.test
|
||||
|
||||
const pluginUtilsPublic = require('../../lib/pluginUtils.js')
|
||||
const symbols = require('../../lib/symbols.js')
|
||||
const pluginUtils = require('../../lib/pluginUtils')[symbols.kTestInternals]
|
||||
|
||||
test("shouldSkipOverride should check the 'skip-override' symbol", t => {
|
||||
t.plan(2)
|
||||
|
||||
yes[Symbol.for('skip-override')] = true
|
||||
|
||||
t.ok(pluginUtils.shouldSkipOverride(yes))
|
||||
t.notOk(pluginUtils.shouldSkipOverride(no))
|
||||
|
||||
function yes () {}
|
||||
function no () {}
|
||||
})
|
||||
|
||||
test('getPluginName should return plugin name if the file is cached', t => {
|
||||
t.plan(1)
|
||||
const expectedPluginName = 'example'
|
||||
const fn = () => console.log('is just an example')
|
||||
require.cache[expectedPluginName] = { exports: fn }
|
||||
const pluginName = pluginUtilsPublic.getPluginName(fn)
|
||||
|
||||
t.equal(pluginName, expectedPluginName)
|
||||
})
|
||||
|
||||
test('getPluginName should not throw when require.cache is undefined', t => {
|
||||
t.plan(1)
|
||||
function example () {
|
||||
console.log('is just an example')
|
||||
}
|
||||
const cache = require.cache
|
||||
require.cache = undefined
|
||||
t.teardown(() => {
|
||||
require.cache = cache
|
||||
})
|
||||
const pluginName = pluginUtilsPublic.getPluginName(example)
|
||||
|
||||
t.equal(pluginName, 'example')
|
||||
})
|
||||
|
||||
test("getMeta should return the object stored with the 'plugin-meta' symbol", t => {
|
||||
t.plan(1)
|
||||
|
||||
const meta = { hello: 'world' }
|
||||
fn[Symbol.for('plugin-meta')] = meta
|
||||
|
||||
t.same(meta, pluginUtils.getMeta(fn))
|
||||
|
||||
function fn () {}
|
||||
})
|
||||
|
||||
test('checkDecorators should check if the given decorator is present in the instance', t => {
|
||||
t.plan(1)
|
||||
|
||||
fn[Symbol.for('plugin-meta')] = {
|
||||
decorators: {
|
||||
fastify: ['plugin'],
|
||||
reply: ['plugin'],
|
||||
request: ['plugin']
|
||||
}
|
||||
}
|
||||
|
||||
function context () {}
|
||||
context.plugin = true
|
||||
context[symbols.kReply] = { prototype: { plugin: true }, props: [] }
|
||||
context[symbols.kRequest] = { prototype: { plugin: true }, props: [] }
|
||||
|
||||
try {
|
||||
pluginUtils.checkDecorators.call(context, fn)
|
||||
t.pass('Everything ok')
|
||||
} catch (err) {
|
||||
t.fail(err)
|
||||
}
|
||||
|
||||
function fn () {}
|
||||
})
|
||||
|
||||
test('checkDecorators should check if the given decorator is present in the instance (errored)', t => {
|
||||
t.plan(1)
|
||||
|
||||
fn[Symbol.for('plugin-meta')] = {
|
||||
decorators: {
|
||||
fastify: ['plugin'],
|
||||
reply: ['plugin'],
|
||||
request: ['plugin']
|
||||
}
|
||||
}
|
||||
|
||||
function context () {}
|
||||
context.plugin = true
|
||||
context[symbols.kReply] = { prototype: { plugin: true }, props: [] }
|
||||
context[symbols.kRequest] = { prototype: {}, props: [] }
|
||||
|
||||
try {
|
||||
pluginUtils.checkDecorators.call(context, fn)
|
||||
t.fail('should throw')
|
||||
} catch (err) {
|
||||
t.equal(err.message, "The decorator 'plugin' is not present in Request")
|
||||
}
|
||||
|
||||
function fn () {}
|
||||
})
|
||||
|
||||
test('checkDecorators should accept optional decorators', t => {
|
||||
t.plan(1)
|
||||
|
||||
fn[Symbol.for('plugin-meta')] = {
|
||||
decorators: { }
|
||||
}
|
||||
|
||||
function context () {}
|
||||
context.plugin = true
|
||||
context[symbols.kReply] = { prototype: { plugin: true } }
|
||||
context[symbols.kRequest] = { prototype: { plugin: true } }
|
||||
|
||||
try {
|
||||
pluginUtils.checkDecorators.call(context, fn)
|
||||
t.pass('Everything ok')
|
||||
} catch (err) {
|
||||
t.fail(err)
|
||||
}
|
||||
|
||||
function fn () {}
|
||||
})
|
||||
|
||||
test('checkDependencies should check if the given dependency is present in the instance', t => {
|
||||
t.plan(1)
|
||||
|
||||
fn[Symbol.for('plugin-meta')] = {
|
||||
dependencies: ['plugin']
|
||||
}
|
||||
|
||||
function context () {}
|
||||
context[pluginUtilsPublic.kRegisteredPlugins] = ['plugin']
|
||||
|
||||
try {
|
||||
pluginUtils.checkDependencies.call(context, fn)
|
||||
t.pass('Everything ok')
|
||||
} catch (err) {
|
||||
t.fail(err)
|
||||
}
|
||||
|
||||
function fn () {}
|
||||
})
|
||||
|
||||
test('checkDependencies should check if the given dependency is present in the instance (errored)', t => {
|
||||
t.plan(1)
|
||||
|
||||
fn[Symbol.for('plugin-meta')] = {
|
||||
name: 'test-plugin',
|
||||
dependencies: ['plugin']
|
||||
}
|
||||
|
||||
function context () {}
|
||||
context[pluginUtilsPublic.kRegisteredPlugins] = []
|
||||
|
||||
try {
|
||||
pluginUtils.checkDependencies.call(context, fn)
|
||||
t.fail('should throw')
|
||||
} catch (err) {
|
||||
t.equal(err.message, "The dependency 'plugin' of plugin 'test-plugin' is not registered")
|
||||
}
|
||||
|
||||
function fn () {}
|
||||
})
|
||||
699
node_modules/fastify/test/internals/reply-serialize.test.js
generated
vendored
Normal file
699
node_modules/fastify/test/internals/reply-serialize.test.js
generated
vendored
Normal file
@@ -0,0 +1,699 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const { kReplyCacheSerializeFns, kRouteContext } = require('../../lib/symbols')
|
||||
const Fastify = require('../../fastify')
|
||||
|
||||
function getDefaultSchema () {
|
||||
return {
|
||||
type: 'object',
|
||||
required: ['hello'],
|
||||
properties: {
|
||||
hello: { type: 'string' },
|
||||
world: { type: 'string' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getResponseSchema () {
|
||||
return {
|
||||
201: {
|
||||
type: 'object',
|
||||
required: ['status'],
|
||||
properties: {
|
||||
status: {
|
||||
type: 'string',
|
||||
enum: ['ok']
|
||||
},
|
||||
message: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
'4xx': {
|
||||
type: 'object',
|
||||
properties: {
|
||||
status: {
|
||||
type: 'string',
|
||||
enum: ['error']
|
||||
},
|
||||
code: {
|
||||
type: 'integer',
|
||||
minimum: 1
|
||||
},
|
||||
message: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
},
|
||||
'3xx': {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
fullName: { type: 'string' },
|
||||
phone: { type: 'number' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test('Reply#compileSerializationSchema', t => {
|
||||
t.plan(4)
|
||||
|
||||
t.test('Should return a serialization function', async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
t.plan(4)
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
const serialize = reply.compileSerializationSchema(getDefaultSchema())
|
||||
const input = { hello: 'world' }
|
||||
t.type(serialize, Function)
|
||||
t.type(serialize(input), 'string')
|
||||
t.equal(serialize(input), JSON.stringify(input))
|
||||
|
||||
try {
|
||||
serialize({ world: 'foo' })
|
||||
} catch (err) {
|
||||
t.equal(err.message, '"hello" is required!')
|
||||
}
|
||||
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
})
|
||||
|
||||
t.test('Should reuse the serialize fn across multiple invocations - Route without schema',
|
||||
async t => {
|
||||
const fastify = Fastify()
|
||||
let serialize = null
|
||||
let counter = 0
|
||||
|
||||
t.plan(17)
|
||||
|
||||
const schemaObj = getDefaultSchema()
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
const input = { hello: 'world' }
|
||||
counter++
|
||||
if (counter > 1) {
|
||||
const newSerialize = reply.compileSerializationSchema(schemaObj)
|
||||
t.equal(serialize, newSerialize, 'Are the same validate function')
|
||||
serialize = newSerialize
|
||||
} else {
|
||||
t.pass('build the schema compilation function')
|
||||
serialize = reply.compileSerializationSchema(schemaObj)
|
||||
}
|
||||
|
||||
t.type(serialize, Function)
|
||||
t.equal(serialize(input), JSON.stringify(input))
|
||||
|
||||
try {
|
||||
serialize({ world: 'foo' })
|
||||
} catch (err) {
|
||||
t.equal(err.message, '"hello" is required!')
|
||||
}
|
||||
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
fastify.inject('/'),
|
||||
fastify.inject('/'),
|
||||
fastify.inject('/'),
|
||||
fastify.inject('/')
|
||||
])
|
||||
|
||||
t.equal(counter, 4)
|
||||
}
|
||||
)
|
||||
|
||||
t.test('Should use the custom serializer compiler for the route',
|
||||
async t => {
|
||||
const fastify = Fastify()
|
||||
let called = 0
|
||||
const custom = ({ schema, httpStatus, url, method }) => {
|
||||
t.equal(schema, schemaObj)
|
||||
t.equal(url, '/')
|
||||
t.equal(method, 'GET')
|
||||
t.equal(httpStatus, '201')
|
||||
|
||||
return input => {
|
||||
called++
|
||||
t.same(input, { hello: 'world' })
|
||||
return JSON.stringify(input)
|
||||
}
|
||||
}
|
||||
|
||||
const custom2 = ({ schema, httpStatus, url, method, contentType }) => {
|
||||
t.equal(schema, schemaObj)
|
||||
t.equal(url, '/user')
|
||||
t.equal(method, 'GET')
|
||||
t.equal(httpStatus, '3xx')
|
||||
t.equal(contentType, 'application/json')
|
||||
|
||||
return input => {
|
||||
t.same(input, { fullName: 'Jone', phone: 1090243795 })
|
||||
return JSON.stringify(input)
|
||||
}
|
||||
}
|
||||
|
||||
t.plan(17)
|
||||
const schemaObj = getDefaultSchema()
|
||||
|
||||
fastify.get('/', { serializerCompiler: custom }, (req, reply) => {
|
||||
const input = { hello: 'world' }
|
||||
const first = reply.compileSerializationSchema(schemaObj, '201')
|
||||
const second = reply.compileSerializationSchema(schemaObj, '201')
|
||||
|
||||
t.equal(first, second)
|
||||
t.ok(first(input), JSON.stringify(input))
|
||||
t.ok(second(input), JSON.stringify(input))
|
||||
t.equal(called, 2)
|
||||
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
fastify.get('/user', { serializerCompiler: custom2 }, (req, reply) => {
|
||||
const input = { fullName: 'Jone', phone: 1090243795 }
|
||||
const first = reply.compileSerializationSchema(schemaObj, '3xx', 'application/json')
|
||||
t.ok(first(input), JSON.stringify(input))
|
||||
reply.send(input)
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/user',
|
||||
method: 'GET'
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
t.test('Should build a WeakMap for cache when called', async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
t.plan(4)
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
const input = { hello: 'world' }
|
||||
|
||||
t.equal(reply[kRouteContext][kReplyCacheSerializeFns], null)
|
||||
t.equal(reply.compileSerializationSchema(getDefaultSchema())(input), JSON.stringify(input))
|
||||
t.type(reply[kRouteContext][kReplyCacheSerializeFns], WeakMap)
|
||||
t.equal(reply.compileSerializationSchema(getDefaultSchema())(input), JSON.stringify(input))
|
||||
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Reply#getSerializationFunction', t => {
|
||||
t.plan(3)
|
||||
|
||||
t.test('Should retrieve the serialization function from the Schema definition',
|
||||
async t => {
|
||||
const fastify = Fastify()
|
||||
const okInput201 = {
|
||||
status: 'ok',
|
||||
message: 'done!'
|
||||
}
|
||||
const notOkInput201 = {
|
||||
message: 'created'
|
||||
}
|
||||
const okInput4xx = {
|
||||
status: 'error',
|
||||
code: 2,
|
||||
message: 'oops!'
|
||||
}
|
||||
const notOkInput4xx = {
|
||||
status: 'error',
|
||||
code: 'something'
|
||||
}
|
||||
const okInput3xx = {
|
||||
fullName: 'Jone',
|
||||
phone: 0
|
||||
}
|
||||
const noOkInput3xx = {
|
||||
fullName: 'Jone',
|
||||
phone: 'phone'
|
||||
}
|
||||
let cached4xx
|
||||
let cached201
|
||||
let cachedJson3xx
|
||||
|
||||
t.plan(13)
|
||||
|
||||
const responseSchema = getResponseSchema()
|
||||
|
||||
fastify.get(
|
||||
'/:id',
|
||||
{
|
||||
params: {
|
||||
id: {
|
||||
type: 'integer'
|
||||
}
|
||||
},
|
||||
schema: {
|
||||
response: responseSchema
|
||||
}
|
||||
},
|
||||
(req, reply) => {
|
||||
const { id } = req.params
|
||||
|
||||
if (Number(id) === 1) {
|
||||
const serialize4xx = reply.getSerializationFunction('4xx')
|
||||
const serialize201 = reply.getSerializationFunction(201)
|
||||
const serializeJson3xx = reply.getSerializationFunction('3xx', 'application/json')
|
||||
const serializeUndefined = reply.getSerializationFunction(undefined)
|
||||
|
||||
cached4xx = serialize4xx
|
||||
cached201 = serialize201
|
||||
cachedJson3xx = serializeJson3xx
|
||||
|
||||
t.type(serialize4xx, Function)
|
||||
t.type(serialize201, Function)
|
||||
t.type(serializeJson3xx, Function)
|
||||
t.equal(serialize4xx(okInput4xx), JSON.stringify(okInput4xx))
|
||||
t.equal(serialize201(okInput201), JSON.stringify(okInput201))
|
||||
t.equal(serializeJson3xx(okInput3xx), JSON.stringify(okInput3xx))
|
||||
t.notOk(serializeUndefined)
|
||||
|
||||
try {
|
||||
serialize4xx(notOkInput4xx)
|
||||
} catch (err) {
|
||||
t.equal(
|
||||
err.message,
|
||||
'The value "something" cannot be converted to an integer.'
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
serialize201(notOkInput201)
|
||||
} catch (err) {
|
||||
t.equal(err.message, '"status" is required!')
|
||||
}
|
||||
|
||||
try {
|
||||
serializeJson3xx(noOkInput3xx)
|
||||
} catch (err) {
|
||||
t.equal(err.message, 'The value "phone" cannot be converted to a number.')
|
||||
}
|
||||
|
||||
reply.status(201).send(okInput201)
|
||||
} else {
|
||||
const serialize201 = reply.getSerializationFunction(201)
|
||||
const serialize4xx = reply.getSerializationFunction('4xx')
|
||||
const serializeJson3xx = reply.getSerializationFunction('3xx', 'application/json')
|
||||
|
||||
t.equal(serialize4xx, cached4xx)
|
||||
t.equal(serialize201, cached201)
|
||||
t.equal(serializeJson3xx, cachedJson3xx)
|
||||
reply.status(401).send(okInput4xx)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
await Promise.all([
|
||||
fastify.inject('/1'),
|
||||
fastify.inject('/2')
|
||||
])
|
||||
}
|
||||
)
|
||||
|
||||
t.test('Should retrieve the serialization function from the cached one',
|
||||
async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
const schemaObj = getDefaultSchema()
|
||||
|
||||
const okInput = {
|
||||
hello: 'world',
|
||||
world: 'done!'
|
||||
}
|
||||
const notOkInput = {
|
||||
world: 'done!'
|
||||
}
|
||||
let cached
|
||||
|
||||
t.plan(6)
|
||||
|
||||
fastify.get(
|
||||
'/:id',
|
||||
{
|
||||
params: {
|
||||
id: {
|
||||
type: 'integer'
|
||||
}
|
||||
}
|
||||
},
|
||||
(req, reply) => {
|
||||
const { id } = req.params
|
||||
|
||||
if (Number(id) === 1) {
|
||||
const serialize = reply.compileSerializationSchema(schemaObj)
|
||||
|
||||
t.type(serialize, Function)
|
||||
t.equal(serialize(okInput), JSON.stringify(okInput))
|
||||
|
||||
try {
|
||||
serialize(notOkInput)
|
||||
} catch (err) {
|
||||
t.equal(err.message, '"hello" is required!')
|
||||
}
|
||||
|
||||
cached = serialize
|
||||
} else {
|
||||
const serialize = reply.getSerializationFunction(schemaObj)
|
||||
|
||||
t.equal(serialize, cached)
|
||||
t.equal(serialize(okInput), JSON.stringify(okInput))
|
||||
|
||||
try {
|
||||
serialize(notOkInput)
|
||||
} catch (err) {
|
||||
t.equal(err.message, '"hello" is required!')
|
||||
}
|
||||
}
|
||||
|
||||
reply.status(201).send(okInput)
|
||||
}
|
||||
)
|
||||
|
||||
await Promise.all([
|
||||
fastify.inject('/1'),
|
||||
fastify.inject('/2')
|
||||
])
|
||||
}
|
||||
)
|
||||
|
||||
t.test('Should not instantiate a WeakMap if it is not needed', async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
t.plan(4)
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
t.notOk(reply.getSerializationFunction(getDefaultSchema()))
|
||||
t.equal(reply[kRouteContext][kReplyCacheSerializeFns], null)
|
||||
t.notOk(reply.getSerializationFunction('200'))
|
||||
t.equal(reply[kRouteContext][kReplyCacheSerializeFns], null)
|
||||
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Reply#serializeInput', t => {
|
||||
t.plan(6)
|
||||
|
||||
t.test(
|
||||
'Should throw if missed serialization function from HTTP status',
|
||||
async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
t.plan(2)
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
reply.serializeInput({}, 201)
|
||||
})
|
||||
|
||||
const result = await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
|
||||
t.equal(result.statusCode, 500)
|
||||
t.same(result.json(), {
|
||||
statusCode: 500,
|
||||
code: 'FST_ERR_MISSING_SERIALIZATION_FN',
|
||||
error: 'Internal Server Error',
|
||||
message: 'Missing serialization function. Key "201"'
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
t.test(
|
||||
'Should throw if missed serialization function from HTTP status with specific content type',
|
||||
async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
t.plan(2)
|
||||
|
||||
fastify.get('/', {
|
||||
schema: {
|
||||
response: {
|
||||
'3xx': {
|
||||
content: {
|
||||
'application/json': {
|
||||
schema: {
|
||||
fullName: { type: 'string' },
|
||||
phone: { type: 'number' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, (req, reply) => {
|
||||
reply.serializeInput({}, '3xx', 'application/vnd.v1+json')
|
||||
})
|
||||
|
||||
const result = await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
|
||||
t.equal(result.statusCode, 500)
|
||||
t.same(result.json(), {
|
||||
statusCode: 500,
|
||||
code: 'FST_ERR_MISSING_CONTENTTYPE_SERIALIZATION_FN',
|
||||
error: 'Internal Server Error',
|
||||
message: 'Missing serialization function. Key "3xx:application/vnd.v1+json"'
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
t.test('Should use a serializer fn from HTTP status', async t => {
|
||||
const fastify = Fastify()
|
||||
const okInput201 = {
|
||||
status: 'ok',
|
||||
message: 'done!'
|
||||
}
|
||||
const notOkInput201 = {
|
||||
message: 'created'
|
||||
}
|
||||
const okInput4xx = {
|
||||
status: 'error',
|
||||
code: 2,
|
||||
message: 'oops!'
|
||||
}
|
||||
const notOkInput4xx = {
|
||||
status: 'error',
|
||||
code: 'something'
|
||||
}
|
||||
const okInput3xx = {
|
||||
fullName: 'Jone',
|
||||
phone: 0
|
||||
}
|
||||
const noOkInput3xx = {
|
||||
fullName: 'Jone',
|
||||
phone: 'phone'
|
||||
}
|
||||
|
||||
t.plan(6)
|
||||
|
||||
fastify.get(
|
||||
'/',
|
||||
{
|
||||
params: {
|
||||
id: {
|
||||
type: 'integer'
|
||||
}
|
||||
},
|
||||
schema: {
|
||||
response: getResponseSchema()
|
||||
}
|
||||
},
|
||||
(req, reply) => {
|
||||
t.equal(
|
||||
reply.serializeInput(okInput4xx, '4xx'),
|
||||
JSON.stringify(okInput4xx)
|
||||
)
|
||||
t.equal(
|
||||
reply.serializeInput(okInput201, 201),
|
||||
JSON.stringify(okInput201)
|
||||
)
|
||||
|
||||
t.equal(
|
||||
reply.serializeInput(okInput3xx, {}, '3xx', 'application/json'),
|
||||
JSON.stringify(okInput3xx)
|
||||
)
|
||||
|
||||
try {
|
||||
reply.serializeInput(noOkInput3xx, '3xx', 'application/json')
|
||||
} catch (err) {
|
||||
t.equal(err.message, 'The value "phone" cannot be converted to a number.')
|
||||
}
|
||||
|
||||
try {
|
||||
reply.serializeInput(notOkInput4xx, '4xx')
|
||||
} catch (err) {
|
||||
t.equal(
|
||||
err.message,
|
||||
'The value "something" cannot be converted to an integer.'
|
||||
)
|
||||
}
|
||||
|
||||
try {
|
||||
reply.serializeInput(notOkInput201, 201)
|
||||
} catch (err) {
|
||||
t.equal(err.message, '"status" is required!')
|
||||
}
|
||||
|
||||
reply.status(204).send('')
|
||||
}
|
||||
)
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
})
|
||||
|
||||
t.test(
|
||||
'Should compile a serializer out of a schema if serializer fn missed',
|
||||
async t => {
|
||||
let compilerCalled = 0
|
||||
let serializerCalled = 0
|
||||
const testInput = { hello: 'world' }
|
||||
const schemaObj = getDefaultSchema()
|
||||
const fastify = Fastify()
|
||||
const serializerCompiler = ({ schema, httpStatus, method, url }) => {
|
||||
t.equal(schema, schemaObj)
|
||||
t.notOk(httpStatus)
|
||||
t.equal(method, 'GET')
|
||||
t.equal(url, '/')
|
||||
|
||||
compilerCalled++
|
||||
return input => {
|
||||
t.equal(input, testInput)
|
||||
serializerCalled++
|
||||
return JSON.stringify(input)
|
||||
}
|
||||
}
|
||||
|
||||
t.plan(10)
|
||||
|
||||
fastify.get('/', { serializerCompiler }, (req, reply) => {
|
||||
t.equal(
|
||||
reply.serializeInput(testInput, schemaObj),
|
||||
JSON.stringify(testInput)
|
||||
)
|
||||
|
||||
t.equal(
|
||||
reply.serializeInput(testInput, schemaObj),
|
||||
JSON.stringify(testInput)
|
||||
)
|
||||
|
||||
reply.status(201).send(testInput)
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
|
||||
t.equal(compilerCalled, 1)
|
||||
t.equal(serializerCalled, 2)
|
||||
}
|
||||
)
|
||||
|
||||
t.test('Should use a cached serializer fn', async t => {
|
||||
let compilerCalled = 0
|
||||
let serializerCalled = 0
|
||||
let cached
|
||||
const testInput = { hello: 'world' }
|
||||
const schemaObj = getDefaultSchema()
|
||||
const fastify = Fastify()
|
||||
const serializer = input => {
|
||||
t.equal(input, testInput)
|
||||
serializerCalled++
|
||||
return JSON.stringify(input)
|
||||
}
|
||||
const serializerCompiler = ({ schema, httpStatus, method, url }) => {
|
||||
t.equal(schema, schemaObj)
|
||||
t.notOk(httpStatus)
|
||||
t.equal(method, 'GET')
|
||||
t.equal(url, '/')
|
||||
|
||||
compilerCalled++
|
||||
return serializer
|
||||
}
|
||||
|
||||
t.plan(12)
|
||||
|
||||
fastify.get('/', { serializerCompiler }, (req, reply) => {
|
||||
t.equal(
|
||||
reply.serializeInput(testInput, schemaObj),
|
||||
JSON.stringify(testInput)
|
||||
)
|
||||
|
||||
cached = reply.getSerializationFunction(schemaObj)
|
||||
|
||||
t.equal(
|
||||
reply.serializeInput(testInput, schemaObj),
|
||||
cached(testInput)
|
||||
)
|
||||
|
||||
reply.status(201).send(testInput)
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
|
||||
t.equal(cached, serializer)
|
||||
t.equal(compilerCalled, 1)
|
||||
t.equal(serializerCalled, 3)
|
||||
})
|
||||
|
||||
t.test('Should instantiate a WeakMap after first call', async t => {
|
||||
const fastify = Fastify()
|
||||
|
||||
t.plan(3)
|
||||
|
||||
fastify.get('/', (req, reply) => {
|
||||
const input = { hello: 'world' }
|
||||
t.equal(reply[kRouteContext][kReplyCacheSerializeFns], null)
|
||||
t.equal(reply.serializeInput(input, getDefaultSchema()), JSON.stringify(input))
|
||||
t.type(reply[kRouteContext][kReplyCacheSerializeFns], WeakMap)
|
||||
|
||||
reply.send({ hello: 'world' })
|
||||
})
|
||||
|
||||
await fastify.inject({
|
||||
path: '/',
|
||||
method: 'GET'
|
||||
})
|
||||
})
|
||||
})
|
||||
2279
node_modules/fastify/test/internals/reply.test.js
generated
vendored
Normal file
2279
node_modules/fastify/test/internals/reply.test.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
133
node_modules/fastify/test/internals/reqIdGenFactory.test.js
generated
vendored
Normal file
133
node_modules/fastify/test/internals/reqIdGenFactory.test.js
generated
vendored
Normal file
@@ -0,0 +1,133 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const { reqIdGenFactory } = require('../../lib/reqIdGenFactory')
|
||||
|
||||
test('should create incremental ids deterministically', t => {
|
||||
t.plan(1)
|
||||
const reqIdGen = reqIdGenFactory()
|
||||
|
||||
for (let i = 1; i < 1e4; ++i) {
|
||||
if (reqIdGen() !== 'req-' + i.toString(36)) {
|
||||
t.fail()
|
||||
break
|
||||
}
|
||||
}
|
||||
t.pass()
|
||||
})
|
||||
|
||||
test('should have prefix "req-"', t => {
|
||||
t.plan(1)
|
||||
const reqIdGen = reqIdGenFactory()
|
||||
|
||||
t.ok(reqIdGen().startsWith('req-'))
|
||||
})
|
||||
|
||||
test('different id generator functions should have separate internal counters', t => {
|
||||
t.plan(5)
|
||||
const reqIdGenA = reqIdGenFactory()
|
||||
const reqIdGenB = reqIdGenFactory()
|
||||
|
||||
t.equal(reqIdGenA(), 'req-1')
|
||||
t.equal(reqIdGenA(), 'req-2')
|
||||
t.equal(reqIdGenB(), 'req-1')
|
||||
t.equal(reqIdGenA(), 'req-3')
|
||||
t.equal(reqIdGenB(), 'req-2')
|
||||
})
|
||||
|
||||
test('should start counting with 1', t => {
|
||||
t.plan(1)
|
||||
const reqIdGen = reqIdGenFactory()
|
||||
|
||||
t.equal(reqIdGen(), 'req-1')
|
||||
})
|
||||
|
||||
test('should handle requestIdHeader and return provided id in header', t => {
|
||||
t.plan(1)
|
||||
|
||||
const reqIdGen = reqIdGenFactory('id')
|
||||
|
||||
t.equal(reqIdGen({ headers: { id: '1337' } }), '1337')
|
||||
})
|
||||
|
||||
test('should handle requestIdHeader and fallback if id is not provided in header', t => {
|
||||
t.plan(1)
|
||||
|
||||
const reqIdGen = reqIdGenFactory('id')
|
||||
|
||||
t.equal(reqIdGen({ headers: { notId: '1337' } }), 'req-1')
|
||||
})
|
||||
|
||||
test('should handle requestIdHeader and increment internal counter if no header was provided', t => {
|
||||
t.plan(4)
|
||||
|
||||
const reqIdGen = reqIdGenFactory('id')
|
||||
|
||||
t.equal(reqIdGen({ headers: {} }), 'req-1')
|
||||
t.equal(reqIdGen({ headers: {} }), 'req-2')
|
||||
t.equal(reqIdGen({ headers: { id: '1337' } }), '1337')
|
||||
t.equal(reqIdGen({ headers: {} }), 'req-3')
|
||||
})
|
||||
|
||||
test('should use optGenReqId to generate ids', t => {
|
||||
t.plan(4)
|
||||
|
||||
let i = 1
|
||||
let gotCalled = false
|
||||
function optGenReqId () {
|
||||
gotCalled = true
|
||||
return (i++).toString(16)
|
||||
}
|
||||
const reqIdGen = reqIdGenFactory(undefined, optGenReqId)
|
||||
|
||||
t.equal(gotCalled, false)
|
||||
t.equal(reqIdGen(), '1')
|
||||
t.equal(gotCalled, true)
|
||||
t.equal(reqIdGen(), '2')
|
||||
})
|
||||
|
||||
test('should use optGenReqId to generate ids if requestIdHeader is used but not provided', t => {
|
||||
t.plan(4)
|
||||
|
||||
let i = 1
|
||||
let gotCalled = false
|
||||
function optGenReqId () {
|
||||
gotCalled = true
|
||||
return (i++).toString(16)
|
||||
}
|
||||
const reqIdGen = reqIdGenFactory('reqId', optGenReqId)
|
||||
|
||||
t.equal(gotCalled, false)
|
||||
t.equal(reqIdGen({ headers: {} }), '1')
|
||||
t.equal(gotCalled, true)
|
||||
t.equal(reqIdGen({ headers: {} }), '2')
|
||||
})
|
||||
|
||||
test('should not use optGenReqId to generate ids if requestIdHeader is used and provided', t => {
|
||||
t.plan(2)
|
||||
|
||||
function optGenReqId () {
|
||||
t.fail()
|
||||
}
|
||||
const reqIdGen = reqIdGenFactory('reqId', optGenReqId)
|
||||
|
||||
t.equal(reqIdGen({ headers: { reqId: 'r1' } }), 'r1')
|
||||
t.equal(reqIdGen({ headers: { reqId: 'r2' } }), 'r2')
|
||||
})
|
||||
|
||||
test('should fallback to use optGenReqId to generate ids if requestIdHeader is sometimes provided', t => {
|
||||
t.plan(4)
|
||||
|
||||
let i = 1
|
||||
let gotCalled = false
|
||||
function optGenReqId () {
|
||||
gotCalled = true
|
||||
return (i++).toString(16)
|
||||
}
|
||||
const reqIdGen = reqIdGenFactory('reqId', optGenReqId)
|
||||
|
||||
t.equal(reqIdGen({ headers: { reqId: 'r1' } }), 'r1')
|
||||
t.equal(gotCalled, false)
|
||||
t.equal(reqIdGen({ headers: {} }), '1')
|
||||
t.equal(gotCalled, true)
|
||||
})
|
||||
1396
node_modules/fastify/test/internals/request-validate.test.js
generated
vendored
Normal file
1396
node_modules/fastify/test/internals/request-validate.test.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
403
node_modules/fastify/test/internals/request.test.js
generated
vendored
Normal file
403
node_modules/fastify/test/internals/request.test.js
generated
vendored
Normal file
@@ -0,0 +1,403 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
|
||||
const Request = require('../../lib/request')
|
||||
const Context = require('../../lib/context')
|
||||
const {
|
||||
kPublicRouteContext,
|
||||
kReply,
|
||||
kRequest,
|
||||
kOptions
|
||||
} = require('../../lib/symbols')
|
||||
|
||||
process.removeAllListeners('warning')
|
||||
|
||||
test('Regular request', t => {
|
||||
const headers = {
|
||||
host: 'hostname'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
const context = new Context({
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['hello'],
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
config: {
|
||||
some: 'config',
|
||||
url: req.url,
|
||||
method: req.method
|
||||
},
|
||||
server: {
|
||||
[kReply]: {},
|
||||
[kRequest]: Request,
|
||||
[kOptions]: {
|
||||
requestIdLogLabel: 'reqId'
|
||||
}
|
||||
}
|
||||
})
|
||||
req.connection = req.socket
|
||||
const request = new Request('id', 'params', req, 'query', 'log', context)
|
||||
t.type(request, Request)
|
||||
t.type(request.validateInput, Function)
|
||||
t.type(request.getValidationFunction, Function)
|
||||
t.type(request.compileValidationSchema, Function)
|
||||
t.equal(request.id, 'id')
|
||||
t.equal(request.params, 'params')
|
||||
t.equal(request.raw, req)
|
||||
t.equal(request.query, 'query')
|
||||
t.equal(request.headers, headers)
|
||||
t.equal(request.log, 'log')
|
||||
t.equal(request.ip, 'ip')
|
||||
t.equal(request.ips, undefined)
|
||||
t.equal(request.hostname, 'hostname')
|
||||
t.equal(request.body, undefined)
|
||||
t.equal(request.method, 'GET')
|
||||
t.equal(request.url, '/')
|
||||
t.equal(request.originalUrl, '/')
|
||||
t.equal(request.socket, req.socket)
|
||||
t.equal(request.protocol, 'http')
|
||||
t.equal(request.routerPath, context.config.url)
|
||||
t.equal(request.routerMethod, context.config.method)
|
||||
t.equal(request.routeConfig, context[kPublicRouteContext].config)
|
||||
t.equal(request.routeSchema, context[kPublicRouteContext].schema)
|
||||
// Aim to not bad property keys (including Symbols)
|
||||
t.notOk('undefined' in request)
|
||||
|
||||
// This will be removed, it's deprecated
|
||||
t.equal(request.connection, req.connection)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Request with undefined config', t => {
|
||||
const headers = {
|
||||
host: 'hostname'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
const context = new Context({
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['hello'],
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
server: {
|
||||
[kReply]: {},
|
||||
[kRequest]: Request,
|
||||
[kOptions]: {
|
||||
requestIdLogLabel: 'reqId'
|
||||
}
|
||||
}
|
||||
})
|
||||
req.connection = req.socket
|
||||
const request = new Request('id', 'params', req, 'query', 'log', context)
|
||||
t.type(request, Request)
|
||||
t.type(request.validateInput, Function)
|
||||
t.type(request.getValidationFunction, Function)
|
||||
t.type(request.compileValidationSchema, Function)
|
||||
t.equal(request.id, 'id')
|
||||
t.equal(request.params, 'params')
|
||||
t.equal(request.raw, req)
|
||||
t.equal(request.query, 'query')
|
||||
t.equal(request.headers, headers)
|
||||
t.equal(request.log, 'log')
|
||||
t.equal(request.ip, 'ip')
|
||||
t.equal(request.ips, undefined)
|
||||
t.equal(request.hostname, 'hostname')
|
||||
t.equal(request.body, undefined)
|
||||
t.equal(request.method, 'GET')
|
||||
t.equal(request.url, '/')
|
||||
t.equal(request.originalUrl, '/')
|
||||
t.equal(request.socket, req.socket)
|
||||
t.equal(request.protocol, 'http')
|
||||
t.equal(request.routeSchema, context[kPublicRouteContext].schema)
|
||||
t.equal(request.routerPath, undefined)
|
||||
t.equal(request.routerMethod, undefined)
|
||||
t.equal(request.routeConfig, undefined)
|
||||
|
||||
// Aim to not bad property keys (including Symbols)
|
||||
t.notOk('undefined' in request)
|
||||
|
||||
// This will be removed, it's deprecated
|
||||
t.equal(request.connection, req.connection)
|
||||
t.end()
|
||||
})
|
||||
|
||||
test('Regular request - hostname from authority', t => {
|
||||
t.plan(2)
|
||||
const headers = {
|
||||
':authority': 'authority'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
|
||||
const request = new Request('id', 'params', req, 'query', 'log')
|
||||
t.type(request, Request)
|
||||
t.equal(request.hostname, 'authority')
|
||||
})
|
||||
|
||||
test('Regular request - host header has precedence over authority', t => {
|
||||
t.plan(2)
|
||||
const headers = {
|
||||
host: 'hostname',
|
||||
':authority': 'authority'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
const request = new Request('id', 'params', req, 'query', 'log')
|
||||
t.type(request, Request)
|
||||
t.equal(request.hostname, 'hostname')
|
||||
})
|
||||
|
||||
test('Request with trust proxy', t => {
|
||||
t.plan(22)
|
||||
const headers = {
|
||||
'x-forwarded-for': '2.2.2.2, 1.1.1.1',
|
||||
'x-forwarded-host': 'example.com'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
const context = new Context({
|
||||
schema: {
|
||||
body: {
|
||||
type: 'object',
|
||||
required: ['hello'],
|
||||
properties: {
|
||||
hello: { type: 'string' }
|
||||
}
|
||||
}
|
||||
},
|
||||
config: {
|
||||
some: 'config',
|
||||
url: req.url,
|
||||
method: req.method
|
||||
},
|
||||
server: {
|
||||
[kReply]: {},
|
||||
[kRequest]: Request,
|
||||
[kOptions]: {
|
||||
requestIdLogLabel: 'reqId'
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log', context)
|
||||
t.type(request, TpRequest)
|
||||
t.equal(request.id, 'id')
|
||||
t.equal(request.params, 'params')
|
||||
t.same(request.raw, req)
|
||||
t.equal(request.query, 'query')
|
||||
t.equal(request.headers, headers)
|
||||
t.equal(request.log, 'log')
|
||||
t.equal(request.ip, '2.2.2.2')
|
||||
t.same(request.ips, ['ip', '1.1.1.1', '2.2.2.2'])
|
||||
t.equal(request.hostname, 'example.com')
|
||||
t.equal(request.body, undefined)
|
||||
t.equal(request.method, 'GET')
|
||||
t.equal(request.url, '/')
|
||||
t.equal(request.socket, req.socket)
|
||||
t.equal(request.protocol, 'http')
|
||||
t.type(request.validateInput, Function)
|
||||
t.type(request.getValidationFunction, Function)
|
||||
t.type(request.compileValidationSchema, Function)
|
||||
t.equal(request.routerPath, context.config.url)
|
||||
t.equal(request.routerMethod, context.config.method)
|
||||
t.equal(request.routeConfig, context[kPublicRouteContext].config)
|
||||
t.equal(request.routeSchema, context[kPublicRouteContext].schema)
|
||||
})
|
||||
|
||||
test('Request with trust proxy, encrypted', t => {
|
||||
t.plan(2)
|
||||
const headers = {
|
||||
'x-forwarded-for': '2.2.2.2, 1.1.1.1',
|
||||
'x-forwarded-host': 'example.com'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip', encrypted: true },
|
||||
headers
|
||||
}
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log')
|
||||
t.type(request, TpRequest)
|
||||
t.equal(request.protocol, 'https')
|
||||
})
|
||||
|
||||
test('Request with trust proxy - no x-forwarded-host header', t => {
|
||||
t.plan(2)
|
||||
const headers = {
|
||||
'x-forwarded-for': '2.2.2.2, 1.1.1.1',
|
||||
host: 'hostname'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log')
|
||||
t.type(request, TpRequest)
|
||||
t.equal(request.hostname, 'hostname')
|
||||
})
|
||||
|
||||
test('Request with trust proxy - no x-forwarded-host header and fallback to authority', t => {
|
||||
t.plan(2)
|
||||
const headers = {
|
||||
'x-forwarded-for': '2.2.2.2, 1.1.1.1',
|
||||
':authority': 'authority'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log')
|
||||
t.type(request, TpRequest)
|
||||
t.equal(request.hostname, 'authority')
|
||||
})
|
||||
|
||||
test('Request with trust proxy - x-forwarded-host header has precedence over host', t => {
|
||||
t.plan(2)
|
||||
const headers = {
|
||||
'x-forwarded-for': ' 2.2.2.2, 1.1.1.1',
|
||||
'x-forwarded-host': 'example.com',
|
||||
host: 'hostname'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log')
|
||||
t.type(request, TpRequest)
|
||||
t.equal(request.hostname, 'example.com')
|
||||
})
|
||||
|
||||
test('Request with trust proxy - handles multiple entries in x-forwarded-host/proto', t => {
|
||||
t.plan(3)
|
||||
const headers = {
|
||||
'x-forwarded-host': 'example2.com, example.com',
|
||||
'x-forwarded-proto': 'http, https'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log')
|
||||
t.type(request, TpRequest)
|
||||
t.equal(request.hostname, 'example.com')
|
||||
t.equal(request.protocol, 'https')
|
||||
})
|
||||
|
||||
test('Request with trust proxy - plain', t => {
|
||||
t.plan(1)
|
||||
const headers = {
|
||||
'x-forwarded-for': '2.2.2.2, 1.1.1.1',
|
||||
'x-forwarded-host': 'example.com'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: { remoteAddress: 'ip' },
|
||||
headers
|
||||
}
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log')
|
||||
t.same(request.protocol, 'http')
|
||||
})
|
||||
|
||||
test('Request with undefined socket', t => {
|
||||
t.plan(18)
|
||||
const headers = {
|
||||
host: 'hostname'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: undefined,
|
||||
headers
|
||||
}
|
||||
const request = new Request('id', 'params', req, 'query', 'log')
|
||||
t.type(request, Request)
|
||||
t.equal(request.id, 'id')
|
||||
t.equal(request.params, 'params')
|
||||
t.same(request.raw, req)
|
||||
t.equal(request.query, 'query')
|
||||
t.equal(request.headers, headers)
|
||||
t.equal(request.log, 'log')
|
||||
t.equal(request.ip, undefined)
|
||||
t.equal(request.ips, undefined)
|
||||
t.equal(request.hostname, 'hostname')
|
||||
t.same(request.body, null)
|
||||
t.equal(request.method, 'GET')
|
||||
t.equal(request.url, '/')
|
||||
t.equal(request.protocol, undefined)
|
||||
t.same(request.socket, req.socket)
|
||||
t.type(request.validateInput, Function)
|
||||
t.type(request.getValidationFunction, Function)
|
||||
t.type(request.compileValidationSchema, Function)
|
||||
})
|
||||
|
||||
test('Request with trust proxy and undefined socket', t => {
|
||||
t.plan(1)
|
||||
const headers = {
|
||||
'x-forwarded-for': '2.2.2.2, 1.1.1.1',
|
||||
'x-forwarded-host': 'example.com'
|
||||
}
|
||||
const req = {
|
||||
method: 'GET',
|
||||
url: '/',
|
||||
socket: undefined,
|
||||
headers
|
||||
}
|
||||
|
||||
const TpRequest = Request.buildRequest(Request, true)
|
||||
const request = new TpRequest('id', 'params', req, 'query', 'log')
|
||||
t.same(request.protocol, undefined)
|
||||
})
|
||||
88
node_modules/fastify/test/internals/server.test.js
generated
vendored
Normal file
88
node_modules/fastify/test/internals/server.test.js
generated
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
'use strict'
|
||||
|
||||
const { test } = require('tap')
|
||||
const proxyquire = require('proxyquire')
|
||||
|
||||
const Fastify = require('../../fastify')
|
||||
const { createServer } = require('../../lib/server')
|
||||
|
||||
const handler = (req, res) => {
|
||||
res.writeHead(200, { 'Content-Type': 'application/json' })
|
||||
res.end(JSON.stringify({ data: 'Hello World!' }))
|
||||
}
|
||||
|
||||
test('start listening', async t => {
|
||||
const { server, listen } = createServer({}, handler)
|
||||
await listen.call(Fastify(), { port: 0, host: 'localhost' })
|
||||
server.close()
|
||||
t.pass('server started')
|
||||
})
|
||||
|
||||
test('DNS errors does not stop the main server on localhost - promise interface', async t => {
|
||||
const { createServer } = proxyquire('../../lib/server', {
|
||||
'node:dns': {
|
||||
lookup: (hostname, options, cb) => {
|
||||
cb(new Error('DNS error'))
|
||||
}
|
||||
}
|
||||
})
|
||||
const { server, listen } = createServer({}, handler)
|
||||
await listen.call(Fastify(), { port: 0, host: 'localhost' })
|
||||
server.close()
|
||||
t.pass('server started')
|
||||
})
|
||||
|
||||
test('DNS errors does not stop the main server on localhost - callback interface', t => {
|
||||
t.plan(2)
|
||||
const { createServer } = proxyquire('../../lib/server', {
|
||||
'node:dns': {
|
||||
lookup: (hostname, options, cb) => {
|
||||
cb(new Error('DNS error'))
|
||||
}
|
||||
}
|
||||
})
|
||||
const { server, listen } = createServer({}, handler)
|
||||
listen.call(Fastify(), { port: 0, host: 'localhost' }, (err) => {
|
||||
t.error(err)
|
||||
server.close()
|
||||
t.pass('server started')
|
||||
})
|
||||
})
|
||||
|
||||
test('DNS returns empty binding', t => {
|
||||
t.plan(2)
|
||||
const { createServer } = proxyquire('../../lib/server', {
|
||||
'node:dns': {
|
||||
lookup: (hostname, options, cb) => {
|
||||
cb(null, [])
|
||||
}
|
||||
}
|
||||
})
|
||||
const { server, listen } = createServer({}, handler)
|
||||
listen.call(Fastify(), { port: 0, host: 'localhost' }, (err) => {
|
||||
t.error(err)
|
||||
server.close()
|
||||
t.pass('server started')
|
||||
})
|
||||
})
|
||||
|
||||
test('DNS returns more than two binding', t => {
|
||||
t.plan(2)
|
||||
const { createServer } = proxyquire('../../lib/server', {
|
||||
'node:dns': {
|
||||
lookup: (hostname, options, cb) => {
|
||||
cb(null, [
|
||||
{ address: '::1', family: 6 },
|
||||
{ address: '127.0.0.1', family: 4 },
|
||||
{ address: '0.0.0.0', family: 4 }
|
||||
])
|
||||
}
|
||||
}
|
||||
})
|
||||
const { server, listen } = createServer({}, handler)
|
||||
listen.call(Fastify(), { port: 0, host: 'localhost' }, (err) => {
|
||||
t.error(err)
|
||||
server.close()
|
||||
t.pass('server started')
|
||||
})
|
||||
})
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user