This commit is contained in:
heiye111
2025-09-20 21:06:53 +08:00
commit c74f28caa7
2539 changed files with 365006 additions and 0 deletions

1966
node_modules/fastify/test/404s.test.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

231
node_modules/fastify/test/500s.test.js generated vendored Normal file
View File

@@ -0,0 +1,231 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('..')
const symbols = require('../lib/symbols.js')
test('default 500', (t, done) => {
t.plan(4)
const fastify = Fastify()
t.after(() => fastify.close())
fastify.get('/', function (req, reply) {
reply.send(new Error('kaboom'))
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.assert.ifError(err)
t.assert.strictEqual(res.statusCode, 500)
t.assert.strictEqual(res.headers['content-type'], 'application/json; charset=utf-8')
t.assert.deepStrictEqual(JSON.parse(res.payload), {
error: 'Internal Server Error',
message: 'kaboom',
statusCode: 500
})
done()
})
})
test('custom 500', (t, done) => {
t.plan(6)
const fastify = Fastify()
t.after(() => fastify.close())
fastify.get('/', function (req, reply) {
reply.send(new Error('kaboom'))
})
fastify.setErrorHandler(function (err, request, reply) {
t.assert.ok(typeof request === 'object')
t.assert.ok(request instanceof fastify[symbols.kRequest].parent)
reply
.code(500)
.type('text/plain')
.send('an error happened: ' + err.message)
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.assert.ifError(err)
t.assert.strictEqual(res.statusCode, 500)
t.assert.strictEqual(res.headers['content-type'], 'text/plain')
t.assert.deepStrictEqual(res.payload.toString(), 'an error happened: kaboom')
done()
})
})
test('encapsulated 500', async t => {
t.plan(8)
const fastify = Fastify()
t.after(() => fastify.close())
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.assert.ok(typeof request === 'object')
t.assert.ok(request instanceof fastify[symbols.kRequest].parent)
reply
.code(500)
.type('text/plain')
.send('an error happened: ' + err.message)
})
done()
}, { prefix: 'test' })
{
const response = await fastify.inject({
method: 'GET',
url: '/test'
})
t.assert.strictEqual(response.statusCode, 500)
t.assert.strictEqual(response.headers['content-type'], 'text/plain')
t.assert.deepStrictEqual(response.payload.toString(), 'an error happened: kaboom')
}
{
const response = await fastify.inject({
method: 'GET',
url: '/'
})
t.assert.strictEqual(response.statusCode, 500)
t.assert.strictEqual(response.headers['content-type'], 'application/json; charset=utf-8')
t.assert.deepStrictEqual(JSON.parse(response.payload), {
error: 'Internal Server Error',
message: 'kaboom',
statusCode: 500
})
}
})
test('custom 500 with hooks', (t, done) => {
t.plan(7)
const fastify = Fastify()
t.after(() => fastify.close())
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.assert.ok('called', 'onSend')
done()
})
fastify.addHook('onRequest', (req, res, done) => {
t.assert.ok('called', 'onRequest')
done()
})
fastify.addHook('onResponse', (request, reply, done) => {
t.assert.ok('called', 'onResponse')
done()
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.assert.ifError(err)
t.assert.strictEqual(res.statusCode, 500)
t.assert.strictEqual(res.headers['content-type'], 'text/plain')
t.assert.deepStrictEqual(res.payload.toString(), 'an error happened: kaboom')
done()
})
})
test('cannot set errorHandler after binding', (t, done) => {
t.plan(2)
const fastify = Fastify()
t.after(() => fastify.close())
fastify.listen({ port: 0 }, err => {
t.assert.ifError(err)
try {
fastify.setErrorHandler(() => { })
t.assert.fail()
} catch (e) {
t.assert.ok(true)
} finally {
done()
}
})
})
test('cannot set childLoggerFactory after binding', (t, done) => {
t.plan(2)
const fastify = Fastify()
t.after(() => fastify.close())
fastify.listen({ port: 0 }, err => {
t.assert.ifError(err)
try {
fastify.setChildLoggerFactory(() => { })
t.assert.fail()
} catch (e) {
t.assert.ok(true)
} finally {
done()
}
})
})
test('catch synchronous errors', (t, done) => {
t.plan(3)
const fastify = Fastify()
t.after(() => fastify.close())
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.assert.ifError(err)
t.assert.strictEqual(res.statusCode, 500)
t.assert.deepStrictEqual(res.json(), {
error: 'Internal Server Error',
message: 'kaboom2',
statusCode: 500
})
done()
})
})

92
node_modules/fastify/test/allow-unsafe-regex.test.js generated vendored Normal file
View File

@@ -0,0 +1,92 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('..')
test('allow unsafe regex', async t => {
t.plan(2)
const fastify = Fastify({
allowUnsafeRegex: false
})
t.after(() => fastify.close())
fastify.get('/:foo(^[0-9]*$)', (req, reply) => {
reply.send({ foo: req.params.foo })
})
await fastify.listen({ port: 0 })
const result = await fetch(`http://localhost:${fastify.server.address().port}/1234`)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.json(), { foo: '1234' })
})
test('allow unsafe regex not match', async t => {
t.plan(1)
const fastify = Fastify({
allowUnsafeRegex: false
})
t.after(() => fastify.close())
fastify.get('/:foo(^[0-9]*$)', (req, reply) => {
reply.send({ foo: req.params.foo })
})
await fastify.listen({ port: 0 })
const result = await fetch(`http://localhost:${fastify.server.address().port}/a1234`)
t.assert.strictEqual(result.status, 404)
})
test('allow unsafe regex not safe', (t, done) => {
t.plan(1)
const fastify = Fastify({
allowUnsafeRegex: false
})
t.after(() => fastify.close())
t.assert.throws(() => {
fastify.get('/:foo(^([0-9]+){4}$)', (req, reply) => {
reply.send({ foo: req.params.foo })
})
})
done()
})
test('allow unsafe regex not safe by default', (t, done) => {
t.plan(1)
const fastify = Fastify()
t.after(() => fastify.close())
t.assert.throws(() => {
fastify.get('/:foo(^([0-9]+){4}$)', (req, reply) => {
reply.send({ foo: req.params.foo })
})
})
done()
})
test('allow unsafe regex allow unsafe', async t => {
t.plan(3)
const fastify = Fastify({
allowUnsafeRegex: true
})
t.after(() => fastify.close())
t.assert.doesNotThrow(() => {
fastify.get('/:foo(^([0-9]+){4}$)', (req, reply) => {
reply.send({ foo: req.params.foo })
})
})
await fastify.listen({ port: 0 })
const result = await fetch(`http://localhost:${fastify.server.address().port}/1234`)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.json(), { foo: '1234' })
})

65
node_modules/fastify/test/als.test.js generated vendored Normal file
View File

@@ -0,0 +1,65 @@
'use strict'
const { AsyncLocalStorage } = require('node:async_hooks')
const { test } = require('node:test')
const Fastify = require('..')
test('Async Local Storage test', async (t) => {
t.plan(12)
if (!AsyncLocalStorage) {
t.skip('AsyncLocalStorage not available, skipping test')
process.exit(0)
}
const storage = new AsyncLocalStorage()
const app = Fastify({ logger: false })
t.after(() => app.close())
let counter = 0
app.addHook('onRequest', (req, reply, next) => {
const id = counter++
storage.run({ id }, next)
})
app.get('/', function (request, reply) {
t.assert.ok(storage.getStore())
const id = storage.getStore().id
reply.send({ id })
})
app.post('/', function (request, reply) {
t.assert.ok(storage.getStore())
const id = storage.getStore().id
reply.send({ id })
})
const fastifyServer = await app.listen({ port: 0 })
// First POST request
const result1 = await fetch(fastifyServer, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ hello: 'world' })
})
t.assert.ok(result1.ok)
t.assert.strictEqual(result1.status, 200)
t.assert.deepStrictEqual(await result1.json(), { id: 0 })
const result2 = await fetch(fastifyServer, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ hello: 'world' })
})
t.assert.ok(result2.ok)
t.assert.strictEqual(result2.status, 200)
t.assert.deepStrictEqual(await result2.json(), { id: 1 })
// GET request
const result3 = await fetch(fastifyServer, {
method: 'GET'
})
t.assert.ok(result3.ok)
t.assert.strictEqual(result3.status, 200)
t.assert.deepStrictEqual(await result3.json(), { id: 2 })
})

705
node_modules/fastify/test/async-await.test.js generated vendored Normal file
View File

@@ -0,0 +1,705 @@
'use strict'
const { test } = require('node:test')
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'
}
}
}
}
}
}
const optsWithHostnameAndPort = {
schema: {
response: {
'2xx': {
type: 'object',
properties: {
hello: {
type: 'string'
},
hostname: {
type: 'string'
},
port: {
type: 'string'
}
}
}
}
}
}
test('async await', async t => {
t.plan(15)
const fastify = Fastify()
try {
fastify.get('/', opts, async function awaitMyFunc (req, reply) {
await sleep(200)
return { hello: 'world' }
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
try {
fastify.get('/no-await', opts, async function (req, reply) {
return { hello: 'world' }
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
try {
fastify.get('/await/hostname_port', optsWithHostnameAndPort, async function awaitMyFunc (req, reply) {
await sleep(200)
return { hello: 'world', hostname: req.hostname, port: req.port }
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
const result = await fetch(fastifyServer)
const body = await result.text()
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
const result1 = await fetch(`${fastifyServer}/no-await`)
const body1 = await result1.text()
t.assert.ok(result1.ok)
t.assert.strictEqual(result1.status, 200)
t.assert.strictEqual(result1.headers.get('content-length'), '' + body1.length)
t.assert.deepStrictEqual(JSON.parse(body1), { hello: 'world' })
const result2 = await fetch(`http://localhost:${fastify.server.address().port}/await/hostname_port`)
const parsedBody = await result2.json()
t.assert.ok(result2.ok)
t.assert.strictEqual(result2.status, 200)
t.assert.strictEqual(parsedBody.hostname, 'localhost')
t.assert.strictEqual(parseInt(parsedBody.port), fastify.server.address().port)
})
test('ignore the result of the promise if reply.send is called beforehand (undefined)', async (t) => {
t.plan(3)
const server = Fastify()
const payload = { hello: 'world' }
server.get('/', async function awaitMyFunc (req, reply) {
await reply.send(payload)
})
t.after(() => { server.close() })
const fastifyServer = await server.listen({ port: 0 })
const result = await fetch(fastifyServer)
t.assert.ok(result.ok)
t.assert.deepStrictEqual(payload, await result.json())
t.assert.strictEqual(result.status, 200)
})
test('ignore the result of the promise if reply.send is called beforehand (object)', async (t) => {
t.plan(3)
const server = Fastify()
const payload = { hello: 'world2' }
server.get('/', async function awaitMyFunc (req, reply) {
await reply.send(payload)
return { hello: 'world' }
})
t.after(() => { server.close() })
const fastifyServer = await server.listen({ port: 0 })
const result = await fetch(fastifyServer)
t.assert.ok(result.ok)
t.assert.deepStrictEqual(payload, await result.json())
t.assert.strictEqual(result.status, 200)
})
test('server logs an error if reply.send is called and a value is returned via async/await', (t, done) => {
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.assert.strictEqual(line.msg, lines.shift())
})
const logger = pino(splitStream)
const fastify = Fastify({
loggerInstance: logger
})
fastify.get('/', async (req, reply) => {
await reply.send({ hello: 'world' })
return { hello: 'world2' }
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.deepStrictEqual(payload, { hello: 'world' })
done()
})
})
test('ignore the result of the promise if reply.send is called beforehand (undefined)', async (t) => {
t.plan(3)
const server = Fastify()
const payload = { hello: 'world' }
server.get('/', async function awaitMyFunc (req, reply) {
await reply.send(payload)
})
t.after(() => { server.close() })
const fastifyServer = await server.listen({ port: 0 })
const result = await fetch(fastifyServer)
t.assert.ok(result.ok)
t.assert.deepStrictEqual(payload, await result.json())
t.assert.strictEqual(result.status, 200)
})
test('ignore the result of the promise if reply.send is called beforehand (object)', async (t) => {
t.plan(3)
const server = Fastify()
const payload = { hello: 'world2' }
server.get('/', async function awaitMyFunc (req, reply) {
await reply.send(payload)
return { hello: 'world' }
})
t.after(() => { server.close() })
const fastifyServer = await server.listen({ port: 0 })
const result = await fetch(fastifyServer)
t.assert.ok(result.ok)
t.assert.deepStrictEqual(payload, await result.json())
t.assert.strictEqual(result.status, 200)
})
test('await reply if we will be calling reply.send in the future', (t, done) => {
const lines = ['incoming request', 'request completed']
t.plan(lines.length + 2)
const splitStream = split(JSON.parse)
splitStream.on('data', (line) => {
t.assert.strictEqual(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.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.deepStrictEqual(payload, { hello: 'world' })
done()
})
})
test('await reply if we will be calling reply.send in the future (error case)', (t, done) => {
const lines = ['incoming request', 'kaboom', 'request completed']
t.plan(lines.length + 2)
const splitStream = split(JSON.parse)
splitStream.on('data', (line) => {
t.assert.strictEqual(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.assert.ifError(err)
t.assert.strictEqual(res.statusCode, 500)
done()
})
})
test('support reply decorators with await', (t, done) => {
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.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.deepStrictEqual(payload, { hello: 'world' })
done()
})
})
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.assert.deepStrictEqual({ hello: 'world' }, JSON.parse(res.payload))
} catch (err) {
t.assert.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.assert.deepStrictEqual({ hello: 'world' }, JSON.parse(res.payload))
} catch (err) {
t.assert.fail(err)
}
await sleep(200)
try {
const res2 = await fastify.inject({ method: 'GET', url: '/' })
t.assert.deepStrictEqual({ hello: 'world' }, JSON.parse(res2.payload))
} catch (err) {
t.assert.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.assert.deepStrictEqual({ hello: 'world' }, JSON.parse(res.payload))
} catch (err) {
t.assert.fail(err)
}
})
test('does not call reply.send() twice if 204 response equal already sent', (t, done) => {
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.assert.ifError(err)
t.assert.strictEqual(res.statusCode, 204)
done()
})
})
test('promise was fulfilled with undefined', async (t) => {
t.plan(3)
let fastify = null
const stream = split(JSON.parse)
try {
fastify = Fastify({
logger: {
stream,
level: 'error'
}
})
} catch (e) {
t.assert.fail()
}
t.after(() => { fastify.close() })
fastify.get('/', async (req, reply) => {
})
stream.once('data', line => {
t.assert.fail('should not log an error')
})
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(fastifyServer)
t.assert.ok(result.ok)
t.assert.strictEqual(await result.text(), '')
t.assert.strictEqual(result.status, 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.assert.fail('should not log an error')
})
const res = await fastify.inject('/')
t.assert.strictEqual(res.body, '')
t.assert.strictEqual(res.statusCode, 200)
})
test('error is not logged because promise was fulfilled with undefined but response was sent before promise resolution', async (t) => {
t.plan(3)
let fastify = null
const stream = split(JSON.parse)
const payload = { hello: 'world' }
try {
fastify = Fastify({
logger: {
stream,
level: 'error'
}
})
} catch (e) {
t.assert.fail()
}
t.after(() => { fastify.close() })
fastify.get('/', async (req, reply) => {
reply.send(payload)
})
stream.once('data', line => {
t.assert.fail('should not log an error')
})
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(fastifyServer)
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(
payload,
await result.json()
)
})
test('Thrown Error instance sets HTTP status code', (t, done) => {
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.assert.ifError(error)
t.assert.strictEqual(res.statusCode, 418)
t.assert.deepStrictEqual(
{
error: statusCodes['418'],
message: err.message,
statusCode: 418
},
JSON.parse(res.payload)
)
done()
})
})
test('customErrorHandler support', (t, done) => {
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.assert.strictEqual(err.message, 'ouch')
const error = new Error('kaboom')
error.statusCode = 401
throw error
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.assert.ifError(err)
t.assert.strictEqual(res.statusCode, 401)
t.assert.deepStrictEqual(
{
error: statusCodes['401'],
message: 'kaboom',
statusCode: 401
},
JSON.parse(res.payload)
)
done()
})
})
test('customErrorHandler support without throwing', (t, done) => {
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.assert.strictEqual(err.message, 'ouch')
await reply.code(401).send('kaboom')
reply.send = t.assert.fail.bind(t, 'should not be called')
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.assert.ifError(err)
t.assert.strictEqual(res.statusCode, 401)
t.assert.deepStrictEqual(
'kaboom',
res.payload
)
done()
})
})
// See https://github.com/fastify/fastify/issues/2653
test('customErrorHandler only called if reply not already sent', (t, done) => {
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.assert.fail.bind(t, 'should not be called'))
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.assert.ifError(err)
t.assert.strictEqual(res.statusCode, 200)
t.assert.deepStrictEqual(
'success',
res.payload
)
done()
})
})
// See https://github.com/fastify/fastify/issues/3209
test('setNotFoundHandler should accept return value', (t, done) => {
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.assert.ifError(err)
t.assert.strictEqual(res.statusCode, 404)
t.assert.deepStrictEqual(
{
error: statusCodes['404'],
message: 'lost',
statusCode: 404
},
JSON.parse(res.payload)
)
done()
})
})
// See https://github.com/fastify/fastify/issues/3209
test('customErrorHandler should accept return value', (t, done) => {
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.assert.strictEqual(err.message, 'ouch')
reply.code(401)
return {
error: statusCodes['401'],
message: 'kaboom',
statusCode: 401
}
})
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.assert.ifError(err)
t.assert.strictEqual(res.statusCode, 401)
t.assert.deepStrictEqual(
{
error: statusCodes['401'],
message: 'kaboom',
statusCode: 401
},
JSON.parse(res.payload)
)
done()
})
})
test('await self', async t => {
const app = Fastify()
t.assert.strictEqual(await app, app)
})

20
node_modules/fastify/test/async-dispose.test.js generated vendored Normal file
View File

@@ -0,0 +1,20 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('../fastify')
// asyncDispose doesn't exist in node <= 16
test('async dispose should close fastify', { skip: !('asyncDispose' in Symbol) }, async t => {
t.plan(2)
const fastify = Fastify()
await fastify.listen({ port: 0 })
t.assert.strictEqual(fastify.server.listening, true)
// the same as syntax sugar for
// await using app = fastify()
await fastify[Symbol.asyncDispose]()
t.assert.strictEqual(fastify.server.listening, false)
})

52
node_modules/fastify/test/async_hooks.test.js generated vendored Normal file
View File

@@ -0,0 +1,52 @@
'use strict'
const { createHook } = require('node:async_hooks')
const { test } = require('node:test')
const Fastify = require('..')
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 })
test('test async hooks', async (t) => {
app.get('/', function (request, reply) {
reply.send({ id: 42 })
})
app.post('/', function (request, reply) {
reply.send({ id: 42 })
})
t.after(() => app.close())
const fastifyServer = await app.listen({ port: 0 })
const result1 = await fetch(fastifyServer, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ hello: 'world' })
})
t.assert.strictEqual(result1.status, 200)
const result2 = await fetch(fastifyServer, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ hello: 'world' })
})
t.assert.strictEqual(result2.status, 200)
const result3 = await fetch(fastifyServer)
t.assert.strictEqual(result3.status, 200)
t.assert.strictEqual(remainingIds.size, 0)
})

224
node_modules/fastify/test/body-limit.test.js generated vendored Normal file
View File

@@ -0,0 +1,224 @@
'use strict'
const Fastify = require('../fastify')
const zlib = require('node:zlib')
const { test } = require('node:test')
test('bodyLimit', async t => {
t.plan(4)
try {
Fastify({ bodyLimit: 1.3 })
t.assert.fail('option must be an integer')
} catch (err) {
t.assert.ok(err)
}
try {
Fastify({ bodyLimit: [] })
t.assert.fail('option must be an integer')
} catch (err) {
t.assert.ok(err)
}
const fastify = Fastify({ bodyLimit: 1 })
fastify.post('/', (request, reply) => {
reply.send({ error: 'handler should not be called' })
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
const result = await fetch(fastifyServer, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify([])
})
t.assert.ok(!result.ok)
t.assert.strictEqual(result.status, 413)
})
test('bodyLimit is applied to decoded content', async (t) => {
t.plan(6)
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.assert.strictEqual(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.assert.strictEqual(err.code, 'FST_ERR_CTP_BODY_TOO_LARGE')
t.assert.strictEqual(err.statusCode, 413)
}
}, (request, reply) => {
reply.send({ x: 'handler should not be called' })
})
await t.test('bodyLimit 40k', async (t) => {
const result = await fastify.inject({
method: 'POST',
url: '/body-limit-40k',
headers: {
'content-encoding': 'gzip',
'content-type': 'application/json'
},
payload: encoded
})
t.assert.strictEqual(result.statusCode, 200)
t.assert.deepStrictEqual(result.json(), body)
})
await t.test('bodyLimit 20k', async (t) => {
const result = await fastify.inject({
method: 'POST',
url: '/body-limit-20k',
headers: {
'content-encoding': 'gzip',
'content-type': 'application/json'
},
payload: encoded
})
t.assert.strictEqual(result.statusCode, 413)
})
})
test('default request.routeOptions.bodyLimit should be 1048576', async t => {
t.plan(3)
const fastify = Fastify()
fastify.post('/default-bodylimit', {
handler (request, reply) {
t.assert.strictEqual(1048576, request.routeOptions.bodyLimit)
reply.send({ })
}
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
const result = await fetch(fastifyServer + '/default-bodylimit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify([])
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
})
test('request.routeOptions.bodyLimit should be equal to route limit', async t => {
t.plan(3)
const fastify = Fastify({ bodyLimit: 1 })
fastify.post('/route-limit', {
bodyLimit: 1000,
handler (request, reply) {
t.assert.strictEqual(1000, request.routeOptions.bodyLimit)
reply.send({})
}
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
const result = await fetch(fastifyServer + '/route-limit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify([])
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
})
test('request.routeOptions.bodyLimit should be equal to server limit', async t => {
t.plan(3)
const fastify = Fastify({ bodyLimit: 100 })
fastify.post('/server-limit', {
handler (request, reply) {
t.assert.strictEqual(100, request.routeOptions.bodyLimit)
reply.send({})
}
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
const result = await fetch(fastifyServer + '/server-limit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify([])
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
})
test('bodyLimit should use byte length for UTF-8 strings, not character length', async t => {
t.plan(4)
// Create a string with multi-byte UTF-8 characters
// Use Japanese characters that are 3 bytes each in UTF-8
const multiByteString = 'あああ' // 3 characters, 9 bytes in UTF-8
t.assert.strictEqual(multiByteString.length, 3) // 3 characters
t.assert.strictEqual(Buffer.byteLength(multiByteString, 'utf8'), 9) // 9 bytes
const fastify = Fastify()
// Add a custom text parser that returns the string as-is
fastify.addContentTypeParser('text/plain', { parseAs: 'string' }, (req, body, done) => {
done(null, body)
})
// Set body limit to 7 bytes - this should reject the string (9 bytes)
// even though string.length (3) would be under any reasonable limit
fastify.post('/test-utf8', {
bodyLimit: 7
}, (request, reply) => {
reply.send({ body: request.body, length: request.body.length })
})
await t.test('should reject body when byte length exceeds limit', async (t) => {
const result = await fastify.inject({
method: 'POST',
url: '/test-utf8',
headers: { 'Content-Type': 'text/plain', 'Content-Length': null },
payload: multiByteString
})
t.assert.strictEqual(result.statusCode, 413)
})
await t.test('should accept body when byte length is within limit', async (t) => {
const smallString = 'あ' // 1 character, 3 bytes, under the 7 byte limit
const result = await fastify.inject({
method: 'POST',
url: '/test-utf8',
headers: { 'Content-Type': 'text/plain' },
payload: smallString
})
t.assert.strictEqual(result.statusCode, 200)
t.assert.strictEqual(result.json().body, smallString)
t.assert.strictEqual(result.json().length, 1) // 1 character
})
})

74
node_modules/fastify/test/buffer.test.js generated vendored Normal file
View File

@@ -0,0 +1,74 @@
'use strict'
const { test } = require('node: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
})
await 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.assert.ifError(response.error)
t.assert.strictEqual(response.statusCode, 200)
t.assert.deepStrictEqual(response.payload.toString(), '{"hello":"world"}')
})
await 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.assert.ifError(response.error)
t.assert.strictEqual(response.statusCode, 400)
t.assert.deepStrictEqual(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
})
})
await test('should return 400 if the body is invalid json', async t => {
t.plan(3)
const response = await fastify.inject({
method: 'DELETE',
url: '/',
payload: Buffer.from(']'),
headers: {
'content-type': 'application/json'
}
})
t.assert.ifError(response.error)
t.assert.strictEqual(response.statusCode, 400)
t.assert.deepStrictEqual(JSON.parse(response.payload.toString()), {
error: 'Bad Request',
code: 'FST_ERR_CTP_INVALID_JSON_BODY',
message: 'Body is not valid JSON but content-type is set to \'application/json\'',
statusCode: 400
})
})
})

109
node_modules/fastify/test/build-certificate.js generated vendored Normal file
View File

@@ -0,0 +1,109 @@
'use strict'
const os = require('node: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)
}
}
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 }

View File

@@ -0,0 +1,36 @@
'use strict'
const { test } = require('node:test')
const fs = require('node:fs')
const path = require('node:path')
const { loadESLint } = require('eslint')
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 Eslint = await loadESLint({ useFlatConfig: true })
const eslint = new Eslint()
const result = await eslint.lintText(code)
// if there are any invalid syntax
// fatal count will be greater than 0
t.assert.strictEqual(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.assert.strictEqual(unifyLineBreak(current), unifyLineBreak(code))
})

14
node_modules/fastify/test/build/version.test.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
'use strict'
const fs = require('node:fs')
const path = require('node:path')
const { test } = require('node: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.assert.strictEqual(fastify.version, json.version)
})

29
node_modules/fastify/test/bundler/README.md generated vendored Normal file
View 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.

View File

@@ -0,0 +1,32 @@
'use strict'
const { test } = require('node:test')
const fastifySuccess = require('./dist/success')
const fastifyFailPlugin = require('./dist/failPlugin')
test('Bundled package should work', (t, done) => {
t.plan(4)
fastifySuccess.ready((err) => {
t.assert.ifError(err)
fastifySuccess.inject(
{
method: 'GET',
url: '/'
},
(error, res) => {
t.assert.ifError(error)
t.assert.strictEqual(res.statusCode, 200)
t.assert.deepStrictEqual(res.json(), { hello: 'world' })
done()
}
)
})
})
test('Bundled package should not work with bad plugin version', (t, done) => {
t.plan(1)
fastifyFailPlugin.ready((err) => {
t.assert.match(err.message, /expected '9.x' fastify version/i)
done()
})
})

10
node_modules/fastify/test/bundler/esbuild/package.json generated vendored Normal file
View 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.25.0"
}
}

View 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

View 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

View File

@@ -0,0 +1,32 @@
'use strict'
const { test } = require('node:test')
const fastifySuccess = require('./dist/success')
const fastifyFailPlugin = require('./dist/failPlugin')
test('Bundled package should work', (t, done) => {
t.plan(4)
fastifySuccess.ready((err) => {
t.assert.ifError(err)
fastifySuccess.inject(
{
method: 'GET',
url: '/'
},
(error, res) => {
t.assert.ifError(error)
t.assert.strictEqual(res.statusCode, 200)
t.assert.deepStrictEqual(res.json(), { hello: 'world' })
done()
}
)
})
})
test('Bundled package should not work with bad plugin version', (t, done) => {
t.plan(1)
fastifyFailPlugin.ready((err) => {
t.assert.match(err.message, /expected '9.x' fastify version/i)
done()
})
})

11
node_modules/fastify/test/bundler/webpack/package.json generated vendored Normal file
View 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"
}
}

View 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

View 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

View 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'
}
}
}

102
node_modules/fastify/test/case-insensitive.test.js generated vendored Normal file
View File

@@ -0,0 +1,102 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('..')
test('case insensitive', async (t) => {
t.plan(3)
const fastify = Fastify({
caseSensitive: false
})
t.after(() => fastify.close())
fastify.get('/foo', (req, reply) => {
reply.send({ hello: 'world' })
})
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(`${fastifyServer}/FOO`)
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.json(), {
hello: 'world'
})
})
test('case insensitive inject', async t => {
t.plan(2)
const fastify = Fastify({
caseSensitive: false
})
t.after(() => fastify.close())
fastify.get('/foo', (req, reply) => {
reply.send({ hello: 'world' })
})
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fastify.inject({
method: 'GET',
url: fastifyServer + '/FOO'
})
t.assert.strictEqual(result.statusCode, 200)
t.assert.deepStrictEqual(result.json(), {
hello: 'world'
})
})
test('case insensitive (parametric)', async (t) => {
t.plan(4)
const fastify = Fastify({
caseSensitive: false
})
t.after(() => fastify.close())
fastify.get('/foo/:param', (req, reply) => {
t.assert.strictEqual(req.params.param, 'bAr')
reply.send({ hello: 'world' })
})
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(`${fastifyServer}/FoO/bAr`, {
method: 'GET'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.json(), {
hello: 'world'
})
})
test('case insensitive (wildcard)', async (t) => {
t.plan(4)
const fastify = Fastify({
caseSensitive: false
})
t.after(() => fastify.close())
fastify.get('/foo/*', (req, reply) => {
t.assert.strictEqual(req.params['*'], 'bAr/baZ')
reply.send({ hello: 'world' })
})
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(`${fastifyServer}/FoO/bAr/baZ`)
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.json(), {
hello: 'world'
})
})

40
node_modules/fastify/test/chainable.test.js generated vendored Normal file
View File

@@ -0,0 +1,40 @@
'use strict'
const { test } = require('node: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.assert.strictEqual(fastify.get('/', opts, noop), fastify)
})
test('chainable - post', t => {
t.plan(1)
t.assert.strictEqual(fastify.post('/', opts, noop), fastify)
})
test('chainable - route', t => {
t.plan(1)
t.assert.strictEqual(fastify.route({
method: 'GET',
url: '/other',
schema: opts.schema,
handler: noop
}), fastify)
})

219
node_modules/fastify/test/check.test.js generated vendored Normal file
View File

@@ -0,0 +1,219 @@
'use strict'
const { test } = require('node:test')
const { S } = require('fluent-json-schema')
const Fastify = require('..')
const BadRequestSchema = S.object()
.prop('statusCode', S.number())
.prop('error', S.string())
.prop('message', S.string())
const InternalServerErrorSchema = S.object()
.prop('statusCode', S.number())
.prop('error', S.string())
.prop('message', S.string())
const NotFoundSchema = S.object()
.prop('statusCode', S.number())
.prop('error', S.string())
.prop('message', S.string())
const options = {
schema: {
body: {
type: 'object',
properties: {
id: { type: 'string' }
}
},
response: {
200: {
type: 'object',
properties: {
id: { type: 'string' }
}
},
400: {
description: 'Bad Request',
content: {
'application/json': {
schema: BadRequestSchema.valueOf()
}
}
},
404: {
description: 'Resource not found',
content: {
'application/json': {
schema: NotFoundSchema.valueOf(),
example: {
statusCode: 404,
error: 'Not Found',
message: 'Not Found'
}
}
}
},
500: {
description: 'Internal Server Error',
content: {
'application/json': {
schema: InternalServerErrorSchema.valueOf(),
example: {
message: 'Internal Server Error'
}
}
}
}
}
}
}
const handler = (request, reply) => {
if (request.body.id === '400') {
return reply.status(400).send({
statusCode: 400,
error: 'Bad Request',
message: 'Custom message',
extra: 'This should not be in the response'
})
}
if (request.body.id === '404') {
return reply.status(404).send({
statusCode: 404,
error: 'Not Found',
message: 'Custom Not Found',
extra: 'This should not be in the response'
})
}
if (request.body.id === '500') {
reply.status(500).send({
statusCode: 500,
error: 'Internal Server Error',
message: 'Custom Internal Server Error',
extra: 'This should not be in the response'
})
}
reply.send({
id: request.body.id,
extra: 'This should not be in the response'
})
}
test('serialize the response for a Bad Request error, as defined on the schema', async t => {
const fastify = Fastify({})
t.after(() => fastify.close())
fastify.post('/', options, handler)
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(fastifyServer, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: '12'
})
t.assert.ok(!result.ok)
t.assert.strictEqual(result.status, 400)
t.assert.deepStrictEqual(await result.json(), {
statusCode: 400,
error: 'Bad Request',
message: 'body must be object'
})
})
// test('serialize the response for a Not Found error, as defined on the schema', t => {
// const fastify = Fastify({})
// t.teardown(fastify.close.bind(fastify))
// fastify.post('/', options, handler)
// fastify.listen({ port: 0 }, err => {
// t.error(err)
// const url = `http://localhost:${fastify.server.address().port}/`
// sget({
// method: 'POST',
// url,
// json: true,
// body: { id: '404' }
// }, (err, response, body) => {
// t.error(err)
// t.equal(response.statusCode, 404)
// t.same(body, {
// statusCode: 404,
// error: 'Not Found',
// message: 'Custom Not Found'
// })
// t.end()
// })
// })
// })
// test('serialize the response for a Internal Server Error error, as defined on the schema', t => {
// const fastify = Fastify({})
// t.teardown(fastify.close.bind(fastify))
// fastify.post('/', options, handler)
// fastify.listen({ port: 0 }, err => {
// t.error(err)
// const url = `http://localhost:${fastify.server.address().port}/`
// sget({
// method: 'POST',
// url,
// json: true,
// body: { id: '500' }
// }, (err, response, body) => {
// t.error(err)
// t.equal(response.statusCode, 500)
// t.same(body, {
// statusCode: 500,
// error: 'Internal Server Error',
// message: 'Custom Internal Server Error'
// })
// t.end()
// })
// })
// })
// test('serialize the success response, as defined on the schema', t => {
// const fastify = Fastify({})
// t.teardown(fastify.close.bind(fastify))
// fastify.post('/', options, handler)
// fastify.listen({ port: 0 }, err => {
// t.error(err)
// const url = `http://localhost:${fastify.server.address().port}/`
// sget({
// method: 'POST',
// url,
// json: true,
// body: { id: 'test' }
// }, (err, response, body) => {
// t.error(err)
// t.equal(response.statusCode, 200)
// t.same(body, {
// id: 'test'
// })
// t.end()
// })
// })
// })

128
node_modules/fastify/test/child-logger-factory.test.js generated vendored Normal file
View File

@@ -0,0 +1,128 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('..')
test('Should accept a custom childLoggerFactory function', (t, done) => {
t.plan(4)
const fastify = Fastify()
fastify.setChildLoggerFactory(function (logger, bindings, opts) {
t.assert.ok(bindings.reqId)
t.assert.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()
})
t.after(() => fastify.close())
fastify.listen({ port: 0 }, err => {
t.assert.ifError(err)
fastify.inject({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port
}, (err, res) => {
t.assert.ifError(err)
done()
})
})
})
test('Should accept a custom childLoggerFactory function as option', (t, done) => {
t.plan(2)
const fastify = Fastify({
childLoggerFactory: 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()
})
t.after(() => fastify.close())
fastify.listen({ port: 0 }, err => {
t.assert.ifError(err)
fastify.inject({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port
}, (err, res) => {
t.assert.ifError(err)
done()
})
})
})
test('req.log should be the instance returned by the factory', (t, done) => {
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.assert.strictEqual(req.log, fastify.log)
req.log.info('log message')
reply.send()
})
t.after(() => fastify.close())
fastify.listen({ port: 0 }, err => {
t.assert.ifError(err)
fastify.inject({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port
}, (err, res) => {
t.assert.ifError(err)
done()
})
})
})
test('should throw error if invalid logger is returned', (t, done) => {
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()
})
t.after(() => fastify.close())
fastify.listen({ port: 0 }, err => {
t.assert.ifError(err)
t.assert.throws(() => {
try {
fastify.inject({
method: 'GET',
url: 'http://localhost:' + fastify.server.address().port
}, (err) => {
t.assert.fail('request should have failed but did not')
t.assert.ifError(err)
done()
})
} finally {
done()
}
}, { code: 'FST_ERR_LOG_INVALID_LOGGER' })
})
})

38
node_modules/fastify/test/client-timeout.test.js generated vendored Normal file
View File

@@ -0,0 +1,38 @@
'use strict'
const { test } = require('node:test')
const fastify = require('..')({ requestTimeout: 5, http: { connectionsCheckingInterval: 1000 } })
const { connect } = require('node:net')
test('requestTimeout should return 408', (t, done) => {
t.plan(1)
t.after(() => {
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.assert.strictEqual(
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}'
)
done()
})
})
})

78
node_modules/fastify/test/close-pipelining.test.js generated vendored Normal file
View File

@@ -0,0 +1,78 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('..')
const { Client } = require('undici')
test('Should return 503 while closing - pipelining', async t => {
const fastify = Fastify({
return503OnClosing: true,
forceCloseConnections: false
})
fastify.get('/', async (req, reply) => {
// Simulate a delay to allow pipelining to kick in
await new Promise(resolve => setTimeout(resolve, 5))
reply.send({ hello: 'world' })
fastify.close()
})
await fastify.listen({ port: 0 })
const instance = new Client('http://localhost:' + fastify.server.address().port, {
pipelining: 2
})
const [firstRequest, secondRequest, thirdRequest] = await Promise.allSettled([
instance.request({ path: '/', method: 'GET', blocking: false }),
instance.request({ path: '/', method: 'GET', blocking: false }),
instance.request({ path: '/', method: 'GET', blocking: false })
])
t.assert.strictEqual(firstRequest.status, 'fulfilled')
t.assert.strictEqual(secondRequest.status, 'fulfilled')
t.assert.strictEqual(firstRequest.value.statusCode, 200)
t.assert.strictEqual(secondRequest.value.statusCode, 200)
t.assert.strictEqual(thirdRequest.status, 'fulfilled')
t.assert.strictEqual(thirdRequest.value.statusCode, 503)
await instance.close()
})
test('Should close the socket abruptly - pipelining - return503OnClosing: false', async t => {
// Since Node v20, we will always invoke server.closeIdleConnections()
// therefore our socket will be closed
const fastify = Fastify({
return503OnClosing: false,
forceCloseConnections: false
})
fastify.get('/', async (req, reply) => {
// Simulate a delay to allow pipelining to kick in
await new Promise(resolve => setTimeout(resolve, 5))
reply.send({ hello: 'world' })
fastify.close()
})
await fastify.listen({ port: 0 })
const instance = new Client('http://localhost:' + fastify.server.address().port, {
pipelining: 1
})
const responses = await Promise.allSettled([
instance.request({ path: '/', method: 'GET', blocking: false }),
instance.request({ path: '/', method: 'GET', blocking: false }),
instance.request({ path: '/', method: 'GET', blocking: false }),
instance.request({ path: '/', method: 'GET', blocking: false })
])
const fulfilled = responses.filter(r => r.status === 'fulfilled')
const rejected = responses.filter(r => r.status === 'rejected')
t.assert.strictEqual(fulfilled.length, 1)
t.assert.strictEqual(rejected.length, 3)
await instance.close()
})

706
node_modules/fastify/test/close.test.js generated vendored Normal file
View File

@@ -0,0 +1,706 @@
'use strict'
const net = require('node:net')
const http = require('node:http')
const { test } = require('node:test')
const Fastify = require('..')
const { Client } = require('undici')
const split = require('split2')
const { sleep } = require('./helper')
test('close callback', (t, testDone) => {
t.plan(7)
const fastify = Fastify()
fastify.addHook('onClose', onClose)
function onClose (instance, done) {
t.assert.ok(typeof fastify === typeof this)
t.assert.ok(typeof fastify === typeof instance)
t.assert.strictEqual(fastify, this)
t.assert.strictEqual(fastify, instance)
done()
}
fastify.listen({ port: 0 }, err => {
t.assert.ifError(err)
fastify.close((err) => {
t.assert.ifError(err)
t.assert.ok('close callback')
testDone()
})
})
})
test('inside register', (t, done) => {
t.plan(5)
const fastify = Fastify()
fastify.register(function (f, opts, done) {
f.addHook('onClose', onClose)
function onClose (instance, done) {
t.assert.ok(instance.prototype === fastify.prototype)
t.assert.strictEqual(instance, f)
done()
}
done()
})
fastify.listen({ port: 0 }, err => {
t.assert.ifError(err)
fastify.close((err) => {
t.assert.ifError(err)
t.assert.ok('close callback')
done()
})
})
})
test('close order', (t, done) => {
t.plan(5)
const fastify = Fastify()
const order = [1, 2, 3]
fastify.register(function (f, opts, done) {
f.addHook('onClose', (instance, done) => {
t.assert.strictEqual(order.shift(), 1)
done()
})
done()
})
fastify.addHook('onClose', (instance, done) => {
t.assert.strictEqual(order.shift(), 2)
done()
})
fastify.listen({ port: 0 }, err => {
t.assert.ifError(err)
fastify.close((err) => {
t.assert.ifError(err)
t.assert.strictEqual(order.shift(), 3)
done()
})
})
})
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.assert.strictEqual(order.shift(), 1)
})
done()
})
fastify.addHook('onClose', () => {
t.assert.strictEqual(order.shift(), 2)
})
await fastify.listen({ port: 0 })
await fastify.close()
t.assert.strictEqual(order.shift(), 3)
})
test('should not throw an error if the server is not listening', (t, done) => {
t.plan(2)
const fastify = Fastify()
fastify.addHook('onClose', onClose)
function onClose (instance, done) {
t.assert.ok(instance.prototype === fastify.prototype)
done()
}
fastify.close((err) => {
t.assert.ifError(err)
done()
})
})
test('onClose should keep the context', (t, done) => {
t.plan(4)
const fastify = Fastify()
fastify.register(plugin)
function plugin (instance, opts, done) {
instance.decorate('test', true)
instance.addHook('onClose', onClose)
t.assert.ok(instance.prototype === fastify.prototype)
function onClose (i, done) {
t.assert.ok(i.test)
t.assert.strictEqual(i, instance)
done()
}
done()
}
fastify.close((err) => {
t.assert.ifError(err)
done()
})
})
test('Should return error while closing (promise) - injection', (t, done) => {
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.assert.ifError(err)
t.assert.strictEqual(res.statusCode, 200)
fastify.close()
process.nextTick(() => {
fastify.inject({
method: 'GET',
url: '/'
}).catch(err => {
t.assert.ok(err)
t.assert.strictEqual(err.code, 'FST_ERR_REOPENED_CLOSE_SERVER')
done()
})
}, 100)
})
})
test('Should return error while closing (callback) - injection', (t, done) => {
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.assert.ifError(err)
t.assert.strictEqual(res.statusCode, 200)
fastify.close()
setTimeout(() => {
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.assert.ok(err)
t.assert.strictEqual(err.code, 'FST_ERR_REOPENED_CLOSE_SERVER')
done()
})
}, 100)
})
})
test('Current opened connection should NOT continue to work after closing and return "connection: close" header - return503OnClosing: false', (t, done) => {
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.assert.ifError(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.assert.ok(true)
done()
})
client.once('data', data => {
t.assert.match(data.toString(), /Connection:\s*keep-alive/i)
t.assert.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, done) => {
t.plan(3)
const fastify = Fastify({ forceCloseConnections: false })
fastify.get('/', (req, reply) => {
fastify.close()
setTimeout(() => {
reply.send({ hello: 'world' })
}, 250)
})
fastify.listen({ port: 0 }, async err => {
t.assert.ifError(err)
const instance = new Client('http://localhost:' + fastify.server.address().port)
let response = await instance.request({ path: '/', method: 'GET' })
t.assert.strictEqual(response.statusCode, 200)
response = await instance.request({ path: '/', method: 'GET' })
t.assert.strictEqual(response.statusCode, 503)
done()
})
})
test('rejected incoming connections should be logged', (t, done) => {
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.assert.ifError(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.assert.ok(messages.find(message => message.msg.includes('request aborted')))
done()
})
})
})
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.assert.ok(err)
t.assert.strictEqual(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.assert.strictEqual(err.code, 'FST_ERR_REOPENED_CLOSE_SERVER')
t.assert.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, done) => {
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.assert.ifError(err)
const client = new Client(
'http://localhost:' + fastify.server.address().port,
{ keepAliveTimeout: 1 * 60 * 1000 }
)
client.request({ path: '/', method: 'GET' }, (err, response) => {
t.assert.ifError(err)
t.assert.strictEqual(client.closed, false)
fastify.close((err) => {
t.assert.ifError(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.assert.strictEqual(client.closed, false)
done()
})
})
})
})
test('shutsdown while keep-alive connections are active (non-async, idle, native)', { skip: noSupport }, (t, done) => {
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.assert.ifError(err)
const client = new Client(
'http://localhost:' + fastify.server.address().port,
{ keepAliveTimeout: 1 * 60 * 1000 }
)
client.request({ path: '/', method: 'GET' }, (err, response) => {
t.assert.ifError(err)
t.assert.strictEqual(client.closed, false)
fastify.close((err) => {
t.assert.ifError(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.assert.strictEqual(client.closed, false)
done()
})
})
})
})
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.assert.deepEqual(order, expectedOrder)
if (err) t.assert.ifError(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.assert.ifError(err))
.then(json => {
t.assert.deepEqual(json, expectedPayload, 'should payload match')
t.assert.ok(!client.closed, 'should client not be closed')
}, err => t.assert.ifError(err))
}
await new Promise((resolve, reject) => {
setTimeout(() => {
fastify.close(err => {
order.push(2)
t.assert.deepEqual(order, expectedOrder)
if (err) t.assert.ifError(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.assert.ifError(err))
.then(json => {
t.assert.deepEqual(json, expectedPayload, 'should payload match')
t.assert.ok(!client.closed, 'should client not be closed')
}, err => t.assert.ifError(err))
}
await new Promise((resolve, reject) => {
setTimeout(() => {
fastify.close(err => {
order.push(2)
t.assert.deepEqual(order, expectedOrder)
if (err) t.assert.ifError(err)
else resolve()
})
}, 2000)
})
})
test('shutsdown while keep-alive connections are active (non-async, custom)', (t, done) => {
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.assert.ifError(err)
const client = new Client(
'http://localhost:' + fastify.server.address().port,
{ keepAliveTimeout: 1 * 60 * 1000 }
)
client.request({ path: '/', method: 'GET' }, (err, response) => {
t.assert.ifError(err)
t.assert.strictEqual(client.closed, false)
fastify.close((err) => {
t.assert.ifError(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.assert.strictEqual(client.closed, false)
done()
})
})
})
})
test('preClose callback', (t, done) => {
t.plan(5)
const fastify = Fastify()
fastify.addHook('onClose', onClose)
let preCloseCalled = false
function onClose (instance, done) {
t.assert.strictEqual(preCloseCalled, true)
done()
}
fastify.addHook('preClose', preClose)
function preClose (done) {
t.assert.ok(typeof this === typeof fastify)
preCloseCalled = true
done()
}
fastify.listen({ port: 0 }, err => {
t.assert.ifError(err)
fastify.close((err) => {
t.assert.ifError(err)
t.assert.ok('close callback')
done()
})
})
})
test('preClose async', async t => {
t.plan(2)
const fastify = Fastify()
fastify.addHook('onClose', onClose)
let preCloseCalled = false
async function onClose () {
t.assert.strictEqual(preCloseCalled, true)
}
fastify.addHook('preClose', preClose)
async function preClose () {
preCloseCalled = true
t.assert.ok(typeof this === typeof fastify)
}
await fastify.listen({ port: 0 })
await fastify.close()
})
test('preClose execution order', (t, done) => {
t.plan(4)
const fastify = Fastify()
const order = []
fastify.addHook('onClose', onClose)
function onClose (instance, done) {
t.assert.deepStrictEqual(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.assert.ifError(err)
fastify.close((err) => {
t.assert.ifError(err)
t.assert.ok('close callback')
done()
})
})
})

47
node_modules/fastify/test/conditional-pino.test.js generated vendored Normal file
View File

@@ -0,0 +1,47 @@
'use strict'
const { test } = require('node:test')
test("pino is not require'd if logger is not passed", t => {
t.plan(1)
const fastify = require('..')
fastify()
t.assert.strictEqual(require.cache[require.resolve('pino')], undefined)
})
test("pino is require'd if logger is passed", t => {
t.plan(1)
const fastify = require('..')
fastify({
logger: true
})
t.assert.notStrictEqual(require.cache[require.resolve('pino')], undefined)
})
test("pino is require'd if loggerInstance is passed", t => {
t.plan(1)
const fastify = require('..')
const loggerInstance = {
fatal: (msg) => { },
error: (msg) => { },
warn: (msg) => { },
info: (msg) => { },
debug: (msg) => { },
trace: (msg) => { },
child: () => loggerInstance
}
fastify({
loggerInstance
})
t.assert.notStrictEqual(require.cache[require.resolve('pino')], undefined)
})

42
node_modules/fastify/test/connection-timeout.test.js generated vendored Normal file
View File

@@ -0,0 +1,42 @@
'use strict'
const Fastify = require('..')
const http = require('node:http')
const { test } = require('node:test')
test('connectionTimeout', async t => {
t.plan(6)
try {
Fastify({ connectionTimeout: 1.3 })
t.assert.fail('option must be an integer')
} catch (err) {
t.assert.ok(err)
}
try {
Fastify({ connectionTimeout: [] })
t.assert.fail('option must be an integer')
} catch (err) {
t.assert.ok(err)
}
const httpServer = Fastify({ connectionTimeout: 1 }).server
t.assert.strictEqual(httpServer.timeout, 1)
const httpsServer = Fastify({ connectionTimeout: 2, https: {} }).server
t.assert.strictEqual(httpsServer.timeout, 2)
const http2Server = Fastify({ connectionTimeout: 3, http2: true }).server
t.assert.strictEqual(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.assert.strictEqual(customServer.timeout, 5)
})

1138
node_modules/fastify/test/constrained-routes.test.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

174
node_modules/fastify/test/content-length.test.js generated vendored Normal file
View File

@@ -0,0 +1,174 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('..')
test('default 413 with bodyLimit option', async (t) => {
t.plan(3)
const fastify = Fastify({
bodyLimit: 10
})
fastify.post('/', function (req, reply) {
reply.send({ hello: 'world' })
})
const response = await fastify.inject({
method: 'POST',
url: '/',
body: {
text: '12345678901234567890123456789012345678901234567890'
}
})
t.assert.strictEqual(response.statusCode, 413)
t.assert.strictEqual(response.headers['content-type'], 'application/json; charset=utf-8')
t.assert.deepStrictEqual(JSON.parse(response.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', async (t) => {
t.plan(3)
const fastify = Fastify()
fastify.post('/', function (req, reply) {
reply.send({ hello: 'world' })
})
const response = await fastify.inject({
method: 'POST',
url: '/',
headers: {
'content-length': 20
},
body: {
text: '12345678901234567890123456789012345678901234567890'
}
})
t.assert.strictEqual(response.statusCode, 400)
t.assert.strictEqual(response.headers['content-type'], 'application/json; charset=utf-8')
t.assert.deepStrictEqual(JSON.parse(response.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', async (t) => {
t.plan(3)
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)
})
const response = await fastify.inject({
method: 'POST',
url: '/',
body: {
text: '12345678901234567890123456789012345678901234567890'
}
})
t.assert.strictEqual(response.statusCode, 413)
t.assert.strictEqual(response.headers['content-type'], 'application/json; charset=utf-8')
t.assert.deepStrictEqual(JSON.parse(response.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', async (t) => {
t.plan(3)
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)
})
const response = await fastify.inject({
method: 'POST',
url: '/',
headers: {
'content-length': 20
},
body: {
text: '12345678901234567890123456789012345678901234567890'
}
})
t.assert.strictEqual(response.statusCode, 400)
t.assert.strictEqual(response.headers['content-type'], 'application/json; charset=utf-8')
t.assert.deepStrictEqual(JSON.parse(response.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', async (t) => {
const fastify = Fastify()
fastify.get('/', async () => {
const error = new Error('MY_ERROR_MESSAGE')
error.headers = {
'content-length': 2
}
throw error
})
const response = await fastify.inject({
method: 'GET',
path: '/'
})
t.assert.strictEqual(response.headers['content-length'], '' + response.rawPayload.length)
})
test('#2543 - wrong content-length with errorHandler', async (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
})
const response = await fastify.inject({
method: 'GET',
path: '/'
})
t.assert.strictEqual(response.statusCode, 500)
t.assert.strictEqual(response.headers['content-length'], '' + response.rawPayload.length)
t.assert.deepStrictEqual(JSON.parse(response.payload), { message: 'longer than 2 bytes' })
})

732
node_modules/fastify/test/content-parser.test.js generated vendored Normal file
View File

@@ -0,0 +1,732 @@
'use strict'
const { test } = require('node: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', async t => {
await t.test('should know about internal parsers', (t, done) => {
t.plan(5)
const fastify = Fastify()
fastify.ready(err => {
t.assert.ifError(err)
t.assert.ok(fastify.hasContentTypeParser('application/json'))
t.assert.ok(fastify.hasContentTypeParser('text/plain'))
t.assert.ok(fastify.hasContentTypeParser(' text/plain '))
t.assert.ok(!fastify.hasContentTypeParser('application/jsoff'))
done()
})
})
await t.test('should only work with string and RegExp', t => {
t.plan(8)
const fastify = Fastify()
fastify.addContentTypeParser(/^image\/.*/, first)
fastify.addContentTypeParser(/^application\/.+\+xml/, first)
fastify.addContentTypeParser('image/gif', first)
t.assert.ok(fastify.hasContentTypeParser('application/json'))
t.assert.ok(fastify.hasContentTypeParser(/^image\/.*/))
t.assert.ok(fastify.hasContentTypeParser(/^application\/.+\+xml/))
t.assert.ok(fastify.hasContentTypeParser('image/gif'))
t.assert.ok(!fastify.hasContentTypeParser(/^image\/.+\+xml/))
t.assert.ok(!fastify.hasContentTypeParser('image/png'))
t.assert.ok(!fastify.hasContentTypeParser('*'))
t.assert.throws(
() => fastify.hasContentTypeParser(123),
FST_ERR_CTP_INVALID_TYPE
)
})
})
test('getParser', async t => {
await t.test('should return matching parser', t => {
t.plan(6)
const fastify = Fastify()
fastify.addContentTypeParser(/^image\/.*/, first)
fastify.addContentTypeParser(/^application\/.+\+xml/, second)
fastify.addContentTypeParser('text/html', third)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('application/t+xml').fn, second)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('image/png').fn, first)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('text/html').fn, third)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('text/html; charset=utf-8').fn, third)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('text/html ; charset=utf-8').fn, third)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('text/htmlINVALID')?.fn, undefined)
})
await t.test('should return matching parser with caching /1', t => {
t.plan(6)
const fastify = Fastify()
fastify.addContentTypeParser('text/html', first)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('text/html').fn, first)
t.assert.strictEqual(fastify[keys.kContentTypeParser].cache.size, 0)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('text/html ').fn, first)
t.assert.strictEqual(fastify[keys.kContentTypeParser].cache.size, 1)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('text/html ').fn, first)
t.assert.strictEqual(fastify[keys.kContentTypeParser].cache.size, 1)
})
await t.test('should return matching parser with caching /2', t => {
t.plan(8)
const fastify = Fastify()
fastify.addContentTypeParser('text/html', first)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('text/html').fn, first)
t.assert.strictEqual(fastify[keys.kContentTypeParser].cache.size, 0)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('text/HTML').fn, first)
t.assert.strictEqual(fastify[keys.kContentTypeParser].cache.size, 1)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('TEXT/html').fn, first)
t.assert.strictEqual(fastify[keys.kContentTypeParser].cache.size, 2)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('TEXT/html').fn, first)
t.assert.strictEqual(fastify[keys.kContentTypeParser].cache.size, 2)
})
await t.test('should return matching parser with caching /3', t => {
t.plan(6)
const fastify = Fastify()
fastify.addContentTypeParser(/^text\/html(;\s*charset=[^;]+)?$/, first)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('text/html').fn, first)
t.assert.strictEqual(fastify[keys.kContentTypeParser].cache.size, 1)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('text/html;charset=utf-8').fn, first)
t.assert.strictEqual(fastify[keys.kContentTypeParser].cache.size, 2)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('text/html;charset=utf-8').fn, first)
t.assert.strictEqual(fastify[keys.kContentTypeParser].cache.size, 2)
})
await t.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.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('image/gif').fn, second)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('image/png').fn, first)
})
await t.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.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('image/gif').fn, first)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('text/html').fn, second)
t.assert.strictEqual(fastify[keys.kContentTypeParser].getParser('text').fn, first)
})
await t.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.assert.ok(!fastify[keys.kContentTypeParser].getParser('application/xml'))
t.assert.ok(!fastify[keys.kContentTypeParser].getParser('weirdType/'))
})
})
test('existingParser', async t => {
await 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.assert.ok(!fastify[keys.kContentTypeParser].existingParser('*'))
fastify.addContentTypeParser('*', first)
t.assert.ok(!fastify[keys.kContentTypeParser].existingParser('*'))
})
await t.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.assert.throws(
() => fastify.addContentTypeParser('application/json', first),
FST_ERR_CTP_ALREADY_PRESENT
)
t.assert.throws(
() => fastify.addContentTypeParser('text/plain', first),
FST_ERR_CTP_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.assert.ok(contentTypeParser.existingParser(/^image\/.*/))
t.assert.ok(contentTypeParser.existingParser('text/html'))
t.assert.ok(contentTypeParser.existingParser(/^application\/.+\+xml/))
t.assert.ok(!contentTypeParser.existingParser('application/json'))
t.assert.ok(!contentTypeParser.existingParser('text/plain'))
t.assert.ok(!contentTypeParser.existingParser('image/png'))
t.assert.ok(!contentTypeParser.existingParser(/^application\/.+\+json/))
})
test('add', async t => {
await t.test('should only accept string and RegExp', t => {
t.plan(4)
const fastify = Fastify()
const contentTypeParser = fastify[keys.kContentTypeParser]
t.assert.ifError(contentTypeParser.add('test', {}, first))
t.assert.ifError(contentTypeParser.add(/test/, {}, first))
t.assert.throws(
() => contentTypeParser.add({}, {}, first),
FST_ERR_CTP_INVALID_TYPE,
'The content type should be a string or a RegExp'
)
t.assert.throws(
() => contentTypeParser.add(1, {}, first),
FST_ERR_CTP_INVALID_TYPE,
'The content type should be a string or a RegExp'
)
})
await t.test('should set "*" as parser that catches all', t => {
t.plan(1)
const fastify = Fastify()
const contentTypeParser = fastify[keys.kContentTypeParser]
contentTypeParser.add('*', {}, first)
t.assert.strictEqual(contentTypeParser.customParsers.get('').fn, first)
})
await t.test('should lowercase contentTypeParser name', async t => {
t.plan(1)
const fastify = Fastify()
fastify.addContentTypeParser('text/html', function (req, done) {
done()
})
try {
fastify.addContentTypeParser('TEXT/html', function (req, done) {
done()
})
} catch (err) {
t.assert.strictEqual(err.message, FST_ERR_CTP_ALREADY_PRESENT('text/html').message)
}
})
await t.test('should trim contentTypeParser name', async t => {
t.plan(1)
const fastify = Fastify()
fastify.addContentTypeParser('text/html', function (req, done) {
done()
})
try {
fastify.addContentTypeParser(' text/html', function (req, done) {
done()
})
} catch (err) {
t.assert.strictEqual(err.message, FST_ERR_CTP_ALREADY_PRESENT('text/html').message)
}
})
})
test('non-Error thrown from content parser is properly handled', (t, done) => {
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.assert.strictEqual(err, throwable)
res.send(payload)
})
fastify.inject({
method: 'POST',
url: '/',
headers: { 'Content-Type': 'text/test' },
body: 'some text'
}, (err, res) => {
t.assert.ifError(err)
t.assert.strictEqual(res.payload, payload)
done()
})
})
test('Error thrown 415 from content type is null and make post request to server', (t, done) => {
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.assert.ifError(err)
t.assert.strictEqual(res.statusCode, 415)
t.assert.strictEqual(JSON.parse(res.body).message, errMsg)
done()
})
})
test('remove', async t => {
await t.test('should remove default parser', t => {
t.plan(6)
const fastify = Fastify()
const contentTypeParser = fastify[keys.kContentTypeParser]
t.assert.ok(contentTypeParser.remove('application/json'))
t.assert.ok(!contentTypeParser.customParsers['application/json'])
t.assert.ok(!contentTypeParser.parserList.find(parser => parser === 'application/json'))
t.assert.ok(contentTypeParser.remove(' text/plain '))
t.assert.ok(!contentTypeParser.customParsers['text/plain'])
t.assert.ok(!contentTypeParser.parserList.find(parser => parser === 'text/plain'))
})
await t.test('should remove RegExp parser', t => {
t.plan(3)
const fastify = Fastify()
fastify.addContentTypeParser(/^text\/*/, first)
const contentTypeParser = fastify[keys.kContentTypeParser]
t.assert.ok(contentTypeParser.remove(/^text\/*/))
t.assert.ok(!contentTypeParser.customParsers[/^text\/*/])
t.assert.ok(!contentTypeParser.parserRegExpList.find(parser => parser.toString() === /^text\/*/.toString()))
})
await t.test('should throw an error if content type is neither string nor RegExp', t => {
t.plan(1)
const fastify = Fastify()
t.assert.throws(() => fastify[keys.kContentTypeParser].remove(12), FST_ERR_CTP_INVALID_TYPE)
})
await t.test('should return false if content type does not exist', t => {
t.plan(1)
const fastify = Fastify()
t.assert.ok(!fastify[keys.kContentTypeParser].remove('image/png'))
})
await t.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.assert.ok(!contentTypeParser.remove('image/png'))
t.assert.strictEqual(contentTypeParser.customParsers.size, 2)
})
})
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.assert.strictEqual(contentTypeParser.cache.size, 0)
t.assert.strictEqual(contentTypeParser.parserList.length, 0)
t.assert.strictEqual(contentTypeParser.parserRegExpList.length, 0)
t.assert.strictEqual(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.assert.strictEqual(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.assert.strictEqual(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.assert.strictEqual(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.assert.ok('should be called')
done(null, body)
})
fastify.addContentTypeParser('application/json', function (request, body, done) {
t.assert.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('Warning against improper content-type - regexp', async t => {
await t.test('improper regex - text plain', (t, done) => {
t.plan(2)
const fastify = Fastify()
process.on('warning', onWarning)
function onWarning (warning) {
t.assert.strictEqual(warning.name, 'FastifySecurity')
t.assert.strictEqual(warning.code, 'FSTSEC001')
done()
}
t.after(() => process.removeListener('warning', onWarning))
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser(/text\/plain/, function (request, body, done) {
done(null, body)
})
})
await t.test('improper regex - application json', (t, done) => {
t.plan(2)
const fastify = Fastify()
process.on('warning', onWarning)
function onWarning (warning) {
t.assert.strictEqual(warning.name, 'FastifySecurity')
t.assert.strictEqual(warning.code, 'FSTSEC001')
done()
}
t.after(() => process.removeListener('warning', onWarning))
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser(/application\/json/, function (request, body, done) {
done(null, 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.assert.fail('shouldn\'t be called')
done(null, body)
})
fastify.addContentTypeParser('application/json; charset=utf8', function (request, body, done) {
t.assert.ok('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 - regexp', async t => {
t.plan(1)
const fastify = Fastify()
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser(/application\/json; charset=utf8/, function (request, body, done) {
t.assert.ok('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.assert.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.assert.strictEqual(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.assert.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.assert.strictEqual(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.assert.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.assert.strictEqual(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.assert.strictEqual(statusCode, 200)
t.assert.strictEqual(headers['content-type'], 'image/jpeg')
t.assert.strictEqual(payload, 'jpeg')
}
{
const { payload, headers, statusCode } = await fastify.inject({
method: 'POST',
path: '/',
payload: 'png',
headers: { 'content-type': 'image/png' }
})
t.assert.strictEqual(statusCode, 200)
t.assert.strictEqual(headers['content-type'], 'image/png')
t.assert.strictEqual(payload, 'png')
}
})
test('edge case content-type - ;', async t => {
t.plan(1)
const fastify = Fastify()
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser(';', function (request, body, done) {
t.assert.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.assert.ok('end')
})

42
node_modules/fastify/test/content-type.test.js generated vendored Normal file
View File

@@ -0,0 +1,42 @@
'use strict'
const { test } = require('node: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.assert.strictEqual(error.message, 'kaboom')
t.assert.strictEqual(reply.hasHeader('content-type'), false)
reply.code(400).send({ foo: 'bar' })
})
fastify.addHook('onSend', async function (request, reply, payload) {
count++
t.assert.strictEqual(typeof payload, 'string')
switch (count) {
case 1: {
// should guess the correct content-type based on payload
t.assert.strictEqual(reply.getHeader('content-type'), 'text/plain; charset=utf-8')
throw Error('kaboom')
}
case 2: {
// should guess the correct content-type based on payload
t.assert.strictEqual(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.assert.strictEqual(statusCode, 400)
t.assert.strictEqual(body, JSON.stringify({ foo: 'bar' }))
})

164
node_modules/fastify/test/context-config.test.js generated vendored Normal file
View File

@@ -0,0 +1,164 @@
'use strict'
const { test } = require('node: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', async t => {
t.plan(6)
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
})
let response = await fastify.inject({
method: 'GET',
url: '/route'
})
t.assert.strictEqual(response.statusCode, 200)
t.assert.deepStrictEqual(response.json(), Object.assign({ url: '/route', method: 'GET' }, schema.config))
response = await fastify.inject({
method: 'GET',
url: '/route'
})
t.assert.strictEqual(response.statusCode, 200)
t.assert.deepStrictEqual(response.json(), Object.assign({ url: '/route', method: 'GET' }, schema.config))
response = await fastify.inject({
method: 'GET',
url: '/no-config'
})
t.assert.strictEqual(response.statusCode, 200)
t.assert.deepStrictEqual(response.json(), { url: '/no-config', method: 'GET' })
})
test('config with exposeHeadRoutes', async t => {
t.plan(6)
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
})
let response = await fastify.inject({
method: 'GET',
url: '/get'
})
t.assert.strictEqual(response.statusCode, 200)
t.assert.deepStrictEqual(response.json(), Object.assign({ url: '/get', method: 'GET' }, schema.config))
response = await fastify.inject({
method: 'GET',
url: '/route'
})
t.assert.strictEqual(response.statusCode, 200)
t.assert.deepStrictEqual(response.json(), Object.assign({ url: '/route', method: 'GET' }, schema.config))
response = await fastify.inject({
method: 'GET',
url: '/no-config'
})
t.assert.strictEqual(response.statusCode, 200)
t.assert.deepStrictEqual(response.json(), { url: '/no-config', method: 'GET' })
})
test('config without exposeHeadRoutes', async t => {
t.plan(6)
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
})
let response = await fastify.inject({
method: 'GET',
url: '/get'
})
t.assert.strictEqual(response.statusCode, 200)
t.assert.deepStrictEqual(response.json(), Object.assign({ url: '/get', method: 'GET' }, schema.config))
response = await fastify.inject({
method: 'GET',
url: '/route'
})
t.assert.strictEqual(response.statusCode, 200)
t.assert.deepStrictEqual(response.json(), Object.assign({ url: '/route', method: 'GET' }, schema.config))
response = await fastify.inject({
method: 'GET',
url: '/no-config'
})
t.assert.strictEqual(response.statusCode, 200)
t.assert.deepStrictEqual(response.json(), { url: '/no-config', method: 'GET' })
})

118
node_modules/fastify/test/custom-http-server.test.js generated vendored Normal file
View File

@@ -0,0 +1,118 @@
'use strict'
const { test } = require('node:test')
const http = require('node:http')
const dns = require('node:dns').promises
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(5)
const fastify = Fastify({
serverFactory: (handler, opts) => {
t.assert.ok(opts.serverFactory, 'it is called once for localhost')
const server = http.createServer((req, res) => {
req.custom = true
handler(req, res)
})
return server
}
})
t.after(() => fastify.close())
fastify.get('/', (req, reply) => {
t.assert.ok(req.raw.custom)
reply.send({ hello: 'world' })
})
await fastify.listen({ port: 0 })
const response = await fetch('http://localhost:' + fastify.server.address().port, {
method: 'GET'
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
})
test('Should not allow forceCloseConnection=idle if the server does not support closeIdleConnections', t => {
t.plan(1)
t.assert.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.after(() => new Promise(resolve => server.close(resolve)))
const app = Fastify({
serverFactory: () => server
})
await t.assert.doesNotReject(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.assert.strictEqual(server.listening, true)
await fastify.close()
t.assert.strictEqual(server.listening, true)
t.assert.deepStrictEqual(server.address(), address)
t.assert.deepStrictEqual(fastify.addresses(), [address])
await new Promise((resolve, reject) => {
server.close((err) => {
if (err) {
return reject(err)
}
resolve()
})
})
t.assert.strictEqual(server.listening, false)
t.assert.deepStrictEqual(server.address(), null)
})
}
setup()

59
node_modules/fastify/test/custom-parser-async.test.js generated vendored Normal file
View File

@@ -0,0 +1,59 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('../fastify')
process.removeAllListeners('warning')
test('contentTypeParser should add a custom async parser', async t => {
t.plan(2)
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
})
t.after(() => fastify.close())
const fastifyServer = await fastify.listen({ port: 0 })
await t.test('in POST', async t => {
t.plan(3)
const result = await fetch(fastifyServer, {
method: 'POST',
headers: {
'Content-Type': 'application/jsoff'
},
body: '{"hello":"world"}'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.json(), { hello: 'world' })
})
await t.test('in OPTIONS', async t => {
t.plan(3)
const result = await fetch(fastifyServer, {
method: 'OPTIONS',
headers: {
'Content-Type': 'application/jsoff'
},
body: '{"hello":"world"}'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.json(), { hello: 'world' })
})
})

701
node_modules/fastify/test/custom-parser.0.test.js generated vendored Normal file
View File

@@ -0,0 +1,701 @@
'use strict'
const fs = require('node:fs')
const { test } = require('node:test')
const Fastify = require('../fastify')
const jsonParser = require('fast-json-body')
const { plainTextParser } = require('./helper')
process.removeAllListeners('warning')
test('contentTypeParser method should exist', t => {
t.plan(1)
const fastify = Fastify()
t.assert.ok(fastify.addContentTypeParser)
})
test('contentTypeParser should add a custom parser', async (t) => {
t.plan(2)
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)
})
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
await t.test('in POST', async (t) => {
t.plan(3)
const result = await fetch(fastifyServer, {
method: 'POST',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/jsoff'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.json(), { hello: 'world' })
})
await t.test('in OPTIONS', async (t) => {
t.plan(2)
const result = await fetch(fastifyServer, {
method: 'OPTIONS',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/jsoff'
}
})
t.assert.strictEqual(result.status, 200)
const body = await result.text()
t.assert.strictEqual(body, JSON.stringify({ hello: 'world' }))
})
})
test('contentTypeParser should handle multiple custom parsers', async (t) => {
t.plan(6)
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)
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result1 = await fetch(fastifyServer, {
method: 'POST',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/jsoff'
}
})
t.assert.ok(result1.ok)
t.assert.strictEqual(result1.status, 200)
t.assert.deepStrictEqual(await result1.json(), { hello: 'world' })
const result2 = await fetch(fastifyServer + '/hello', {
method: 'POST',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/ffosj'
}
})
t.assert.ok(result2.ok)
t.assert.strictEqual(result2.status, 200)
t.assert.deepStrictEqual(await result2.json(), { hello: 'world' })
})
test('contentTypeParser should handle an array of custom contentTypes', async (t) => {
t.plan(6)
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)
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result1 = await fetch(fastifyServer, {
method: 'POST',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/jsoff'
}
})
t.assert.ok(result1.ok)
t.assert.strictEqual(result1.status, 200)
t.assert.deepStrictEqual(await result1.json(), { hello: 'world' })
const result2 = await fetch(fastifyServer + '/hello', {
method: 'POST',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/ffosj'
}
})
t.assert.ok(result2.ok)
t.assert.strictEqual(result2.status, 200)
t.assert.deepStrictEqual(await result2.json(), { hello: 'world' })
})
test('contentTypeParser should handle errors', async (t) => {
t.plan(1)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.addContentTypeParser('application/jsoff', function (req, payload, done) {
done(new Error('kaboom!'), {})
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/jsoff'
}
})
t.assert.strictEqual(result.status, 500)
})
test('contentTypeParser should support encapsulation', (t, testDone) => {
t.plan(6)
const fastify = Fastify()
fastify.register((instance, opts, done) => {
instance.addContentTypeParser('application/jsoff', () => {})
t.assert.ok(instance.hasContentTypeParser('application/jsoff'))
instance.register((instance, opts, done) => {
instance.addContentTypeParser('application/ffosj', () => {})
t.assert.ok(instance.hasContentTypeParser('application/jsoff'))
t.assert.ok(instance.hasContentTypeParser('application/ffosj'))
done()
})
done()
})
fastify.ready(err => {
t.assert.ifError(err)
t.assert.ok(!fastify.hasContentTypeParser('application/jsoff'))
t.assert.ok(!fastify.hasContentTypeParser('application/ffosj'))
testDone()
})
})
test('contentTypeParser should support encapsulation, second try', async (t) => {
t.plan(2)
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()
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/jsoff'
}
})
t.assert.strictEqual(result.status, 200)
const body = await result.text()
t.assert.strictEqual(body, JSON.stringify({ hello: 'world' }))
})
test('contentTypeParser shouldn\'t support request with undefined "Content-Type"', async (t) => {
t.plan(1)
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)
})
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: 'unknown content type!',
headers: {
'Content-Type': undefined
}
})
t.assert.strictEqual(result.status, 415)
})
test('the content type should be a string or RegExp', t => {
t.plan(2)
const fastify = Fastify()
try {
fastify.addContentTypeParser(null, () => {})
t.assert.fail()
} catch (err) {
t.assert.strictEqual(err.code, 'FST_ERR_CTP_INVALID_TYPE')
t.assert.strictEqual(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.assert.fail()
} catch (err) {
t.assert.strictEqual(err.code, 'FST_ERR_CTP_EMPTY_TYPE')
t.assert.strictEqual(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.assert.fail()
} catch (err) {
t.assert.strictEqual(err.code, 'FST_ERR_CTP_INVALID_HANDLER')
t.assert.strictEqual(err.message, 'The content type handler should be a function')
}
})
test('catch all content type parser', async (t) => {
t.plan(6)
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)
})
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result1 = await fetch(fastifyServer, {
method: 'POST',
body: 'hello',
headers: {
'Content-Type': 'application/jsoff'
}
})
t.assert.ok(result1.ok)
t.assert.strictEqual(result1.status, 200)
t.assert.strictEqual(await result1.text(), 'hello')
const result2 = await fetch(fastifyServer, {
method: 'POST',
body: 'hello',
headers: {
'Content-Type': 'very-weird-content-type'
}
})
t.assert.ok(result2.ok)
t.assert.strictEqual(result2.status, 200)
t.assert.strictEqual(await result2.text(), 'hello')
})
test('catch all content type parser should not interfere with other conte type parsers', async (t) => {
t.plan(6)
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)
})
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result1 = await fetch(fastifyServer, {
method: 'POST',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/jsoff'
}
})
t.assert.ok(result1.ok)
t.assert.strictEqual(result1.status, 200)
t.assert.deepStrictEqual(await result1.json(), { hello: 'world' })
const result2 = await fetch(fastifyServer, {
method: 'POST',
body: 'hello',
headers: {
'Content-Type': 'very-weird-content-type'
}
})
t.assert.ok(result2.ok)
t.assert.strictEqual(result2.status, 200)
t.assert.strictEqual(await result2.text(), 'hello')
})
// Issue 492 https://github.com/fastify/fastify/issues/492
test('\'*\' catch undefined Content-Type requests', async (t) => {
t.plan(3)
const fastify = Fastify()
t.after(() => fastify.close())
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)
})
const fastifyServer = await fastify.listen({ port: 0 })
const fileStream = fs.createReadStream(__filename)
const result = await fetch(fastifyServer + '/', {
method: 'POST',
body: fileStream,
duplex: 'half'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(await result.text(), fs.readFileSync(__filename).toString())
})
test('cannot add custom parser after binding', (t, testDone) => {
t.plan(2)
const fastify = Fastify()
t.after(() => fastify.close())
fastify.post('/', (req, res) => {
res.type('text/plain').send(req.body)
})
fastify.listen({ port: 0 }, function (err) {
t.assert.ifError(err)
try {
fastify.addContentTypeParser('*', () => {})
t.assert.fail()
} catch (e) {
t.assert.ok(true)
testDone()
}
})
})
test('Can override the default json parser', async (t) => {
t.plan(3)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.addContentTypeParser('application/json', function (req, payload, done) {
t.assert.ok('called')
jsonParser(payload, function (err, body) {
done(err, body)
})
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/json'
}
})
t.assert.strictEqual(result.status, 200)
const body = await result.text()
t.assert.strictEqual(body, '{"hello":"world"}')
})
test('Can override the default plain text parser', async (t) => {
t.plan(3)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.addContentTypeParser('text/plain', function (req, payload, done) {
t.assert.ok('called')
plainTextParser(payload, function (err, body) {
done(err, body)
})
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: 'hello world',
headers: {
'Content-Type': 'text/plain'
}
})
t.assert.strictEqual(result.status, 200)
const body = await result.text()
t.assert.strictEqual(body, 'hello world')
})
test('Can override the default json parser in a plugin', async (t) => {
t.plan(3)
const fastify = Fastify()
fastify.register((instance, opts, done) => {
instance.addContentTypeParser('application/json', function (req, payload, done) {
t.assert.ok('called')
jsonParser(payload, function (err, body) {
done(err, body)
})
})
instance.post('/', (req, reply) => {
reply.send(req.body)
})
done()
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/json'
}
})
t.assert.strictEqual(result.status, 200)
const body = await result.text()
t.assert.strictEqual(body, '{"hello":"world"}')
})
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.assert.ok('called')
jsonParser(payload, function (err, body) {
done(err, body)
})
})
} catch (err) {
t.assert.strictEqual(err.code, 'FST_ERR_CTP_ALREADY_PRESENT')
t.assert.strictEqual(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.assert.ok('called')
plainTextParser(payload, function (err, body) {
done(err, body)
})
})
} catch (err) {
t.assert.strictEqual(err.code, 'FST_ERR_CTP_ALREADY_PRESENT')
t.assert.strictEqual(err.message, 'Content type parser \'text/plain\' already present.')
}
})
test('Should get the body as string', async (t) => {
t.plan(4)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.addContentTypeParser('application/json', { parseAs: 'string' }, function (req, body, done) {
t.assert.ok('called')
t.assert.ok(typeof body === 'string')
try {
const json = JSON.parse(body)
done(null, json)
} catch (err) {
err.statusCode = 400
done(err, undefined)
}
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/json'
}
})
t.assert.strictEqual(result.status, 200)
const body = await result.text()
t.assert.strictEqual(body, '{"hello":"world"}')
})
test('Should return defined body with no custom parser defined and content type = \'text/plain\'', async (t) => {
t.plan(2)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: 'hello world',
headers: {
'Content-Type': 'text/plain'
}
})
t.assert.strictEqual(result.status, 200)
const body = await result.text()
t.assert.strictEqual(body, 'hello world')
})
test('Should have typeof body object with no custom parser defined, no body defined and content type = \'text/plain\'', async (t) => {
t.plan(3)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
t.after(() => fastify.close())
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(fastifyServer, {
method: 'POST',
headers: {
'Content-Type': 'text/plain'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(await result.text(), '')
})

301
node_modules/fastify/test/custom-parser.1.test.js generated vendored Normal file
View File

@@ -0,0 +1,301 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('../fastify')
const jsonParser = require('fast-json-body')
process.removeAllListeners('warning')
test('Should have typeof body object with no custom parser defined, null body and content type = \'text/plain\'', async (t) => {
t.plan(3)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: null,
headers: {
'Content-Type': 'text/plain'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(await result.text(), '')
})
test('Should have typeof body object with no custom parser defined, undefined body and content type = \'text/plain\'', async (t) => {
t.plan(3)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: undefined,
headers: {
'Content-Type': 'text/plain'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(await result.text(), '')
})
test('Should get the body as string /1', async (t) => {
t.plan(4)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.addContentTypeParser('text/plain', { parseAs: 'string' }, function (req, body, done) {
t.assert.ok('called')
t.assert.ok(typeof body === 'string')
try {
const plainText = body
done(null, plainText)
} catch (err) {
err.statusCode = 400
done(err, undefined)
}
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: 'hello world',
headers: {
'Content-Type': 'text/plain'
}
})
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(await result.text(), 'hello world')
})
test('Should get the body as string /2', async (t) => {
t.plan(4)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.addContentTypeParser('text/plain/test', { parseAs: 'string' }, function (req, body, done) {
t.assert.ok('called')
t.assert.ok(typeof body === 'string')
try {
const plainText = body
done(null, plainText)
} catch (err) {
err.statusCode = 400
done(err, undefined)
}
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: 'hello world',
headers: {
'Content-Type': ' text/plain/test '
}
})
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(await result.text(), 'hello world')
})
test('Should get the body as buffer', async (t) => {
t.plan(4)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.addContentTypeParser('application/json', { parseAs: 'buffer' }, function (req, body, done) {
t.assert.ok('called')
t.assert.ok(body instanceof Buffer)
try {
const json = JSON.parse(body)
done(null, json)
} catch (err) {
err.statusCode = 400
done(err, undefined)
}
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/json'
}
})
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(await result.text(), '{"hello":"world"}')
})
test('Should get the body as buffer', async (t) => {
t.plan(4)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.addContentTypeParser('text/plain', { parseAs: 'buffer' }, function (req, body, done) {
t.assert.ok('called')
t.assert.ok(body instanceof Buffer)
try {
const plainText = body
done(null, plainText)
} catch (err) {
err.statusCode = 400
done(err, undefined)
}
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: 'hello world',
headers: {
'Content-Type': 'text/plain'
}
})
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(await result.text(), 'hello world')
})
test('Should parse empty bodies as a string', async (t) => {
t.plan(8)
const fastify = Fastify()
fastify.addContentTypeParser('text/plain', { parseAs: 'string' }, (req, body, done) => {
t.assert.strictEqual(body, '')
done(null, body)
})
fastify.route({
method: ['POST', 'DELETE'],
url: '/',
handler (request, reply) {
reply.send(request.body)
}
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const postResult = await fetch(fastifyServer, {
method: 'POST',
body: '',
headers: {
'Content-Type': 'text/plain'
}
})
t.assert.ok(postResult.ok)
t.assert.strictEqual(postResult.status, 200)
t.assert.strictEqual(await postResult.text(), '')
const deleteResult = await fetch(fastifyServer, {
method: 'DELETE',
body: '',
headers: {
'Content-Type': 'text/plain',
'Content-Length': '0'
}
})
t.assert.ok(deleteResult.ok)
t.assert.strictEqual(deleteResult.status, 200)
t.assert.strictEqual(await deleteResult.text(), '')
})
test('Should parse empty bodies as a buffer', async (t) => {
t.plan(4)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.addContentTypeParser('text/plain', { parseAs: 'buffer' }, function (req, body, done) {
t.assert.ok(body instanceof Buffer)
t.assert.strictEqual(body.length, 0)
done(null, body)
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: '',
headers: {
'Content-Type': 'text/plain'
}
})
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual((await result.arrayBuffer()).byteLength, 0)
})
test('The charset should not interfere with the content type handling', async (t) => {
t.plan(4)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.addContentTypeParser('application/json', function (req, payload, done) {
t.assert.ok('called')
jsonParser(payload, function (err, body) {
done(err, body)
})
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer, {
method: 'POST',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/json; charset=utf-8'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(await result.text(), '{"hello":"world"}')
})

91
node_modules/fastify/test/custom-parser.2.test.js generated vendored Normal file
View File

@@ -0,0 +1,91 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('..')
process.removeAllListeners('warning')
test('Wrong parseAs parameter', t => {
t.plan(2)
const fastify = Fastify()
try {
fastify.addContentTypeParser('application/json', { parseAs: 'fireworks' }, () => {})
t.assert.fail('should throw')
} catch (err) {
t.assert.strictEqual(err.code, 'FST_ERR_CTP_INVALID_PARSE_TYPE')
t.assert.strictEqual(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', async (t) => {
t.plan(2)
const fastify = Fastify()
t.after(() => fastify.close())
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.addContentTypeParser(
'x/foo',
{ parseAs: 'string', bodyLimit: 5 },
function (req, body, done) {
t.assert.fail('should not be invoked')
done()
}
)
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(fastifyServer, {
method: 'POST',
body: '1234567890',
headers: {
'Content-Type': 'x/foo'
}
})
t.assert.ok(!result.ok)
t.assert.deepStrictEqual(await result.json(), {
statusCode: 413,
code: 'FST_ERR_CTP_BODY_TOO_LARGE',
error: 'Payload Too Large',
message: 'Request body is too large'
})
})
test('route bodyLimit should take precedence over a custom parser bodyLimit', async (t) => {
t.plan(2)
const fastify = Fastify()
t.after(() => 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.assert.fail('should not be invoked')
done()
}
)
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(fastifyServer, {
method: 'POST',
body: '1234567890',
headers: { 'Content-Type': 'x/foo' }
})
t.assert.ok(!result.ok)
t.assert.deepStrictEqual(await result.json(), {
statusCode: 413,
code: 'FST_ERR_CTP_BODY_TOO_LARGE',
error: 'Payload Too Large',
message: 'Request body is too large'
})
})

208
node_modules/fastify/test/custom-parser.3.test.js generated vendored Normal file
View File

@@ -0,0 +1,208 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('..')
const jsonParser = require('fast-json-body')
process.removeAllListeners('warning')
test('should be able to use default parser for extra content type', async t => {
t.plan(3)
const fastify = Fastify()
t.after(() => fastify.close())
fastify.post('/', (request, reply) => {
reply.send(request.body)
})
fastify.addContentTypeParser('text/json', { parseAs: 'string' }, fastify.getDefaultJsonParser('ignore', 'ignore'))
const fastifyServer = await fastify.listen({ port: 0 })
const response = await fetch(fastifyServer, {
method: 'POST',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'text/json'
}
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
t.assert.deepStrictEqual(await response.json(), { hello: 'world' })
})
test('contentTypeParser should add a custom parser with RegExp value', async (t) => {
const fastify = Fastify()
t.after(() => fastify.close())
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)
})
})
const fastifyServer = await fastify.listen({ port: 0 })
await t.test('in POST', async t => {
t.plan(3)
const response = await fetch(fastifyServer, {
method: 'POST',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/vnd.test+json'
}
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.deepStrictEqual(body.toString(), JSON.stringify({ hello: 'world' }))
})
await t.test('in OPTIONS', async t => {
t.plan(3)
const response = await fetch(fastifyServer, {
method: 'OPTIONS',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'weird/content-type+json'
}
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.deepStrictEqual(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.after(() => fastify.close())
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.assert.strictEqual(response.statusCode, 200)
t.assert.deepStrictEqual(response.payload.toString(), '{"hello":"world"}')
}
{
const response = await fastify.inject({
method: 'POST',
url: '/',
body: '{"hello":"world"}',
headers: {
'Content-Type': 'application/test+xml'
}
})
t.assert.strictEqual(response.statusCode, 200)
t.assert.deepStrictEqual(response.payload.toString(), 'xml')
}
await fastify.inject({
method: 'POST',
path: '/',
payload: 'abcdefg',
headers: {
'Content-Type': 'application/+myExtension'
}
}).then((response) => {
t.assert.strictEqual(response.statusCode, 200)
t.assert.deepStrictEqual(response.payload.toString(), 'abcdefgmyExtension')
}).catch((err) => {
t.assert.ifError(err)
})
})
test('catch all content type parser should not interfere with content type parser', async t => {
t.plan(9)
const fastify = Fastify()
t.after(() => fastify.close())
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')
})
})
const fastifyServer = await fastify.listen({ port: 0 })
const assertions = [
{ body: '{"myKey":"myValue"}', contentType: 'application/json', expected: JSON.stringify({ myKey: 'myValue' }) },
{ body: 'body', contentType: 'very-weird-content-type', expected: 'body' },
{ body: 'my text', contentType: 'text/html', expected: 'my texthtml' }
]
for (const { body, contentType, expected } of assertions) {
const response = await fetch(fastifyServer, {
method: 'POST',
body,
headers: {
'Content-Type': contentType
}
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
t.assert.deepStrictEqual(await response.text(), expected)
}
})

218
node_modules/fastify/test/custom-parser.4.test.js generated vendored Normal file
View File

@@ -0,0 +1,218 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('../fastify')
const jsonParser = require('fast-json-body')
process.removeAllListeners('warning')
test('should prefer string content types over RegExp ones', async (t) => {
t.plan(6)
const fastify = Fastify()
t.after(() => { fastify.close() })
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)
})
})
const fastifyServer = await fastify.listen({ port: 0 })
const result1 = await fetch(fastifyServer, {
method: 'POST',
body: '{"k1":"myValue", "k2": "myValue"}',
headers: {
'Content-Type': 'application/json'
}
})
t.assert.ok(result1.ok)
t.assert.strictEqual(result1.status, 200)
t.assert.equal(await result1.text(), JSON.stringify({ k1: 'myValue', k2: 'myValue' }))
const result2 = await fetch(fastifyServer, {
method: 'POST',
body: 'javascript',
headers: {
'Content-Type': 'application/javascript'
}
})
t.assert.ok(result2.ok)
t.assert.strictEqual(result2.status, 200)
t.assert.equal(await result2.text(), 'javascript')
})
test('removeContentTypeParser should support arrays of content types to remove', async (t) => {
t.plan(7)
const fastify = Fastify()
t.after(() => fastify.close())
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)
})
const fastifyServer = await fastify.listen({ port: 0 })
const result1 = await fetch(fastifyServer, {
method: 'POST',
body: '<?xml version="1.0">',
headers: {
'Content-Type': 'application/xml'
}
})
t.assert.ok(result1.ok)
t.assert.strictEqual(result1.status, 200)
t.assert.equal(await result1.text(), 'xml')
const result2 = await fetch(fastifyServer, {
method: 'POST',
body: '',
headers: {
'Content-Type': 'image/png'
}
})
t.assert.ok(!result2.ok)
t.assert.strictEqual(result2.status, 415)
const result3 = await fetch(fastifyServer, {
method: 'POST',
body: '{test: "test"}',
headers: {
'Content-Type': 'application/json'
}
})
t.assert.ok(!result3.ok)
t.assert.strictEqual(result3.status, 415)
})
test('removeContentTypeParser should support encapsulation', async (t) => {
t.plan(5)
const fastify = Fastify()
t.after(() => fastify.close())
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()
})
const fastifyServer = await fastify.listen({ port: 0 })
const result1 = await fetch(fastifyServer + '/encapsulated', {
method: 'POST',
body: '<?xml version="1.0">',
headers: {
'Content-Type': 'application/xml'
}
})
t.assert.ok(!result1.ok)
t.assert.strictEqual(result1.status, 415)
const result2 = await fetch(fastifyServer, {
method: 'POST',
body: '<?xml version="1.0">',
headers: {
'Content-Type': 'application/xml'
}
})
t.assert.ok(result2.ok)
t.assert.strictEqual(result2.status, 200)
t.assert.equal(await result2.text(), 'xml')
})
test('removeAllContentTypeParsers should support encapsulation', async (t) => {
t.plan(5)
const fastify = Fastify()
t.after(() => fastify.close())
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()
})
const fastifyServer = await fastify.listen({ port: 0 })
const result1 = await fetch(fastifyServer + '/encapsulated', {
method: 'POST',
body: '{}',
headers: {
'Content-Type': 'application/json'
}
})
t.assert.ok(!result1.ok)
t.assert.strictEqual(result1.status, 415)
const result2 = await fetch(fastifyServer, {
method: 'POST',
body: '{"test":1}',
headers: {
'Content-Type': 'application/json'
}
})
t.assert.ok(result2.ok)
t.assert.strictEqual(result2.status, 200)
t.assert.equal(JSON.parse(await result2.text()).test, 1)
})

130
node_modules/fastify/test/custom-parser.5.test.js generated vendored Normal file
View File

@@ -0,0 +1,130 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('../fastify')
const jsonParser = require('fast-json-body')
const { plainTextParser } = require('./helper')
process.removeAllListeners('warning')
test('cannot remove all content type parsers after binding', async (t) => {
t.plan(1)
const fastify = Fastify()
t.after(() => fastify.close())
await fastify.listen({ port: 0 })
t.assert.throws(() => fastify.removeAllContentTypeParsers())
})
test('cannot remove content type parsers after binding', async (t) => {
t.plan(1)
const fastify = Fastify()
t.after(() => fastify.close())
await fastify.listen({ port: 0 })
t.assert.throws(() => fastify.removeContentTypeParser('application/json'))
})
test('should be able to override the default json parser after removeAllContentTypeParsers', async (t) => {
t.plan(4)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser('application/json', function (req, payload, done) {
t.assert.ok('called')
jsonParser(payload, function (err, body) {
done(err, body)
})
})
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(fastifyServer, {
method: 'POST',
body: JSON.stringify({ hello: 'world' }),
headers: {
'Content-Type': 'application/json'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.text(), JSON.stringify({ hello: 'world' }))
await fastify.close()
})
test('should be able to override the default plain text parser after removeAllContentTypeParsers', async (t) => {
t.plan(4)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser('text/plain', function (req, payload, done) {
t.assert.ok('called')
plainTextParser(payload, function (err, body) {
done(err, body)
})
})
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(fastifyServer, {
method: 'POST',
body: 'hello world',
headers: {
'Content-Type': 'text/plain'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(await result.text(), 'hello world')
await fastify.close()
})
test('should be able to add a custom content type parser after removeAllContentTypeParsers', async (t) => {
t.plan(4)
const fastify = Fastify()
fastify.post('/', (req, reply) => {
reply.send(req.body)
})
fastify.removeAllContentTypeParsers()
fastify.addContentTypeParser('application/jsoff', function (req, payload, done) {
t.assert.ok('called')
jsonParser(payload, function (err, body) {
done(err, body)
})
})
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(fastifyServer, {
method: 'POST',
body: JSON.stringify({ hello: 'world' }),
headers: {
'Content-Type': 'application/jsoff'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.text(), JSON.stringify({ hello: 'world' }))
await fastify.close()
})

View File

@@ -0,0 +1,129 @@
'use strict'
const { test } = require('node:test')
const querystring = require('node:querystring')
const Fastify = require('..')
test('Custom querystring parser', async t => {
t.plan(7)
const fastify = Fastify({
querystringParser: function (str) {
t.assert.strictEqual(str, 'foo=bar&baz=faz')
return querystring.parse(str)
}
})
fastify.get('/', (req, reply) => {
t.assert.deepEqual(req.query, {
foo: 'bar',
baz: 'faz'
})
reply.send({ hello: 'world' })
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(`${fastifyServer}?foo=bar&baz=faz`)
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
const injectResponse = await fastify.inject({
method: 'GET',
url: `${fastifyServer}?foo=bar&baz=faz`
})
t.assert.strictEqual(injectResponse.statusCode, 200)
})
test('Custom querystring parser should be called also if there is nothing to parse', async t => {
t.plan(7)
const fastify = Fastify({
querystringParser: function (str) {
t.assert.strictEqual(str, '')
return querystring.parse(str)
}
})
fastify.get('/', (req, reply) => {
t.assert.deepEqual(req.query, {})
reply.send({ hello: 'world' })
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(fastifyServer)
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
const injectResponse = await fastify.inject({
method: 'GET',
url: fastifyServer
})
t.assert.strictEqual(injectResponse.statusCode, 200)
})
test('Querystring without value', async t => {
t.plan(7)
const fastify = Fastify({
querystringParser: function (str) {
t.assert.strictEqual(str, 'foo')
return querystring.parse(str)
}
})
fastify.get('/', (req, reply) => {
t.assert.deepEqual(req.query, { foo: '' })
reply.send({ hello: 'world' })
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => fastify.close())
const result = await fetch(`${fastifyServer}?foo`)
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
const injectResponse = await fastify.inject({
method: 'GET',
url: `${fastifyServer}?foo`
})
t.assert.strictEqual(injectResponse.statusCode, 200)
})
test('Custom querystring parser should be a function', t => {
t.plan(1)
try {
Fastify({
querystringParser: 10
})
t.assert.fail('Should throw')
} catch (err) {
t.assert.strictEqual(
err.message,
"querystringParser option should be a function, instead got 'number'"
)
}
})
test('Custom querystring parser should be a function', t => {
t.plan(1)
try {
Fastify({
routerOptions: {
querystringParser: 10
}
})
t.fail('Should throw')
} catch (err) {
t.assert.equal(
err.message,
"querystringParser option should be a function, instead got 'number'"
)
}
})

View File

@@ -0,0 +1,30 @@
'use strict'
/* eslint no-prototype-builtins: 0 */
const { test } = require('node:test')
const Fastify = require('..')
const fp = require('fastify-plugin')
test('plugin namespace', async t => {
t.plan(2)
const app = Fastify()
await app.register(async function plugin (app, opts) {
app.decorate('utility', function () {
return 'utility'
})
app.get('/', function (req, reply) {
// ! here the plugin would use app.utility()
// ! the plugin does not know about the namespace
reply.send({ utility: app.utility() })
})
}, { namepace: 'foo' })
// ! but outside the plugin the decorator would be app.foo.utility()
t.assert.ok(app.foo.utility)
const res = await app.inject('/')
t.assert.deepStrictEqual(res.json(), { utility: 'utility' })
})

1330
node_modules/fastify/test/decorator.test.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

344
node_modules/fastify/test/delete.test.js generated vendored Normal file
View File

@@ -0,0 +1,344 @@
'use strict'
const { test } = require('node:test')
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, done) => {
t.plan(1)
try {
fastify.delete('/', schema, function (req, reply) {
reply.code(200).send({ hello: 'world' })
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
} finally {
done()
}
})
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.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('shorthand - delete, querystring schema', t => {
t.plan(1)
try {
fastify.delete('/query', querySchema, function (req, reply) {
reply.send(req.query)
})
t.assert.ok(true)
} catch (e) {
t.assert.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.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('missing schema - delete', t => {
t.plan(1)
try {
fastify.delete('/missing', function (req, reply) {
reply.code(200).send({ hello: 'world' })
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('body - delete', t => {
t.plan(1)
try {
fastify.delete('/body', bodySchema, function (req, reply) {
reply.send(req.body)
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('delete tests', async t => {
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
await t.test('shorthand - request delete', async t => {
t.plan(4)
const response = await fetch(fastifyServer, {
method: 'DELETE'
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.strictEqual(response.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
})
await t.test('shorthand - request delete params schema', async t => {
t.plan(4)
const response = await fetch(fastifyServer + '/params/world/123', {
method: 'DELETE'
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.strictEqual(response.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), { foo: 'world', test: 123 })
})
await t.test('shorthand - request delete params schema error', async t => {
t.plan(3)
const response = await fetch(fastifyServer + '/params/world/string', {
method: 'DELETE'
})
t.assert.ok(!response.ok)
t.assert.strictEqual(response.status, 400)
t.assert.deepStrictEqual(await response.json(), {
error: 'Bad Request',
code: 'FST_ERR_VALIDATION',
message: 'params/test must be integer',
statusCode: 400
})
})
await t.test('shorthand - request delete headers schema', async t => {
t.plan(4)
const response = await fetch(fastifyServer + '/headers', {
method: 'DELETE',
headers: {
'x-test': '1'
}
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.strictEqual(response.headers.get('content-length'), '' + body.length)
t.assert.strictEqual(JSON.parse(body)['x-test'], 1)
})
await t.test('shorthand - request delete headers schema error', async t => {
t.plan(3)
const response = await fetch(fastifyServer + '/headers', {
method: 'DELETE',
headers: {
'x-test': 'abc'
}
})
t.assert.ok(!response.ok)
t.assert.strictEqual(response.status, 400)
const body = await response.text()
t.assert.deepStrictEqual(JSON.parse(body), {
error: 'Bad Request',
code: 'FST_ERR_VALIDATION',
message: 'headers/x-test must be number',
statusCode: 400
})
})
await t.test('shorthand - request delete querystring schema', async t => {
t.plan(4)
const response = await fetch(fastifyServer + '/query?hello=123', {
method: 'DELETE'
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.strictEqual(response.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), { hello: 123 })
})
await t.test('shorthand - request delete querystring schema error', async t => {
t.plan(3)
const response = await fetch(fastifyServer + '/query?hello=world', {
method: 'DELETE'
})
t.assert.ok(!response.ok)
t.assert.strictEqual(response.status, 400)
const body = await response.text()
t.assert.deepStrictEqual(JSON.parse(body), {
error: 'Bad Request',
code: 'FST_ERR_VALIDATION',
message: 'querystring/hello must be integer',
statusCode: 400
})
})
await t.test('shorthand - request delete missing schema', async t => {
t.plan(4)
const response = await fetch(fastifyServer + '/missing', {
method: 'DELETE'
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.strictEqual(response.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
})
await t.test('shorthand - delete with body', async t => {
t.plan(3)
const response = await fetch(fastifyServer + '/body', {
method: 'DELETE',
body: JSON.stringify({ hello: 'world' }),
headers: {
'Content-Type': 'application/json'
}
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.json()
t.assert.deepStrictEqual(body, { hello: 'world' })
})
})
test('shorthand - delete with application/json Content-Type header and null body', (t, done) => {
t.plan(4)
const fastify = require('..')()
fastify.delete('/', {}, (req, reply) => {
t.assert.strictEqual(req.body, null)
reply.send(req.body)
})
fastify.inject({
method: 'DELETE',
url: '/',
headers: { 'Content-Type': 'application/json' },
body: 'null'
}, (err, response) => {
t.assert.ifError(err)
t.assert.strictEqual(response.statusCode, 200)
t.assert.strictEqual(response.payload.toString(), 'null')
done()
})
})
// https://github.com/fastify/fastify/issues/936
// Skip this test because this is an invalid request
test('shorthand - delete with application/json Content-Type header and without body', { skip: 'https://github.com/fastify/fastify/pull/5419' }, t => {
t.plan(4)
const fastify = require('..')()
fastify.delete('/', {}, (req, reply) => {
t.assert.strictEqual(req.body, undefined)
reply.send(req.body)
})
fastify.inject({
method: 'DELETE',
url: '/',
headers: { 'Content-Type': 'application/json' },
body: null
}, (err, response) => {
t.assert.ifError(err)
t.assert.strictEqual(response.statusCode, 200)
t.assert.strictEqual(response.payload.toString(), '')
})
})

View File

@@ -0,0 +1,49 @@
'use strict'
const { test } = require('node:test')
const diagnostics = require('node:diagnostics_channel')
const Fastify = require('../..')
const Request = require('../../lib/request')
const Reply = require('../../lib/reply')
test('diagnostics channel sync events fire in expected order', async t => {
t.plan(9)
let callOrder = 0
let firstEncounteredMessage
diagnostics.subscribe('tracing:fastify.request.handler:start', (msg) => {
t.assert.strictEqual(callOrder++, 0)
firstEncounteredMessage = msg
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
})
diagnostics.subscribe('tracing:fastify.request.handler:end', (msg) => {
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
t.assert.strictEqual(callOrder++, 1)
t.assert.strictEqual(msg, firstEncounteredMessage)
})
diagnostics.subscribe('tracing:fastify.request.handler:error', (msg) => {
t.assert.fail('should not trigger error channel')
})
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
handler: function (req, reply) {
reply.callNotFound()
}
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
const response = await fetch(fastifyServer, {
method: 'GET'
})
t.assert.ok(!response.ok)
t.assert.strictEqual(response.status, 404)
})

View File

@@ -0,0 +1,65 @@
'use strict'
const diagnostics = require('node:diagnostics_channel')
const { test } = require('node:test')
const Fastify = require('../..')
const Request = require('../../lib/request')
const Reply = require('../../lib/reply')
test('diagnostics channel async events fire in expected order', async t => {
t.plan(19)
let callOrder = 0
let firstEncounteredMessage
diagnostics.subscribe('tracing:fastify.request.handler:start', (msg) => {
t.assert.strictEqual(callOrder++, 0)
firstEncounteredMessage = msg
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
})
diagnostics.subscribe('tracing:fastify.request.handler:end', (msg) => {
t.assert.strictEqual(callOrder++, 1)
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
t.assert.strictEqual(msg, firstEncounteredMessage)
t.assert.strictEqual(msg.async, true)
})
diagnostics.subscribe('tracing:fastify.request.handler:asyncStart', (msg) => {
t.assert.strictEqual(callOrder++, 2)
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
t.assert.strictEqual(msg, firstEncounteredMessage)
})
diagnostics.subscribe('tracing:fastify.request.handler:asyncEnd', (msg) => {
t.assert.strictEqual(callOrder++, 3)
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
t.assert.strictEqual(msg, firstEncounteredMessage)
})
diagnostics.subscribe('tracing:fastify.request.handler:error', (msg) => {
t.assert.fail('should not trigger error channel')
})
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
handler: async function (req, reply) {
setImmediate(() => reply.send({ hello: 'world' }))
return reply
}
})
t.after(() => { fastify.close() })
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(fastifyServer + '/')
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.json(), { hello: 'world' })
})

View File

@@ -0,0 +1,64 @@
'use strict'
const { test } = require('node:test')
const diagnostics = require('node:diagnostics_channel')
const Fastify = require('../..')
const Request = require('../../lib/request')
const Reply = require('../../lib/reply')
test('diagnostics channel async events fire in expected order', async t => {
t.plan(18)
let callOrder = 0
let firstEncounteredMessage
diagnostics.subscribe('tracing:fastify.request.handler:start', (msg) => {
t.assert.strictEqual(callOrder++, 0)
firstEncounteredMessage = msg
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
})
diagnostics.subscribe('tracing:fastify.request.handler:end', (msg) => {
t.assert.strictEqual(callOrder++, 1)
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
t.assert.strictEqual(msg, firstEncounteredMessage)
})
diagnostics.subscribe('tracing:fastify.request.handler:asyncStart', (msg) => {
t.assert.strictEqual(callOrder++, 2)
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
t.assert.strictEqual(msg, firstEncounteredMessage)
})
diagnostics.subscribe('tracing:fastify.request.handler:asyncEnd', (msg) => {
t.assert.strictEqual(callOrder++, 3)
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
t.assert.strictEqual(msg, firstEncounteredMessage)
})
diagnostics.subscribe('tracing:fastify.request.handler:error', (msg) => {
t.assert.fail('should not trigger error channel')
})
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
handler: async function (req, reply) {
return { hello: 'world' }
}
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
const response = await fetch(fastifyServer)
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
})

View File

@@ -0,0 +1,35 @@
'use strict'
const diagnostics = require('node:diagnostics_channel')
const { test } = require('node:test')
require('../../lib/hooks').onSendHookRunner = function Stub () {}
const Request = require('../../lib/request')
const Reply = require('../../lib/reply')
const symbols = require('../../lib/symbols.js')
const { preHandlerCallback } = require('../../lib/handleRequest')[Symbol.for('internals')]
test('diagnostics channel handles an error before calling context handler', t => {
t.plan(3)
let callOrder = 0
diagnostics.subscribe('tracing:fastify.request.handler:start', (msg) => {
t.assert.strictEqual(callOrder++, 0)
})
diagnostics.subscribe('tracing:fastify.request.handler:error', (msg) => {
t.assert.strictEqual(callOrder++, 1)
t.assert.strictEqual(msg.error.message, 'oh no')
})
const error = new Error('oh no')
const request = new Request()
const reply = new Reply({}, request)
request[symbols.kRouteContext] = {
config: {
url: '/foo',
method: 'GET'
}
}
preHandlerCallback(error, request, reply)
})

View File

@@ -0,0 +1,53 @@
'use strict'
const { test } = require('node:test')
const diagnostics = require('node:diagnostics_channel')
const Fastify = require('../..')
const Request = require('../../lib/request')
const Reply = require('../../lib/reply')
test('diagnostics channel events report on errors', async t => {
t.plan(14)
let callOrder = 0
let firstEncounteredMessage
diagnostics.subscribe('tracing:fastify.request.handler:start', (msg) => {
t.assert.strictEqual(callOrder++, 0)
firstEncounteredMessage = msg
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
})
diagnostics.subscribe('tracing:fastify.request.handler:end', (msg) => {
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
t.assert.strictEqual(callOrder++, 2)
t.assert.strictEqual(msg, firstEncounteredMessage)
})
diagnostics.subscribe('tracing:fastify.request.handler:error', (msg) => {
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
t.assert.ok(msg.error instanceof Error)
t.assert.strictEqual(callOrder++, 1)
t.assert.strictEqual(msg.error.message, 'borked')
})
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
handler: function (req, reply) {
throw new Error('borked')
}
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
const response = await fetch(fastifyServer, {
method: 'GET'
})
t.assert.ok(!response.ok)
t.assert.strictEqual(response.status, 500)
})

View File

@@ -0,0 +1,39 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('../..')
const statusCodes = require('node:http').STATUS_CODES
const diagnostics = require('node:diagnostics_channel')
test('Error.status property support', (t, done) => {
t.plan(4)
const fastify = Fastify()
t.after(() => fastify.close())
const err = new Error('winter is coming')
err.status = 418
diagnostics.subscribe('tracing:fastify.request.handler:error', (msg) => {
t.assert.strictEqual(msg.error.message, 'winter is coming')
})
fastify.get('/', () => {
return Promise.reject(err)
})
fastify.inject({
method: 'GET',
url: '/'
}, (error, res) => {
t.assert.ifError(error)
t.assert.strictEqual(res.statusCode, 418)
t.assert.deepStrictEqual(
{
error: statusCodes['418'],
message: err.message,
statusCode: 418
},
JSON.parse(res.payload)
)
done()
})
})

View File

@@ -0,0 +1,50 @@
'use strict'
const { test } = require('node:test')
const proxyquire = require('proxyquire')
test('diagnostics_channel when present and subscribers', t => {
t.plan(3)
let fastifyInHook
const diagnostics = {
channel (name) {
t.assert.strictEqual(name, 'fastify.initialization')
return {
hasSubscribers: true,
publish (event) {
t.assert.ok(event.fastify)
fastifyInHook = event.fastify
}
}
},
'@noCallThru': true
}
const fastify = proxyquire('../../fastify', {
'node:diagnostics_channel': diagnostics
})()
t.assert.strictEqual(fastifyInHook, fastify)
})
test('diagnostics_channel when present and no subscribers', t => {
t.plan(1)
const diagnostics = {
channel (name) {
t.assert.strictEqual(name, 'fastify.initialization')
return {
hasSubscribers: false,
publish () {
t.assert.fail('publish should not be called')
}
}
},
'@noCallThru': true
}
proxyquire('../../fastify', {
'node:diagnostics_channel': diagnostics
})()
})

View File

@@ -0,0 +1,49 @@
'use strict'
const { test } = require('node:test')
const diagnostics = require('node:diagnostics_channel')
const Fastify = require('../..')
const Request = require('../../lib/request')
const Reply = require('../../lib/reply')
test('diagnostics channel sync events fire in expected order', async t => {
t.plan(10)
let callOrder = 0
let firstEncounteredMessage
diagnostics.subscribe('tracing:fastify.request.handler:start', (msg) => {
t.assert.strictEqual(callOrder++, 0)
firstEncounteredMessage = msg
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
})
diagnostics.subscribe('tracing:fastify.request.handler:end', (msg) => {
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
t.assert.strictEqual(callOrder++, 1)
t.assert.strictEqual(msg, firstEncounteredMessage)
})
diagnostics.subscribe('tracing:fastify.request.handler:error', (msg) => {
t.assert.fail('should not trigger error channel')
})
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
handler: function (req, reply) {
setImmediate(() => reply.send({ hello: 'world' }))
}
})
t.after(() => { fastify.close() })
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(fastifyServer + '/')
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.json(), { hello: 'world' })
})

View File

@@ -0,0 +1,51 @@
'use strict'
const { test } = require('node:test')
const diagnostics = require('node:diagnostics_channel')
const Fastify = require('../..')
const Request = require('../../lib/request')
const Reply = require('../../lib/reply')
test('diagnostics channel sync events fire in expected order', async t => {
t.plan(10)
let callOrder = 0
let firstEncounteredMessage
diagnostics.subscribe('tracing:fastify.request.handler:start', (msg) => {
t.assert.strictEqual(callOrder++, 0)
firstEncounteredMessage = msg
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
})
diagnostics.subscribe('tracing:fastify.request.handler:end', (msg) => {
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
t.assert.strictEqual(callOrder++, 1)
t.assert.strictEqual(msg, firstEncounteredMessage)
})
diagnostics.subscribe('tracing:fastify.request.handler:error', (msg) => {
t.assert.fail('should not trigger error channel')
})
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/',
handler: function (req, reply) {
reply.send({ hello: 'world' })
}
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
const response = await fetch(fastifyServer, {
method: 'GET'
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
})

View File

@@ -0,0 +1,54 @@
'use strict'
const { test } = require('node:test')
const diagnostics = require('node:diagnostics_channel')
const Fastify = require('../..')
const Request = require('../../lib/request')
const Reply = require('../../lib/reply')
test('diagnostics channel sync events fire in expected order', async t => {
t.plan(13)
let callOrder = 0
let firstEncounteredMessage
diagnostics.subscribe('tracing:fastify.request.handler:start', (msg) => {
t.assert.strictEqual(callOrder++, 0)
firstEncounteredMessage = msg
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
t.assert.ok(msg.route)
t.assert.strictEqual(msg.route.url, '/:id')
t.assert.strictEqual(msg.route.method, 'GET')
})
diagnostics.subscribe('tracing:fastify.request.handler:end', (msg) => {
t.assert.ok(msg.request instanceof Request)
t.assert.ok(msg.reply instanceof Reply)
t.assert.strictEqual(callOrder++, 1)
t.assert.strictEqual(msg, firstEncounteredMessage)
})
diagnostics.subscribe('tracing:fastify.request.handler:error', (msg) => {
t.assert.fail('should not trigger error channel')
})
const fastify = Fastify()
fastify.route({
method: 'GET',
url: '/:id',
handler: function (req, reply) {
return { hello: 'world' }
}
})
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
const response = await fetch(fastifyServer + '/7', {
method: 'GET'
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
})

View File

@@ -0,0 +1,69 @@
'use strict'
const { test } = require('node:test')
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.assert.strictEqual(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.assert.strictEqual(message, 'global')
}
return child
})
fastify.get('/not-encapsulated', async (req) => {
req.log.globalLog('global')
})
const res1 = await fastify.inject('/encapsulated')
t.assert.strictEqual(res1.statusCode, 200)
const res2 = await fastify.inject('/not-encapsulated')
t.assert.strictEqual(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.assert.strictEqual(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.assert.strictEqual(res1.statusCode, 200)
const res2 = await fastify.inject('/not-encapsulated-2')
t.assert.strictEqual(res2.statusCode, 200)
})

View File

@@ -0,0 +1,237 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('..')
// Because of how error handlers wrap things, following the control flow can be tricky
// In this test file numbered comments indicate the order statements are expected to execute
test('encapsulates an asynchronous error handler', async t => {
t.plan(3)
const fastify = Fastify()
fastify.register(async function (fastify) {
fastify.setErrorHandler(async function a (err) {
// 3. the inner error handler catches the error, and throws a new error
t.assert.strictEqual(err.message, 'from_endpoint')
throw new Error('from_inner')
})
fastify.get('/encapsulated', async () => {
// 2. the endpoint throws an error
throw new Error('from_endpoint')
})
})
fastify.setErrorHandler(async function b (err) {
// 4. the outer error handler catches the error thrown by the inner error handler
t.assert.strictEqual(err.message, 'from_inner')
// 5. the outer error handler throws a new error
throw new Error('from_outer')
})
// 1. the endpoint is called
const res = await fastify.inject('/encapsulated')
// 6. the default error handler returns the error from the outer error handler
t.assert.strictEqual(res.json().message, 'from_outer')
})
// See discussion in https://github.com/fastify/fastify/pull/5222#discussion_r1432573655
test('encapsulates a synchronous error handler', async t => {
t.plan(3)
const fastify = Fastify()
fastify.register(async function (fastify) {
fastify.setErrorHandler(function a (err) {
// 3. the inner error handler catches the error, and throws a new error
t.assert.strictEqual(err.message, 'from_endpoint')
throw new Error('from_inner')
})
fastify.get('/encapsulated', async () => {
// 2. the endpoint throws an error
throw new Error('from_endpoint')
})
})
fastify.setErrorHandler(async function b (err) {
// 4. the outer error handler catches the error thrown by the inner error handler
t.assert.strictEqual(err.message, 'from_inner')
// 5. the outer error handler throws a new error
throw new Error('from_outer')
})
// 1. the endpoint is called
const res = await fastify.inject('/encapsulated')
// 6. the default error handler returns the error from the outer error handler
t.assert.strictEqual(res.json().message, 'from_outer')
})
test('onError hook nested', async t => {
t.plan(4)
const fastify = Fastify()
fastify.register(async function (fastify) {
fastify.setErrorHandler(async function a (err) {
// 4. the inner error handler catches the error, and throws a new error
t.assert.strictEqual(err.message, 'from_endpoint')
throw new Error('from_inner')
})
fastify.get('/encapsulated', async () => {
// 2. the endpoint throws an error
throw new Error('from_endpoint')
})
})
fastify.setErrorHandler(async function b (err) {
// 5. the outer error handler catches the error thrown by the inner error handler
t.assert.strictEqual(err.message, 'from_inner')
// 6. the outer error handler throws a new error
throw new Error('from_outer')
})
fastify.addHook('onError', async function (request, reply, err) {
// 3. the hook receives the error
t.assert.strictEqual(err.message, 'from_endpoint')
})
// 1. the endpoint is called
const res = await fastify.inject('/encapsulated')
// 7. the default error handler returns the error from the outer error handler
t.assert.strictEqual(res.json().message, 'from_outer')
})
// See https://github.com/fastify/fastify/issues/5220
test('encapuslates an error handler, for errors thrown in hooks', async t => {
t.plan(3)
const fastify = Fastify()
fastify.register(async function (fastify) {
fastify.setErrorHandler(function a (err) {
// 3. the inner error handler catches the error, and throws a new error
t.assert.strictEqual(err.message, 'from_hook')
throw new Error('from_inner')
})
fastify.addHook('onRequest', async () => {
// 2. the hook throws an error
throw new Error('from_hook')
})
fastify.get('/encapsulated', async () => {})
})
fastify.setErrorHandler(function b (err) {
// 4. the outer error handler catches the error thrown by the inner error handler
t.assert.strictEqual(err.message, 'from_inner')
// 5. the outer error handler throws a new error
throw new Error('from_outer')
})
// 1. the endpoint is called
const res = await fastify.inject('/encapsulated')
// 6. the default error handler returns the error from the outer error handler
t.assert.strictEqual(res.json().message, 'from_outer')
})
// See https://github.com/fastify/fastify/issues/5220
test('encapuslates many synchronous error handlers that rethrow errors', async t => {
const DEPTH = 100
t.plan(DEPTH + 2)
/**
* This creates a very nested set of error handlers, that looks like:
* plugin
* - error handler
* - plugin
* - error handler
* - plugin
* ... {to DEPTH levels}
* - plugin
* - error handler
* - GET /encapsulated
*/
const createNestedRoutes = (fastify, depth) => {
if (depth < 0) {
throw new Error('Expected depth >= 0')
} else if (depth === 0) {
fastify.setErrorHandler(function a (err) {
// 3. innermost error handler catches the error, and throws a new error
t.assert.strictEqual(err.message, 'from_route')
throw new Error(`from_handler_${depth}`)
})
fastify.get('/encapsulated', async () => {
// 2. the endpoint throws an error
throw new Error('from_route')
})
} else {
fastify.setErrorHandler(function d (err) {
// 4 to {DEPTH+4}. error handlers each catch errors, and then throws a new error
t.assert.strictEqual(err.message, `from_handler_${depth - 1}`)
throw new Error(`from_handler_${depth}`)
})
fastify.register(async function (fastify) {
createNestedRoutes(fastify, depth - 1)
})
}
}
const fastify = Fastify()
createNestedRoutes(fastify, DEPTH)
// 1. the endpoint is called
const res = await fastify.inject('/encapsulated')
// {DEPTH+5}. the default error handler returns the error from the outermost error handler
t.assert.strictEqual(res.json().message, `from_handler_${DEPTH}`)
})
// See https://github.com/fastify/fastify/issues/5220
// This was not failing previously, but we want to make sure the behavior continues to work in the same way across async and sync handlers
// Plus, the current setup is somewhat fragile to tweaks to wrapThenable as that's what retries (by calling res.send(err) again)
test('encapuslates many asynchronous error handlers that rethrow errors', async t => {
const DEPTH = 100
t.plan(DEPTH + 2)
/**
* This creates a very nested set of error handlers, that looks like:
* plugin
* - error handler
* - plugin
* - error handler
* - plugin
* ... {to DEPTH levels}
* - plugin
* - error handler
* - GET /encapsulated
*/
const createNestedRoutes = (fastify, depth) => {
if (depth < 0) {
throw new Error('Expected depth >= 0')
} else if (depth === 0) {
fastify.setErrorHandler(async function a (err) {
// 3. innermost error handler catches the error, and throws a new error
t.assert.strictEqual(err.message, 'from_route')
throw new Error(`from_handler_${depth}`)
})
fastify.get('/encapsulated', async () => {
// 2. the endpoint throws an error
throw new Error('from_route')
})
} else {
fastify.setErrorHandler(async function m (err) {
// 4 to {DEPTH+4}. error handlers each catch errors, and then throws a new error
t.assert.strictEqual(err.message, `from_handler_${depth - 1}`)
throw new Error(`from_handler_${depth}`)
})
fastify.register(async function (fastify) {
createNestedRoutes(fastify, depth - 1)
})
}
}
const fastify = Fastify()
createNestedRoutes(fastify, DEPTH)
// 1. the endpoint is called
const res = await fastify.inject('/encapsulated')
// {DEPTH+5}. the default error handler returns the error from the outermost error handler
t.assert.strictEqual(res.json().message, `from_handler_${DEPTH}`)
})

10
node_modules/fastify/test/esm/errorCodes.test.mjs generated vendored Normal file
View File

@@ -0,0 +1,10 @@
import { errorCodes } from '../../fastify.js'
import { test } from 'node:test'
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.assert.ok(typeof customError !== 'undefined')
t.assert.ok(customError instanceof errorCodes.FST_ERR_VALIDATION)
t.assert.strictEqual(customError.message, 'custom error message')
})

13
node_modules/fastify/test/esm/esm.test.mjs generated vendored Normal file
View File

@@ -0,0 +1,13 @@
import { test } from 'node:test'
import Fastify from '../../fastify.js'
test('esm support', async t => {
const fastify = Fastify()
fastify.register(import('./plugin.mjs'), { foo: 'bar' })
fastify.register(import('./other.mjs'))
await fastify.ready()
t.assert.strictEqual(fastify.foo, 'bar')
})

8
node_modules/fastify/test/esm/index.test.js generated vendored Normal file
View File

@@ -0,0 +1,8 @@
'use strict'
import('./named-exports.mjs')
.catch(err => {
process.nextTick(() => {
throw err
})
})

14
node_modules/fastify/test/esm/named-exports.mjs generated vendored Normal file
View File

@@ -0,0 +1,14 @@
import { test } from 'node:test'
import { fastify } from '../../fastify.js'
// This test is executed in index.test.js
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.assert.strictEqual(app.foo, 'bar')
})

8
node_modules/fastify/test/esm/other.mjs generated vendored Normal file
View File

@@ -0,0 +1,8 @@
// Imported in both index.test.js & esm.test.mjs
import { strictEqual } from 'node:assert'
async function other (fastify, opts) {
strictEqual(fastify.foo, 'bar')
}
export default other

8
node_modules/fastify/test/esm/plugin.mjs generated vendored Normal file
View 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

300
node_modules/fastify/test/fastify-instance.test.js generated vendored Normal file
View File

@@ -0,0 +1,300 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('..')
const os = require('node:os')
const {
kOptions,
kErrorHandler,
kChildLoggerFactory,
kState
} = require('../lib/symbols')
const isIPv6Missing = !Object.values(os.networkInterfaces()).flat().some(({ family }) => family === 'IPv6')
test('root fastify instance is an object', t => {
t.plan(1)
t.assert.strictEqual(typeof Fastify(), 'object')
})
test('fastify instance should contains ajv options', t => {
t.plan(1)
const fastify = Fastify({
ajv: {
customOptions: {
nullable: false
}
}
})
t.assert.deepStrictEqual(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.assert.deepStrictEqual(fastify[kOptions].ajv, {
customOptions: {
nullable: false
},
plugins: [[]]
})
})
test('fastify instance get invalid ajv options', t => {
t.plan(1)
t.assert.throws(() => Fastify({
ajv: {
customOptions: 8
}
}))
})
test('fastify instance get invalid ajv options.plugins', t => {
t.plan(1)
t.assert.throws(() => Fastify({
ajv: {
customOptions: {},
plugins: 8
}
}))
})
test('fastify instance should contain default errorHandler', t => {
t.plan(3)
const fastify = Fastify()
t.assert.ok(fastify[kErrorHandler].func instanceof Function)
t.assert.deepStrictEqual(fastify.errorHandler, fastify[kErrorHandler].func)
t.assert.deepStrictEqual(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.assert.notDeepStrictEqual(instance.errorHandler, fastify.errorHandler)
t.assert.strictEqual(instance.errorHandler.name, 'bound inPluginErrHandler')
done()
})
await fastify.ready()
t.assert.ok(fastify[kErrorHandler].func instanceof Function)
t.assert.deepStrictEqual(fastify.errorHandler, fastify[kErrorHandler].func)
})
test('fastify instance should contain default childLoggerFactory', t => {
t.plan(3)
const fastify = Fastify()
t.assert.ok(fastify[kChildLoggerFactory] instanceof Function)
t.assert.deepStrictEqual(fastify.childLoggerFactory, fastify[kChildLoggerFactory])
t.assert.deepStrictEqual(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.assert.notDeepStrictEqual(instance.childLoggerFactory, fastify.childLoggerFactory)
t.assert.strictEqual(instance.childLoggerFactory.name, 'inPluginLoggerFactory')
done()
})
await fastify.ready()
t.assert.ok(fastify[kChildLoggerFactory] instanceof Function)
t.assert.deepStrictEqual(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.assert.deepStrictEqual(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.assert.deepStrictEqual(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.assert.strictEqual(err.message, 'test')
})
t.assert.deepStrictEqual(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.assert.deepStrictEqual(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.assert.deepStrictEqual(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.assert.strictEqual(err.message, 'test')
})
t.assert.deepStrictEqual(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.assert.deepStrictEqual(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.assert.deepStrictEqual(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.assert.deepStrictEqual(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.assert.deepStrictEqual(fastify.listeningOrigin, path)
await fastify.close()
})
test('fastify instance should contains listeningOrigin property (IPv6)', { skip: isIPv6Missing }, async t => {
t.plan(1)
const port = 3000
const host = '::1'
const fastify = Fastify()
await fastify.listen({ port, host })
t.assert.deepStrictEqual(fastify.listeningOrigin, `http://[::1]:${port}`)
await fastify.close()
})
test('fastify instance should ensure ready promise cleanup on ready', async t => {
t.plan(1)
const fastify = Fastify()
await fastify.ready()
t.assert.strictEqual(fastify[kState].readyResolver, null)
})

152
node_modules/fastify/test/find-route.test.js generated vendored Normal file
View File

@@ -0,0 +1,152 @@
'use strict'
const { test } = require('node:test')
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.assert.strictEqual(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.assert.strictEqual(route.params.artistId, ':artistId')
})
test('findRoute should return null when when url is not passed', 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.assert.strictEqual(fastify.findRoute({
method: 'POST'
}), null)
})
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.assert.strictEqual(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.assert.strictEqual(route.params.artistId, ':artistId')
})
test('findRoute should work correctly when used within plugins', (t, done) => {
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.assert.strictEqual(fastify.validateRoutes.validateParams(), true)
done()
})
})
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.assert.strictEqual(route.store, undefined)
})

209
node_modules/fastify/test/fluent-schema.test.js generated vendored Normal file
View File

@@ -0,0 +1,209 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('..')
const S = require('fluent-json-schema')
test('use fluent-json-schema object', async (t) => {
t.plan(10)
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())
}
}
})
const res1 = await fastify.inject({
method: 'POST',
url: '/1',
headers: { 'x-custom': 'me@me.me' },
query: { surname: 'bar' },
payload: { name: 'foo' }
})
t.assert.strictEqual(res1.statusCode, 400)
t.assert.deepStrictEqual(res1.json(), { statusCode: 400, code: 'FST_ERR_VALIDATION', error: 'Bad Request', message: 'params/id must be >= 42' })
// check header
const res2 = await fastify.inject({
method: 'POST',
url: '/42',
headers: { 'x-custom': 'invalid' },
query: { surname: 'bar' },
payload: { name: 'foo' }
})
t.assert.strictEqual(res2.statusCode, 400)
t.assert.deepStrictEqual(res2.json(), { statusCode: 400, code: 'FST_ERR_VALIDATION', error: 'Bad Request', message: 'headers/x-custom must match format "email"' })
// check query
const res3 = await fastify.inject({
method: 'POST',
url: '/42',
headers: { 'x-custom': 'me@me.me' },
query: { },
payload: { name: 'foo' }
})
t.assert.strictEqual(res3.statusCode, 400)
t.assert.deepStrictEqual(res3.json(), { statusCode: 400, code: 'FST_ERR_VALIDATION', error: 'Bad Request', message: 'querystring must have required property \'surname\'' })
// check body
const res4 = await fastify.inject({
method: 'POST',
url: '/42',
headers: { 'x-custom': 'me@me.me' },
query: { surname: 'bar' },
payload: { name: [1, 2, 3] }
})
t.assert.strictEqual(res4.statusCode, 400)
t.assert.deepStrictEqual(res4.json(), { statusCode: 400, code: 'FST_ERR_VALIDATION', error: 'Bad Request', message: 'body/name must be string' })
// check response
const res5 = await fastify.inject({
method: 'POST',
url: '/42',
headers: { 'x-custom': 'me@me.me' },
query: { surname: 'bar' },
payload: { name: 'foo' }
})
t.assert.strictEqual(res5.statusCode, 200)
t.assert.deepStrictEqual(res5.json(), { name: 'a', surname: 'b' })
})
test('use complex fluent-json-schema object', (t, done) => {
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.assert.ifError(err)
done()
})
})
test('use fluent schema and plain JSON schema', (t, done) => {
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.assert.ifError(err)
done()
})
})
test('Should call valueOf internally', (t, done) => {
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(err => {
t.assert.ifError(err)
done()
})
})

426
node_modules/fastify/test/genReqId.test.js generated vendored Normal file
View File

@@ -0,0 +1,426 @@
'use strict'
const { Readable } = require('node:stream')
const { test } = require('node:test')
const fp = require('fastify-plugin')
const Fastify = require('..')
test('Should accept a custom genReqId function', (t, done) => {
t.plan(4)
const fastify = Fastify({
genReqId: function (req) {
return 'a'
}
})
t.after(() => fastify.close())
fastify.get('/', (req, reply) => {
t.assert.ok(req.id)
reply.send({ id: req.id })
})
fastify.listen({ port: 0 }, err => {
t.assert.ifError(err)
fastify.inject({
method: 'GET',
url: `http://localhost:${fastify.server.address().port}`
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.strictEqual(payload.id, 'a')
done()
})
})
})
test('Custom genReqId function gets raw request as argument', (t, done) => {
t.plan(9)
const REQUEST_ID = 'REQ-1234'
const fastify = Fastify({
genReqId: function (req) {
t.assert.strictEqual('id' in req, false)
t.assert.strictEqual('raw' in req, false)
t.assert.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.assert.strictEqual(xReqId, REQUEST_ID)
t.assert.strictEqual(req.headers['x-request-id'], REQUEST_ID)
return xReqId
}
})
t.after(() => fastify.close())
fastify.get('/', (req, reply) => {
t.assert.strictEqual(req.id, REQUEST_ID)
reply.send({ id: req.id })
})
fastify.listen({ port: 0 }, err => {
t.assert.ifError(err)
fastify.inject({
method: 'GET',
headers: {
'x-request-id': REQUEST_ID
},
url: `http://localhost:${fastify.server.address().port}`
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.strictEqual(payload.id, REQUEST_ID)
done()
})
})
})
test('Should handle properly requestIdHeader option', t => {
t.plan(4)
t.assert.strictEqual(Fastify({ requestIdHeader: '' }).initialConfig.requestIdHeader, false)
t.assert.strictEqual(Fastify({ requestIdHeader: false }).initialConfig.requestIdHeader, false)
t.assert.strictEqual(Fastify({ requestIdHeader: true }).initialConfig.requestIdHeader, 'request-id')
t.assert.strictEqual(Fastify({ requestIdHeader: 'x-request-id' }).initialConfig.requestIdHeader, 'x-request-id')
})
test('Should accept option to set genReqId with setGenReqId option', (t, done) => {
t.plan(9)
const fastify = Fastify({
genReqId: function (req) {
return 'base'
}
})
t.after(() => fastify.close())
fastify.register(function (instance, opts, next) {
instance.setGenReqId(function (req) {
return 'foo'
})
instance.get('/', (req, reply) => {
t.assert.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.assert.ok(req.id)
reply.send({ id: req.id })
})
next()
}, { prefix: 'bar' })
fastify.get('/', (req, reply) => {
t.assert.ok(req.id)
reply.send({ id: req.id })
})
let pending = 3
function completed () {
if (--pending === 0) {
done()
}
}
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.strictEqual(payload.id, 'base')
completed()
})
fastify.inject({
method: 'GET',
url: '/foo'
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.strictEqual(payload.id, 'foo')
completed()
})
fastify.inject({
method: 'GET',
url: '/bar'
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.strictEqual(payload.id, 'bar')
completed()
})
})
test('Should encapsulate setGenReqId', (t, done) => {
t.plan(12)
const fastify = Fastify({
genReqId: function (req) {
return 'base'
}
})
t.after(() => fastify.close())
const bazInstance = function (instance, opts, next) {
instance.register(barInstance, { prefix: 'baz' })
instance.setGenReqId(function (req) {
return 'baz'
})
instance.get('/', (req, reply) => {
t.assert.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.assert.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.assert.ok(req.id)
reply.send({ id: req.id })
})
next()
}
fastify.register(fooInstance, { prefix: 'foo' })
fastify.get('/', (req, reply) => {
t.assert.ok(req.id)
reply.send({ id: req.id })
})
let pending = 4
function completed () {
if (--pending === 0) {
done()
}
}
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.strictEqual(payload.id, 'base')
completed()
})
fastify.inject({
method: 'GET',
url: '/foo'
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.strictEqual(payload.id, 'foo')
completed()
})
fastify.inject({
method: 'GET',
url: '/foo/bar'
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.strictEqual(payload.id, 'bar')
completed()
})
fastify.inject({
method: 'GET',
url: '/foo/baz'
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.strictEqual(payload.id, 'baz')
completed()
})
})
test('Should not alter parent of genReqId', (t, done) => {
t.plan(6)
const fastify = Fastify()
t.after(() => fastify.close())
const fooInstance = function (instance, opts, next) {
instance.setGenReqId(function (req) {
return 'foo'
})
instance.get('/', (req, reply) => {
t.assert.ok(req.id)
reply.send({ id: req.id })
})
next()
}
fastify.register(fooInstance, { prefix: 'foo' })
fastify.get('/', (req, reply) => {
t.assert.ok(req.id)
reply.send({ id: req.id })
})
let pending = 2
function completed () {
if (--pending === 0) {
done()
}
}
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.strictEqual(payload.id, 'req-1')
completed()
})
fastify.inject({
method: 'GET',
url: '/foo'
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.strictEqual(payload.id, 'foo')
completed()
})
})
test('Should have child instance user parent genReqId', (t, done) => {
t.plan(6)
const fastify = Fastify({
genReqId: function (req) {
return 'foo'
}
})
t.after(() => fastify.close())
const fooInstance = function (instance, opts, next) {
instance.get('/', (req, reply) => {
t.assert.ok(req.id)
reply.send({ id: req.id })
})
next()
}
fastify.register(fooInstance, { prefix: 'foo' })
fastify.get('/', (req, reply) => {
t.assert.ok(req.id)
reply.send({ id: req.id })
})
let pending = 2
function completed () {
if (--pending === 0) {
done()
}
}
fastify.inject({
method: 'GET',
url: '/'
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.strictEqual(payload.id, 'foo')
completed()
})
fastify.inject({
method: 'GET',
url: '/foo'
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.strictEqual(payload.id, 'foo')
completed()
})
})
test('genReqId set on root scope when using fastify-plugin', (t, done) => {
t.plan(6)
const fastify = Fastify()
t.after(() => fastify.close())
fastify.register(fp(function (fastify, options, done) {
fastify.setGenReqId(function (req) {
return 'not-encapsulated'
})
fastify.get('/not-encapsulated-1', (req, reply) => {
t.assert.ok(req.id)
reply.send({ id: req.id })
})
done()
}))
fastify.get('/not-encapsulated-2', (req, reply) => {
t.assert.ok(req.id)
reply.send({ id: req.id })
})
let pending = 2
function completed () {
if (--pending === 0) {
done()
}
}
fastify.inject({
method: 'GET',
url: '/not-encapsulated-1'
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.strictEqual(payload.id, 'not-encapsulated')
completed()
})
fastify.inject({
method: 'GET',
url: '/not-encapsulated-2'
}, (err, res) => {
t.assert.ifError(err)
const payload = JSON.parse(res.payload)
t.assert.strictEqual(payload.id, 'not-encapsulated')
completed()
})
})

45
node_modules/fastify/test/handler-context.test.js generated vendored Normal file
View File

@@ -0,0 +1,45 @@
'use strict'
const { test } = require('node: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.assert.ok(this.foo)
t.assert.strictEqual(this.foo, 'foo')
reply.send()
})
await instance.inject('/')
t.assert.ok(instance.foo)
t.assert.strictEqual(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.assert.ok(reply[kRouteContext])
t.assert.ok(reply[kRouteContext].config)
t.assert.ok(typeof reply[kRouteContext].config, Object)
t.assert.ok(reply[kRouteContext].config.foo)
t.assert.strictEqual(reply[kRouteContext].config.foo, 'bar')
reply.send()
})
await instance.inject('/')
})

88
node_modules/fastify/test/has-route.test.js generated vendored Normal file
View File

@@ -0,0 +1,88 @@
'use strict'
const { test, describe } = require('node:test')
const Fastify = require('..')
const fastify = Fastify()
describe('hasRoute', async t => {
test('hasRoute - invalid options', t => {
t.plan(3)
t.assert.strictEqual(fastify.hasRoute({ }), false)
t.assert.strictEqual(fastify.hasRoute({ method: 'GET' }), false)
t.assert.strictEqual(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.assert.strictEqual(fastify.hasRoute({
method: 'GET',
url: '/'
}), true)
t.assert.strictEqual(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.assert.strictEqual(fastify.hasRoute({
method: 'GET',
url: '/',
constraints: { version: '1.2.0' }
}), true)
t.assert.strictEqual(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.assert.strictEqual(fastify.hasRoute({
method: 'GET',
url: '/example/:file(^\\d+).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.assert.strictEqual(fastify.hasRoute({
method: 'get',
url: '/equal'
}), true)
})
})

55
node_modules/fastify/test/header-overflow.test.js generated vendored Normal file
View File

@@ -0,0 +1,55 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('..')
const maxHeaderSize = 1024
test('Should return 431 if request header fields are too large', async (t) => {
t.plan(2)
const fastify = Fastify({ http: { maxHeaderSize } })
fastify.route({
method: 'GET',
url: '/',
handler: (_req, reply) => {
reply.send({ hello: 'world' })
}
})
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(fastifyServer, {
method: 'GET',
headers: {
'Large-Header': 'a'.repeat(maxHeaderSize)
}
})
t.assert.ok(!result.ok)
t.assert.strictEqual(result.status, 431)
t.after(() => fastify.close())
})
test('Should return 431 if URI is too long', async (t) => {
t.plan(2)
const fastify = Fastify({ http: { maxHeaderSize } })
fastify.route({
method: 'GET',
url: '/',
handler: (_req, reply) => {
reply.send({ hello: 'world' })
}
})
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(`${fastifyServer}/${'a'.repeat(maxHeaderSize)}`)
t.assert.ok(!result.ok)
t.assert.strictEqual(result.status, 431)
t.after(() => fastify.close())
})

496
node_modules/fastify/test/helper.js generated vendored Normal file
View File

@@ -0,0 +1,496 @@
'use strict'
const dns = require('node:dns').promises
const stream = require('node:stream')
const { promisify } = require('node:util')
const symbols = require('../lib/symbols')
const { waitForCb } = require('./toolkit')
const assert = require('node:assert')
module.exports.sleep = promisify(setTimeout)
/**
* @param method HTTP request method
* @param t node:test 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) {
assert.ok(request instanceof fastify[symbols.kRequest].parent)
assert.strictEqual(typeof request, 'object')
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.assert.ok(true)
} catch (e) {
t.assert.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.assert.ok(true)
} catch (e) {
t.assert.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.assert.ok(true)
} catch (e) {
t.assert.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.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
fastify.listen({ port: 0 }, function (err) {
if (err) {
t.assert.ifError(err)
return
}
t.after(() => { fastify.close() })
test(`${upMethod} - correctly replies`, async (t) => {
t.plan(3)
const result = await fetch('http://localhost:' + fastify.server.address().port, {
method: upMethod,
body: JSON.stringify({ hello: 'world' }),
headers: {
'Content-Type': 'application/json'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.json(), { hello: 'world' })
})
test(`${upMethod} - correctly replies with very large body`, async (t) => {
t.plan(3)
const largeString = 'world'.repeat(13200)
const result = await fetch('http://localhost:' + fastify.server.address().port, {
method: upMethod,
body: JSON.stringify({ hello: largeString }),
headers: {
'Content-Type': 'application/json'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.json(), { hello: largeString })
})
test(`${upMethod} - correctly replies if the content type has the charset`, async (t) => {
t.plan(3)
const result = await fetch('http://localhost:' + fastify.server.address().port, {
method: upMethod,
body: JSON.stringify({ hello: 'world' }),
headers: {
'content-type': 'application/json; charset=utf-8'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.text(), JSON.stringify({ hello: 'world' }))
})
test(`${upMethod} without schema - correctly replies`, async (t) => {
t.plan(3)
const result = await fetch('http://localhost:' + fastify.server.address().port + '/missing', {
method: upMethod,
body: JSON.stringify({ hello: 'world' }),
headers: {
'Content-Type': 'application/json'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.json(), { hello: 'world' })
})
test(`${upMethod} with body and querystring - correctly replies`, async (t) => {
t.plan(3)
const result = await fetch('http://localhost:' + fastify.server.address().port + '/with-query?foo=hello', {
method: upMethod,
body: JSON.stringify({ hello: 'world' }),
headers: {
'Content-Type': 'application/json'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.json(), { hello: 'worldhello' })
})
test(`${upMethod} with no body - correctly replies`, t => {
t.plan(6)
const { stepIn, patience } = waitForCb({ steps: 2 })
fetch('http://localhost:' + fastify.server.address().port + '/missing', {
method: upMethod,
headers: { 'Content-Length': '0' }
}).then(async (response) => {
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
t.assert.strictEqual(await response.text(), '')
stepIn()
})
// Must use inject to make a request without a Content-Length header
fastify.inject({
method: upMethod,
url: '/missing'
}, (err, res) => {
t.assert.ifError(err)
t.assert.strictEqual(res.statusCode, 200)
t.assert.strictEqual(res.payload.toString(), '')
stepIn()
})
return patience
})
test(`${upMethod} returns 415 - incorrect media type if body is not json`, async (t) => {
t.plan(2)
const result = await fetch('http://localhost:' + fastify.server.address().port + '/missing', {
method: upMethod,
body: 'hello world',
headers: {
'Content-Type': undefined
}
})
t.assert.ok(!result.ok)
t.assert.strictEqual(result.status, 415)
})
if (loMethod === 'options') {
test('OPTIONS returns 415 - should return 415 if Content-Type is not json or plain text', async (t) => {
t.plan(2)
const result = await fetch('http://localhost:' + fastify.server.address().port + '/missing', {
method: upMethod,
body: 'hello world',
headers: {
'Content-Type': 'text/xml'
}
})
t.assert.ok(!result.ok)
t.assert.strictEqual(result.status, 415)
})
}
test(`${upMethod} returns 400 - Bad Request`, t => {
const isOptions = upMethod === 'OPTIONS'
t.plan(isOptions ? 2 : 4)
const { stepIn, patience } = waitForCb({ steps: isOptions ? 1 : 2 })
fetch('http://localhost:' + fastify.server.address().port, {
method: upMethod,
body: 'hello world',
headers: {
'Content-Type': 'application/json'
}
}).then((response) => {
t.assert.ok(!response.ok)
t.assert.strictEqual(response.status, 400)
stepIn()
})
if (!isOptions) {
fetch(`http://localhost:${fastify.server.address().port}`, {
method: upMethod,
headers: {
'Content-Type': 'application/json',
'Content-Length': '0'
}
}).then((response) => {
t.assert.ok(!response.ok)
t.assert.strictEqual(response.status, 400)
stepIn()
})
}
return patience
})
test(`${upMethod} returns 413 - Payload Too Large`, t => {
const isOptions = upMethod === 'OPTIONS'
t.plan(isOptions ? 3 : 5)
const { stepIn, patience } = waitForCb({ steps: isOptions ? 2 : 3 })
fetch(`http://localhost:${fastify.server.address().port}`, {
method: upMethod,
body: JSON.stringify({ w: 'w'.repeat(1024 * 1024 + 1) }),
headers: {
'Content-Type': 'application/json'
}
}).then((response) => {
t.assert.strictEqual(response.status, 413)
stepIn()
}).catch((err) => {
// Handle EPIPE error - server closed connection after sending 413
if (err.cause?.code === 'EPIPE' || err.message.includes('fetch failed')) {
t.assert.ok(true, 'Expected EPIPE error due to server closing connection on 413')
} else {
throw err
}
stepIn()
})
// Node errors for OPTIONS requests with a stream body and no Content-Length header
if (!isOptions) {
let chunk = Buffer.alloc(1024 * 1024 + 1, 0)
const largeStream = new stream.Readable({
read () {
this.push(chunk)
chunk = null
}
})
fetch('http://localhost:' + fastify.server.address().port, {
method: upMethod,
headers: { 'Content-Type': 'application/json' },
body: largeStream,
duplex: 'half'
}).then((response) => {
t.assert.ok(!response.ok)
t.assert.strictEqual(response.status, 413)
stepIn()
}).catch((err) => {
// Handle EPIPE error - server closed connection after sending 413
if (err.cause?.code === 'EPIPE' || err.message.includes('fetch failed')) {
t.assert.ok(true, 'Expected EPIPE error due to server closing connection on 413')
} else {
throw err
}
stepIn()
})
}
fetch(`http://localhost:${fastify.server.address().port}/with-limit`, {
method: upMethod,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({})
}).then((response) => {
t.assert.ok(!response.ok)
t.assert.strictEqual(response.status, 413)
stepIn()
})
return patience
})
test(`${upMethod} should fail with empty body and application/json content-type`, t => {
if (upMethod === 'OPTIONS') return
t.plan(12)
const { stepIn, patience } = waitForCb({ steps: 5 })
fastify.inject({
method: `${upMethod}`,
url: '/',
headers: {
'Content-Type': 'application/json'
}
}, (err, res) => {
t.assert.ifError(err)
t.assert.deepStrictEqual(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
})
})
fetch(`http://localhost:${fastify.server.address().port}`, {
method: upMethod,
headers: {
'Content-Type': 'application/json'
}
}).then(async (res) => {
t.assert.ok(!res.ok)
t.assert.deepStrictEqual(await res.json(), {
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
})
stepIn()
})
fastify.inject({
method: `${upMethod}`,
url: '/',
headers: {
'Content-Type': 'application/json'
},
payload: null
}, (err, res) => {
t.assert.ifError(err)
t.assert.deepStrictEqual(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
})
stepIn()
})
fetch(`http://localhost:${fastify.server.address().port}`, {
method: upMethod,
headers: {
'Content-Type': 'application/json'
},
body: null
}).then(async (res) => {
t.assert.ok(!res.ok)
t.assert.deepStrictEqual(await res.json(), {
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
})
stepIn()
})
fastify.inject({
method: `${upMethod}`,
url: '/',
headers: {
'Content-Type': 'application/json'
},
payload: undefined
}, (err, res) => {
t.assert.ifError(err)
t.assert.deepStrictEqual(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
})
stepIn()
})
fetch(`http://localhost:${fastify.server.address().port}`, {
method: upMethod,
headers: {
'Content-Type': 'application/json'
},
body: undefined
}).then(async (res) => {
t.assert.ok(!res.ok)
t.assert.deepStrictEqual(await res.json(), {
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
})
stepIn()
})
return patience
})
})
}
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}`
}

1099
node_modules/fastify/test/hooks-async.test.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

1162
node_modules/fastify/test/hooks.on-listen.test.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

421
node_modules/fastify/test/hooks.on-ready.test.js generated vendored Normal file
View File

@@ -0,0 +1,421 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('../fastify')
const immediate = require('node:util').promisify(setImmediate)
test('onReady should be called in order', (t, done) => {
t.plan(7)
const fastify = Fastify()
let order = 0
fastify.addHook('onReady', function (done) {
t.assert.strictEqual(order++, 0, 'called in root')
t.assert.strictEqual(this.pluginName, fastify.pluginName, 'the this binding is the right instance')
done()
})
fastify.register(async (childOne, o) => {
childOne.addHook('onReady', function (done) {
t.assert.strictEqual(order++, 1, 'called in childOne')
t.assert.strictEqual(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.assert.strictEqual(order++, 2, 'called in childTwo')
t.assert.strictEqual(this.pluginName, childTwo.pluginName, 'the this binding is the right instance')
})
})
})
fastify.ready(err => {
t.assert.ifError(err)
done()
})
})
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.assert.strictEqual(result, 1, 'Should resolve in order')
t.assert.strictEqual(counter, 1, 'Should call onReady only once')
})
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.assert.strictEqual(order++, 0, 'called in root')
t.assert.strictEqual(this.pluginName, fastify.pluginName, 'the this binding is the right instance')
})
fastify.register(async (childOne, o) => {
childOne.addHook('onReady', async function () {
await immediate()
t.assert.strictEqual(order++, 1, 'called in childOne')
t.assert.strictEqual(this.pluginName, childOne.pluginName, 'the this binding is the right instance')
})
childOne.register(async (childTwo, o) => {
childTwo.addHook('onReady', async function () {
await immediate()
t.assert.strictEqual(order++, 2, 'called in childTwo')
t.assert.strictEqual(this.pluginName, childTwo.pluginName, 'the this binding is the right instance')
})
})
})
await fastify.ready()
t.assert.ok('ready')
})
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.assert.strictEqual(order, 1)
await fastify.ready()
t.assert.strictEqual(order, 1, 'ready hooks execute once')
})
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.assert.ok('trigger the onReady')
await fastify.listen({ port: 0 })
t.assert.ok('do not trigger the onReady')
await fastify.close()
function checkOrder (shouldbe) {
t.assert.strictEqual(order, shouldbe)
order++
}
})
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.assert.strictEqual(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.assert.ok('trigger the onReady')
await fastify.ready()
t.assert.ok('do not trigger the onReady')
await fastify.ready()
t.assert.ok('do not trigger the onReady')
function checkOrder (shouldbe) {
t.assert.strictEqual(order, shouldbe)
order++
}
})
test('onReady should manage error in sync', (t, done) => {
t.plan(4)
const fastify = Fastify()
fastify.addHook('onReady', function (done) {
t.assert.ok('called in root')
done()
})
fastify.register(async (childOne, o) => {
childOne.addHook('onReady', function (done) {
t.assert.ok('called in childOne')
done(new Error('FAIL ON READY'))
})
childOne.register(async (childTwo, o) => {
childTwo.addHook('onReady', async function () {
t.assert.fail('should not be called')
})
})
})
fastify.ready(err => {
t.assert.ok(err)
t.assert.strictEqual(err.message, 'FAIL ON READY')
done()
})
})
test('onReady should manage error in async', (t, done) => {
t.plan(4)
const fastify = Fastify()
fastify.addHook('onReady', function (done) {
t.assert.ok('called in root')
done()
})
fastify.register(async (childOne, o) => {
childOne.addHook('onReady', async function () {
t.assert.ok('called in childOne')
throw new Error('FAIL ON READY')
})
childOne.register(async (childTwo, o) => {
childTwo.addHook('onReady', async function () {
t.assert.fail('should not be called')
})
})
})
fastify.ready(err => {
t.assert.ok(err)
t.assert.strictEqual(err.message, 'FAIL ON READY')
done()
})
})
test('onReady should manage sync error', (t, done) => {
t.plan(4)
const fastify = Fastify()
fastify.addHook('onReady', function (done) {
t.assert.ok('called in root')
done()
})
fastify.register(async (childOne, o) => {
childOne.addHook('onReady', function (done) {
t.assert.ok('called in childOne')
throw new Error('FAIL UNWANTED SYNC EXCEPTION')
})
childOne.register(async (childTwo, o) => {
childTwo.addHook('onReady', async function () {
t.assert.fail('should not be called')
})
})
})
fastify.ready(err => {
t.assert.ok(err)
t.assert.strictEqual(err.message, 'FAIL UNWANTED SYNC EXCEPTION')
done()
})
})
test('onReady can not add decorators or application hooks', (t, done) => {
t.plan(3)
const fastify = Fastify()
fastify.addHook('onReady', function (done) {
t.assert.ok('called in root')
fastify.decorate('test', () => {})
fastify.addHook('onReady', async function () {
t.assert.fail('it will be not called')
})
done()
})
fastify.addHook('onReady', function (done) {
t.assert.ok(this.hasDecorator('test'))
done()
})
fastify.ready(err => {
t.assert.ifError(err)
done()
})
})
test('onReady cannot add lifecycle hooks', (t, done) => {
t.plan(5)
const fastify = Fastify()
fastify.addHook('onReady', function (done) {
t.assert.ok('called in root')
try {
fastify.addHook('onRequest', (request, reply, done) => {})
} catch (error) {
t.assert.ok(error)
t.assert.strictEqual(error.message, 'Root plugin has already booted')
// TODO: look where the error pops up
t.assert.strictEqual(error.code, 'AVV_ERR_ROOT_PLG_BOOTED')
done(error)
}
})
fastify.addHook('onRequest', (request, reply, done) => {})
fastify.get('/', async () => 'hello')
fastify.ready((err) => {
t.assert.ok(err)
done()
})
})
test('onReady throw loading error', t => {
t.plan(2)
const fastify = Fastify()
try {
fastify.addHook('onReady', async function (done) {})
} catch (e) {
t.assert.strictEqual(e.code, 'FST_ERR_HOOK_INVALID_ASYNC_HANDLER')
t.assert.ok(e.message === 'Async function has too many arguments. Async hooks should not use the \'done\' argument.')
}
})
test('onReady does not call done', (t, done) => {
t.plan(6)
const fastify = Fastify({ pluginTimeout: 500 })
fastify.addHook('onReady', function someHookName (done) {
t.assert.ok('called in root')
// done() // don't call done to test timeout
})
fastify.ready(err => {
t.assert.ok(err)
t.assert.strictEqual(err.message, 'A callback for \'onReady\' hook "someHookName" timed out. You may have forgotten to call \'done\' function or to resolve a Promise')
t.assert.strictEqual(err.code, 'FST_ERR_HOOK_TIMEOUT')
t.assert.ok(err.cause)
t.assert.strictEqual(err.cause.code, 'AVV_ERR_READY_TIMEOUT')
done()
})
})
test('onReady execution order', (t, done) => {
t.plan(3)
const fastify = Fastify({ })
let i = 0
fastify.ready(() => { i++; t.assert.strictEqual(i, 1) })
fastify.ready(() => { i++; t.assert.strictEqual(i, 2) })
fastify.ready(() => {
i++
t.assert.strictEqual(i, 3)
done()
})
})
test('ready return the server with callback', (t, done) => {
t.plan(2)
const fastify = Fastify()
fastify.ready((err, instance) => {
t.assert.ifError(err)
t.assert.deepStrictEqual(instance, fastify)
done()
})
})
test('ready return the server with Promise', async t => {
t.plan(1)
const fastify = Fastify()
await fastify.ready()
.then(instance => { t.assert.deepStrictEqual(instance, fastify) })
.catch(err => { t.assert.fail(err) })
})
test('ready return registered', async t => {
t.plan(4)
const fastify = Fastify()
fastify.register((one, opts, done) => {
one.ready().then(itself => { t.assert.deepStrictEqual(itself, one) })
done()
})
fastify.register((two, opts, done) => {
two.ready().then(itself => { t.assert.deepStrictEqual(itself, two) })
two.register((twoDotOne, opts, done) => {
twoDotOne.ready().then(itself => { t.assert.deepStrictEqual(itself, twoDotOne) })
done()
})
done()
})
await fastify.ready()
.then(instance => { t.assert.deepStrictEqual(instance, fastify) })
.catch(err => { t.assert.fail(err) })
})
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.assert.rejects(fastify.ready())
})

3578
node_modules/fastify/test/hooks.test.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

35
node_modules/fastify/test/http-methods/copy.test.js generated vendored Normal file
View File

@@ -0,0 +1,35 @@
'use strict'
const { test } = require('node:test')
const fastify = require('../../fastify')()
fastify.addHttpMethod('COPY')
test('can be created - copy', async t => {
t.plan(3)
t.after(() => fastify.close())
try {
fastify.route({
method: 'COPY',
url: '*',
handler: function (req, reply) {
reply.code(204).send()
}
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
const fastifyServer = await fastify.listen({ port: 0 })
const result = await fetch(`${fastifyServer}/test.txt`, {
method: 'COPY',
headers: {
Destination: '/test2.txt'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 204)
})

View File

@@ -0,0 +1,114 @@
'use strict'
const http = require('node:http')
const { test } = require('node:test')
const Fastify = require('../../fastify')
function addEcho (fastify, method) {
fastify.route({
method,
url: '/',
handler: function (req, reply) {
reply.send(req.body)
}
})
}
test('missing method from http client', (t, done) => {
t.plan(2)
const fastify = Fastify()
fastify.listen({ port: 3000 }, (err) => {
t.assert.ifError(err)
const port = fastify.server.address().port
const req = http.request({
port,
method: 'REBIND',
path: '/'
}, (res) => {
t.assert.strictEqual(res.statusCode, 404)
fastify.close()
done()
})
req.end()
})
})
test('addHttpMethod increase the supported HTTP methods supported', (t, done) => {
t.plan(8)
const app = Fastify()
t.assert.throws(() => { addEcho(app, 'REBIND') }, /REBIND method is not supported./)
t.assert.ok(!app.supportedMethods.includes('REBIND'))
t.assert.ok(!app.rebind)
app.addHttpMethod('REBIND')
t.assert.doesNotThrow(() => { addEcho(app, 'REBIND') }, 'REBIND method is supported.')
t.assert.ok(app.supportedMethods.includes('REBIND'))
t.assert.ok(app.rebind)
app.rebind('/foo', () => 'hello')
app.inject({
method: 'REBIND',
url: '/foo'
}, (err, response) => {
t.assert.ifError(err)
t.assert.strictEqual(response.payload, 'hello')
done()
})
})
test('addHttpMethod adds a new custom method without body', t => {
t.plan(3)
const app = Fastify()
t.assert.throws(() => { addEcho(app, 'REBIND') }, /REBIND method is not supported./)
app.addHttpMethod('REBIND')
t.assert.doesNotThrow(() => { addEcho(app, 'REBIND') }, 'REBIND method is supported.')
t.assert.throws(() => {
app.route({
url: '/',
method: 'REBIND',
schema: {
body: {
type: 'object',
properties: {
hello: { type: 'string' }
}
}
},
handler: function (req, reply) {
reply.send(req.body)
}
})
}, /Body validation schema for REBIND:\/ route is not supported!/)
})
test('addHttpMethod adds a new custom method with body', (t, done) => {
t.plan(3)
const app = Fastify()
app.addHttpMethod('REBIND', { hasBody: true })
t.assert.doesNotThrow(() => { addEcho(app, 'REBIND') }, 'REBIND method is supported.')
app.inject({
method: 'REBIND',
url: '/',
payload: { hello: 'world' }
}, (err, response) => {
t.assert.ifError(err)
t.assert.deepStrictEqual(response.json(), { hello: 'world' })
done()
})
})
test('addHttpMethod rejects fake http method', t => {
t.plan(1)
const fastify = Fastify()
t.assert.throws(() => { fastify.addHttpMethod('FOOO') }, /Provided method is invalid!/)
})

412
node_modules/fastify/test/http-methods/get.test.js generated vendored Normal file
View File

@@ -0,0 +1,412 @@
'use strict'
const { test } = require('node:test')
const { Client } = require('undici')
const fastify = require('../../fastify')()
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.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('shorthand - get (return null)', t => {
t.plan(1)
try {
fastify.get('/null', nullSchema, function (req, reply) {
reply.code(200).send(null)
})
t.assert.ok(true)
} catch (e) {
t.assert.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.assert.ok(true)
} catch (e) {
t.assert.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.assert.ok(true)
} catch (e) {
t.assert.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.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('missing schema - get', t => {
t.plan(1)
try {
fastify.get('/missing', function (req, reply) {
reply.code(200).send({ hello: 'world' })
})
t.assert.ok(true)
} catch (e) {
t.assert.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.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('empty response', t => {
t.plan(1)
try {
fastify.get('/empty', function (req, reply) {
reply.code(200).send()
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('send a falsy boolean', t => {
t.plan(1)
try {
fastify.get('/boolean', function (req, reply) {
reply.code(200).send(false)
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('shorthand - get, set port', t => {
t.plan(1)
try {
fastify.get('/port', headersSchema, function (req, reply) {
reply.code(200).send({ port: req.port })
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('get test', async t => {
t.after(() => { fastify.close() })
await fastify.listen({ port: 0 })
await t.test('shorthand - request get', async t => {
t.plan(4)
const response = await fetch('http://localhost:' + fastify.server.address().port, {
method: 'GET'
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.strictEqual(response.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
})
await t.test('shorthand - request get params schema', async t => {
t.plan(4)
const response = await fetch('http://localhost:' + fastify.server.address().port + '/params/world/123', {
method: 'GET'
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.strictEqual(response.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), { foo: 'world', test: 123 })
})
await t.test('shorthand - request get params schema error', async t => {
t.plan(3)
const response = await fetch('http://localhost:' + fastify.server.address().port + '/params/world/string', {
method: 'GET'
})
t.assert.ok(!response.ok)
t.assert.strictEqual(response.status, 400)
const body = await response.text()
t.assert.deepStrictEqual(JSON.parse(body), {
error: 'Bad Request',
code: 'FST_ERR_VALIDATION',
message: 'params/test must be integer',
statusCode: 400
})
})
await t.test('shorthand - request get headers schema', async t => {
t.plan(4)
const response = await fetch('http://localhost:' + fastify.server.address().port + '/headers', {
method: 'GET',
headers: {
'x-test': '1',
'Y-Test': '3'
}
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.json()
t.assert.strictEqual(body['x-test'], 1)
t.assert.strictEqual(body['y-test'], 3)
})
await t.test('shorthand - request get headers schema error', async t => {
t.plan(3)
const response = await fetch('http://localhost:' + fastify.server.address().port + '/headers', {
method: 'GET',
headers: {
'x-test': 'abc'
}
})
t.assert.ok(!response.ok)
t.assert.strictEqual(response.status, 400)
const body = await response.text()
t.assert.deepStrictEqual(JSON.parse(body), {
error: 'Bad Request',
code: 'FST_ERR_VALIDATION',
message: 'headers/x-test must be number',
statusCode: 400
})
})
await t.test('shorthand - request get querystring schema', async t => {
t.plan(4)
const response = await fetch('http://localhost:' + fastify.server.address().port + '/query?hello=123', {
method: 'GET'
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.strictEqual(response.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), { hello: 123 })
})
await t.test('shorthand - request get querystring schema error', async t => {
t.plan(3)
const response = await fetch('http://localhost:' + fastify.server.address().port + '/query?hello=world', {
method: 'GET'
})
t.assert.ok(!response.ok)
t.assert.strictEqual(response.status, 400)
const body = await response.text()
t.assert.deepStrictEqual(JSON.parse(body), {
error: 'Bad Request',
code: 'FST_ERR_VALIDATION',
message: 'querystring/hello must be integer',
statusCode: 400
})
})
await t.test('shorthand - request get missing schema', async t => {
t.plan(4)
const response = await fetch('http://localhost:' + fastify.server.address().port + '/missing', {
method: 'GET'
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.strictEqual(response.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
})
await t.test('shorthand - custom serializer', async t => {
t.plan(4)
const response = await fetch('http://localhost:' + fastify.server.address().port + '/custom-serializer', {
method: 'GET'
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.strictEqual(response.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
})
await t.test('shorthand - empty response', async t => {
t.plan(4)
const response = await fetch('http://localhost:' + fastify.server.address().port + '/empty', {
method: 'GET'
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.strictEqual(response.headers.get('content-length'), '0')
t.assert.deepStrictEqual(body.toString(), '')
})
await t.test('shorthand - send a falsy boolean', async t => {
t.plan(3)
const response = await fetch('http://localhost:' + fastify.server.address().port + '/boolean', {
method: 'GET'
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.deepStrictEqual(body.toString(), 'false')
})
await t.test('shorthand - send null value', async t => {
t.plan(3)
const response = await fetch('http://localhost:' + fastify.server.address().port + '/null', {
method: 'GET'
})
t.assert.ok(response.ok)
t.assert.strictEqual(response.status, 200)
const body = await response.text()
t.assert.deepStrictEqual(body.toString(), 'null')
})
await t.test('shorthand - request get headers - test fall back port', async t => {
t.plan(2)
const instance = new Client('http://localhost:' + fastify.server.address().port)
const response = await instance.request({
path: '/port',
method: 'GET',
headers: {
host: 'example.com'
}
})
t.assert.strictEqual(response.statusCode, 200)
const body = JSON.parse(await response.body.text())
t.assert.strictEqual(body.port, null)
})
})

263
node_modules/fastify/test/http-methods/head.test.js generated vendored Normal file
View File

@@ -0,0 +1,263 @@
'use strict'
const { test } = require('node:test')
const fastify = require('../../fastify')()
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.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('shorthand - custom head', t => {
t.plan(1)
try {
fastify.head('/proxy/*', function (req, reply) {
reply.headers({ 'x-foo': 'bar' })
reply.code(200).send(null)
})
fastify.get('/proxy/*', function (req, reply) {
reply.code(200).send(null)
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('shorthand - custom head with constraints', t => {
t.plan(1)
try {
fastify.head('/proxy/*', { constraints: { version: '1.0.0' } }, function (req, reply) {
reply.headers({ 'x-foo': 'bar' })
reply.code(200).send(null)
})
fastify.get('/proxy/*', { constraints: { version: '1.0.0' } }, function (req, reply) {
reply.code(200).send(null)
})
t.assert.ok(true)
} catch (e) {
t.assert.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.assert.ok(true)
} catch (e) {
t.assert.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.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('shorthand - head params', t => {
t.plan(1)
try {
fastify.head('/params/:foo/:test', paramsSchema, function (req, reply) {
reply.send(null)
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('shorthand - head, querystring schema', t => {
t.plan(1)
try {
fastify.head('/query', querySchema, function (req, reply) {
reply.code(200).send(null)
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('missing schema - head', t => {
t.plan(1)
try {
fastify.head('/missing', function (req, reply) {
reply.code(200).send(null)
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('head test', async t => {
t.after(() => { fastify.close() })
const fastifyServer = await fastify.listen({ port: 0 })
await t.test('shorthand - request head', async t => {
t.plan(2)
const result = await fetch(fastifyServer, {
method: 'HEAD'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
})
await t.test('shorthand - request head params schema', async t => {
t.plan(2)
const result = await fetch(`${fastifyServer}/params/world/123`, {
method: 'HEAD'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
})
await t.test('shorthand - request head params schema error', async t => {
t.plan(2)
const result = await fetch(`${fastifyServer}/params/world/string`, {
method: 'HEAD'
})
t.assert.ok(!result.ok)
t.assert.strictEqual(result.status, 400)
})
await t.test('shorthand - request head querystring schema', async t => {
t.plan(2)
const result = await fetch(`${fastifyServer}/query?hello=123`, {
method: 'HEAD'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
})
await t.test('shorthand - request head querystring schema error', async t => {
t.plan(2)
const result = await fetch(`${fastifyServer}/query?hello=world`, {
method: 'HEAD'
})
t.assert.ok(!result.ok)
t.assert.strictEqual(result.status, 400)
})
await t.test('shorthand - request head missing schema', async t => {
t.plan(2)
const result = await fetch(`${fastifyServer}/missing`, {
method: 'HEAD'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
})
await t.test('shorthand - request head custom head', async t => {
t.plan(3)
const result = await fetch(`${fastifyServer}/proxy/test`, {
method: 'HEAD'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.headers.get('x-foo'), 'bar')
t.assert.strictEqual(result.status, 200)
})
await t.test('shorthand - request head custom head with constraints', async t => {
t.plan(3)
const result = await fetch(`${fastifyServer}/proxy/test`, {
method: 'HEAD',
headers: {
version: '1.0.0'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.headers.get('x-foo'), 'bar')
t.assert.strictEqual(result.status, 200)
})
await t.test('shorthand - should not reset a head route', async t => {
t.plan(2)
const result = await fetch(`${fastifyServer}/query1`, {
method: 'HEAD'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
})
await t.test('shorthand - should set get and head route in the same api call', async t => {
t.plan(3)
const result = await fetch(`${fastifyServer}/query4`, {
method: 'HEAD'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.headers.get('x-foo'), 'bar')
t.assert.strictEqual(result.status, 200)
})
})

108
node_modules/fastify/test/http-methods/lock.test.js generated vendored Normal file
View File

@@ -0,0 +1,108 @@
'use strict'
const { test } = require('node:test')
const fastify = require('../../fastify')()
fastify.addHttpMethod('LOCK', { hasBody: true })
const bodySample = `<?xml version="1.0" encoding="utf-8" ?>
<D:lockinfo xmlns:D='DAV:'>
<D:lockscope> <D:exclusive/> </D:lockscope>
<D:locktype> <D:write/> </D:locktype>
<D:owner>
<D:href>http://example.org/~ejw/contact.html</D:href>
</D:owner>
</D:lockinfo> `
test('can be created - lock', t => {
t.plan(1)
try {
fastify.route({
method: 'LOCK',
url: '*',
handler: function (req, reply) {
reply
.code(200)
.send(`<?xml version="1.0" encoding="utf-8" ?>
<D:prop xmlns:D="DAV:">
<D:lockdiscovery>
<D:activelock>
<D:locktype>
<D:write/>
</D:locktype>
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:depth>infinity</D:depth>
<D:owner>
<D:href>http://example.org/~ejw/contact.html</D:href>
</D:owner>
<D:timeout>Second-604800</D:timeout>
<D:locktoken>
<D:href>urn:uuid:e71d4fae-5dec-22d6-fea5-00a0c91e6be4</:href>
</D:locktoken>
<D:lockroot>
<D:href>http://example.com/workspace/webdav/proposal.oc</D:href>
</D:lockroot>
</D:activelock>
</D:lockdiscovery>
</D:prop>`
)
}
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('lock test', async t => {
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => {
fastify.close()
})
// the body test uses a text/plain content type instead of application/xml because it requires
// a specific content type parser
await t.test('request with body - lock', async (t) => {
t.plan(3)
const result = await fetch(`${fastifyServer}/test/a.txt`, {
method: 'LOCK',
headers: { 'content-type': 'text/plain' },
body: bodySample
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
await t.test('request with body and no content type (415 error) - lock', async (t) => {
t.plan(3)
const result = await fetch(`${fastifyServer}/test/a.txt`, {
method: 'LOCK',
body: bodySample,
headers: { 'content-type': undefined }
})
t.assert.ok(!result.ok)
t.assert.strictEqual(result.status, 415)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
await t.test('request without body - lock', async (t) => {
t.plan(3)
const result = await fetch(`${fastifyServer}/test/a.txt`, {
method: 'LOCK',
headers: { 'content-type': 'text/plain' }
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
})

View File

@@ -0,0 +1,143 @@
'use strict'
const { test } = require('node:test')
const fastify = require('../../fastify')()
fastify.addHttpMethod('MKCALENDAR', { hasBody: true })
const bodySample = `<?xml version="1.0" encoding="UTF-8"?>
<B:mkcalendar xmlns:B="urn:ietf:params:xml:ns:caldav">
<A:set xmlns:A="DAV:">
<A:prop>
<B:calendar-free-busy-set>
<NO/>
</B:calendar-free-busy-set>
<E:calendar-order xmlns:E="http://apple.com/ns/ical/">0</E:calendar-order>
<B:supported-calendar-component-set>
<B:comp name="VEVENT"/>
</B:supported-calendar-component-set>
<A:displayname>CALENDAR_NAME</A:displayname>
<B:calendar-timezone>BEGIN:VCALENDAR&#13;
VERSION:2.0&#13;
</B:calendar-timezone>
</A:prop>
</A:set>
</B:mkcalendar>
`
test('can be created - mkcalendar', (t) => {
t.plan(1)
try {
fastify.route({
method: 'MKCALENDAR',
url: '*',
handler: function (req, reply) {
return reply.code(207).send(`<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:">
<D:response xmlns:lp1="DAV:">
<D:href>/</D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype>
<D:collection/>
</lp1:resourcetype>
<lp1:creationdate>2022-04-13T12:35:30Z</lp1:creationdate>
<lp1:getlastmodified>Wed, 13 Apr 2022 12:35:30 GMT</lp1:getlastmodified>
<lp1:getetag>"e0-5dc8869b53ef1"</lp1:getetag>
<D:supportedlock>
<D:lockentry>
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope>
<D:shared/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>`)
}
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('mkcalendar test', async t => {
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => {
fastify.close()
})
await t.test('request - mkcalendar', async t => {
t.plan(2)
const result = await fetch(`${fastifyServer}/`, {
method: 'MKCALENDAR'
})
t.assert.strictEqual(result.status, 207)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
await t.test('request with other path - mkcalendar', async t => {
t.plan(2)
const result = await fetch(`${fastifyServer}/test`, {
method: 'MKCALENDAR'
})
t.assert.strictEqual(result.status, 207)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
// the body test uses a text/plain content type instead of application/xml because it requires
// a specific content type parser
await t.test('request with body - mkcalendar', async t => {
t.plan(3)
const result = await fetch(`${fastifyServer}/test`, {
method: 'MKCALENDAR',
headers: { 'content-type': 'text/plain' },
body: bodySample
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 207)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
await t.test('request with body and no content type (415 error) - mkcalendar', async t => {
t.plan(3)
const result = await fetch(`${fastifyServer}/test`, {
method: 'MKCALENDAR',
body: bodySample,
headers: { 'content-type': undefined }
})
t.assert.ok(!result.ok)
t.assert.strictEqual(result.status, 415)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
await t.test('request without body - mkcalendar', async t => {
t.plan(3)
const result = await fetch(`${fastifyServer}/test`, {
method: 'MKCALENDAR'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 207)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
})

35
node_modules/fastify/test/http-methods/mkcol.test.js generated vendored Normal file
View File

@@ -0,0 +1,35 @@
'use strict'
const { test } = require('node:test')
const fastify = require('../../')()
fastify.addHttpMethod('MKCOL')
test('can be created - mkcol', t => {
t.plan(1)
try {
fastify.route({
method: 'MKCOL',
url: '*',
handler: function (req, reply) {
reply.code(201).send()
}
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('mkcol test', async t => {
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
await t.test('request - mkcol', async t => {
t.plan(2)
const result = await fetch(`${fastifyServer}/test/`, {
method: 'MKCOL'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 201)
})
})

42
node_modules/fastify/test/http-methods/move.test.js generated vendored Normal file
View File

@@ -0,0 +1,42 @@
'use strict'
const { test } = require('node:test')
const fastify = require('../../')()
fastify.addHttpMethod('MOVE')
test('shorthand - move', t => {
t.plan(1)
try {
fastify.route({
method: 'MOVE',
url: '*',
handler: function (req, reply) {
const destination = req.headers.destination
reply.code(201)
.header('location', destination)
.send()
}
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('move test', async t => {
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
await t.test('request - move', async t => {
t.plan(3)
const result = await fetch(`${fastifyServer}/test.txt`, {
method: 'MOVE',
headers: {
Destination: '/test2.txt'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 201)
t.assert.strictEqual(result.headers.get('location'), '/test2.txt')
})
})

136
node_modules/fastify/test/http-methods/propfind.test.js generated vendored Normal file
View File

@@ -0,0 +1,136 @@
'use strict'
const { test } = require('node:test')
const fastify = require('../../')()
fastify.addHttpMethod('PROPFIND', { hasBody: true })
const bodySample = `<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:prop xmlns:R="http://ns.example.com/boxschema/">
<R:bigbox/> <R:author/> <R:DingALing/> <R:Random/>
</D:prop>
</D:propfind>
`
test('can be created - propfind', t => {
t.plan(1)
try {
fastify.route({
method: 'PROPFIND',
url: '*',
handler: function (req, reply) {
return reply.code(207)
.send(`<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:">
<D:response xmlns:lp1="DAV:">
<D:href>/</D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype>
<D:collection/>
</lp1:resourcetype>
<lp1:creationdate>2022-04-13T12:35:30Z</lp1:creationdate>
<lp1:getlastmodified>Wed, 13 Apr 2022 12:35:30 GMT</lp1:getlastmodified>
<lp1:getetag>"e0-5dc8869b53ef1"</lp1:getetag>
<D:supportedlock>
<D:lockentry>
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope>
<D:shared/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>`
)
}
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('propfind test', async t => {
await fastify.listen({ port: 0 })
t.after(() => {
fastify.close()
})
await t.test('request - propfind', async t => {
t.plan(3)
const result = await fetch(`http://localhost:${fastify.server.address().port}/`, {
method: 'PROPFIND'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 207)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
await t.test('request with other path - propfind', async t => {
t.plan(3)
const result = await fetch(`http://localhost:${fastify.server.address().port}/test`, {
method: 'PROPFIND'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 207)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
// the body test uses a text/plain content type instead of application/xml because it requires
// a specific content type parser
await t.test('request with body - propfind', async t => {
t.plan(3)
const result = await fetch(`http://localhost:${fastify.server.address().port}/test`, {
method: 'PROPFIND',
headers: { 'content-type': 'text/plain' },
body: bodySample
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 207)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
await t.test('request with body and no content type (415 error) - propfind', async t => {
t.plan(3)
const result = await fetch(`http://localhost:${fastify.server.address().port}/test`, {
method: 'PROPFIND',
body: bodySample,
headers: { 'content-type': '' }
})
t.assert.ok(!result.ok)
t.assert.strictEqual(result.status, 415)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
await t.test('request without body - propfind', async t => {
t.plan(3)
const result = await fetch(`http://localhost:${fastify.server.address().port}/test`, {
method: 'PROPFIND'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 207)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
})

View File

@@ -0,0 +1,105 @@
'use strict'
const { test } = require('node:test')
const fastify = require('../../')()
fastify.addHttpMethod('PROPPATCH', { hasBody: true })
const bodySample = `<?xml version="1.0" encoding="utf-8" ?>
<D:propertyupdate xmlns:D="DAV:"
xmlns:Z="http://ns.example.com/standards/z39.50/">
<D:set>
<D:prop>
<Z:Authors>
<Z:Author>Jim Whitehead</Z:Author>
<Z:Author>Roy Fielding</Z:Author>
</Z:Authors>
</D:prop>
</D:set>
<D:remove>
<D:prop>
<Z:Copyright-Owner/>
</D:prop>
</D:remove>
</D:propertyupdate>`
test('shorthand - proppatch', t => {
t.plan(1)
try {
fastify.route({
method: 'PROPPATCH',
url: '*',
handler: function (req, reply) {
reply
.code(207)
.send(`<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:"
xmlns:Z="http://ns.example.com/standards/z39.50/">
<D:response>
<D:href>http://www.example.com/bar.html</D:href>
<D:propstat>
<D:prop>
<Z:Authors/>
</D:prop>
<D:status>HTTP/1.1 424 Failed Dependency</D:status>
</D:propstat>
<D:propstat>
<D:prop>
<Z:Copyright-Owner/>
</D:prop>
<D:status>HTTP/1.1 409 Conflict</D:status>
</D:propstat>
<D:responsedescription> Copyright Owner cannot be deleted or altered.</D:responsedescription>
</D:response>
</D:multistatus>`
)
}
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('proppatch test', async t => {
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
// the body test uses a text/plain content type instead of application/xml because it requires
// a specific content type parser
await t.test('request with body - proppatch', async t => {
t.plan(3)
const result = await fetch(`${fastifyServer}/test/a.txt`, {
method: 'PROPPATCH',
headers: { 'content-type': 'text/plain' },
body: bodySample
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 207)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
await t.test('request with body and no content type (415 error) - proppatch', async t => {
t.plan(3)
const result = await fetch(`${fastifyServer}/test/a.txt`, {
method: 'PROPPATCH',
body: bodySample,
headers: { 'content-type': undefined }
})
t.assert.ok(!result.ok)
t.assert.strictEqual(result.status, 415)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
await t.test('request without body - proppatch', async t => {
t.plan(3)
const result = await fetch(`${fastifyServer}/test/a.txt`, {
method: 'PROPPATCH'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 207)
const body = await result.text()
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
})
})

142
node_modules/fastify/test/http-methods/report.test.js generated vendored Normal file
View File

@@ -0,0 +1,142 @@
'use strict'
const { test } = require('node:test')
const fastify = require('../../fastify')()
fastify.addHttpMethod('REPORT', { hasBody: true })
const bodySample = `<?xml version="1.0" encoding="UTF-8"?>
<B:calendar-query xmlns:B="urn:ietf:params:xml:ns:caldav">
<A:prop xmlns:A="DAV:">
<A:getetag/>
<A:getcontenttype/>
</A:prop>
<B:filter>
<B:comp-filter name="VCALENDAR">
<B:comp-filter name="VEVENT">
<B:time-range start="20170215T000000Z"/>
</B:comp-filter>
</B:comp-filter>
</B:filter>
</B:calendar-query>
`
test('can be created - report', (t) => {
t.plan(1)
try {
fastify.route({
method: 'REPORT',
url: '*',
handler: function (req, reply) {
return reply.code(207).send(`<?xml version="1.0" encoding="utf-8"?>
<D:multistatus xmlns:D="DAV:">
<D:response xmlns:lp1="DAV:">
<D:href>/</D:href>
<D:propstat>
<D:prop>
<lp1:resourcetype>
<D:collection/>
</lp1:resourcetype>
<lp1:creationdate>2022-04-13T12:35:30Z</lp1:creationdate>
<lp1:getlastmodified>Wed, 13 Apr 2022 12:35:30 GMT</lp1:getlastmodified>
<lp1:getetag>"e0-5dc8869b53ef1"</lp1:getetag>
<D:supportedlock>
<D:lockentry>
<D:lockscope>
<D:exclusive/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
<D:lockentry>
<D:lockscope>
<D:shared/>
</D:lockscope>
<D:locktype>
<D:write/>
</D:locktype>
</D:lockentry>
</D:supportedlock>
<D:lockdiscovery/>
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>`)
}
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('report test', async t => {
await fastify.listen({ port: 0 })
t.after(() => {
fastify.close()
})
await t.test('request - report', async (t) => {
t.plan(3)
const result = await fetch(`http://localhost:${fastify.server.address().port}/`, {
method: 'REPORT'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 207)
t.assert.strictEqual(result.headers.get('content-length'), '' + (await result.text()).length)
})
await t.test('request with other path - report', async (t) => {
t.plan(3)
const result = await fetch(`http://localhost:${fastify.server.address().port}/test`, {
method: 'REPORT'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 207)
t.assert.strictEqual(result.headers.get('content-length'), '' + (await result.text()).length)
})
// the body test uses a text/plain content type instead of application/xml because it requires
// a specific content type parser
await t.test('request with body - report', async (t) => {
t.plan(3)
const result = await fetch(`http://localhost:${fastify.server.address().port}/test`, {
method: 'REPORT',
headers: { 'content-type': 'text/plain' },
body: bodySample
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 207)
t.assert.strictEqual(result.headers.get('content-length'), '' + (await result.text()).length)
})
await t.test('request with body and no content type (415 error) - report', async (t) => {
t.plan(3)
const result = await fetch(`http://localhost:${fastify.server.address().port}/test`, {
method: 'REPORT',
body: bodySample,
headers: { 'content-type': '' }
})
t.assert.ok(!result.ok)
t.assert.strictEqual(result.status, 415)
t.assert.strictEqual(result.headers.get('content-length'), '' + (await result.text()).length)
})
await t.test('request without body - report', async (t) => {
t.plan(3)
const result = await fetch(`http://localhost:${fastify.server.address().port}/test`, {
method: 'REPORT'
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 207)
t.assert.strictEqual(result.headers.get('content-length'), '' + (await result.text()).length)
})
})

233
node_modules/fastify/test/http-methods/search.test.js generated vendored Normal file
View File

@@ -0,0 +1,233 @@
'use strict'
const { test } = require('node:test')
const fastify = require('../../fastify')()
fastify.addHttpMethod('SEARCH', { hasBody: true })
const schema = {
response: {
'2xx': {
type: 'object',
properties: {
hello: {
type: 'string'
}
}
}
}
}
const querySchema = {
querystring: {
type: 'object',
properties: {
hello: {
type: 'integer'
}
}
}
}
const paramsSchema = {
params: {
type: 'object',
properties: {
foo: {
type: 'string'
},
test: {
type: 'integer'
}
}
}
}
const bodySchema = {
body: {
type: 'object',
properties: {
foo: {
type: 'string'
},
test: {
type: 'integer'
}
}
}
}
test('search', t => {
t.plan(1)
try {
fastify.route({
method: 'SEARCH',
url: '/',
schema,
handler: function (request, reply) {
reply.code(200).send({ hello: 'world' })
}
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('search, params schema', t => {
t.plan(1)
try {
fastify.route({
method: 'SEARCH',
url: '/params/:foo/:test',
schema: paramsSchema,
handler: function (request, reply) {
reply.code(200).send(request.params)
}
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('search, querystring schema', t => {
t.plan(1)
try {
fastify.route({
method: 'SEARCH',
url: '/query',
schema: querySchema,
handler: function (request, reply) {
reply.code(200).send(request.query)
}
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('search, body schema', t => {
t.plan(1)
try {
fastify.route({
method: 'SEARCH',
url: '/body',
schema: bodySchema,
handler: function (request, reply) {
reply.code(200).send(request.body)
}
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('search test', async t => {
await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
const url = `http://localhost:${fastify.server.address().port}`
await t.test('request - search', async t => {
t.plan(4)
const result = await fetch(url, {
method: 'SEARCH'
})
const body = await result.text()
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), { hello: 'world' })
})
await t.test('request search params schema', async t => {
t.plan(4)
const result = await fetch(`${url}/params/world/123`, {
method: 'SEARCH'
})
const body = await result.text()
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), { foo: 'world', test: 123 })
})
await t.test('request search params schema error', async t => {
t.plan(3)
const result = await fetch(`${url}/params/world/string`, {
method: 'SEARCH'
})
const body = await result.text()
t.assert.strictEqual(result.status, 400)
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), {
error: 'Bad Request',
code: 'FST_ERR_VALIDATION',
message: 'params/test must be integer',
statusCode: 400
})
})
await t.test('request search querystring schema', async t => {
t.plan(4)
const result = await fetch(`${url}/query?hello=123`, {
method: 'SEARCH'
})
const body = await result.text()
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), { hello: 123 })
})
await t.test('request search querystring schema error', async t => {
t.plan(3)
const result = await fetch(`${url}/query?hello=world`, {
method: 'SEARCH'
})
const body = await result.text()
t.assert.strictEqual(result.status, 400)
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), {
error: 'Bad Request',
code: 'FST_ERR_VALIDATION',
message: 'querystring/hello must be integer',
statusCode: 400
})
})
await t.test('request search body schema', async t => {
t.plan(4)
const replyBody = { foo: 'bar', test: 5 }
const result = await fetch(`${url}/body`, {
method: 'SEARCH',
body: JSON.stringify(replyBody),
headers: { 'content-type': 'application/json' }
})
const body = await result.text()
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), replyBody)
})
await t.test('request search body schema error', async t => {
t.plan(4)
const result = await fetch(`${url}/body`, {
method: 'SEARCH',
body: JSON.stringify({ foo: 'bar', test: 'test' }),
headers: { 'content-type': 'application/json' }
})
const body = await result.text()
t.assert.ok(!result.ok)
t.assert.strictEqual(result.status, 400)
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), {
error: 'Bad Request',
code: 'FST_ERR_VALIDATION',
message: 'body/test must be integer',
statusCode: 400
})
})
})

21
node_modules/fastify/test/http-methods/trace.test.js generated vendored Normal file
View File

@@ -0,0 +1,21 @@
'use strict'
const { test } = require('node:test')
const fastify = require('../../fastify')()
fastify.addHttpMethod('TRACE')
test('shorthand - trace', t => {
t.plan(1)
try {
fastify.route({
method: 'TRACE',
url: '/',
handler: function (request, reply) {
reply.code(200).send('TRACE OK')
}
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})

38
node_modules/fastify/test/http-methods/unlock.test.js generated vendored Normal file
View File

@@ -0,0 +1,38 @@
'use strict'
const { test } = require('node:test')
const fastify = require('../../fastify')()
fastify.addHttpMethod('UNLOCK')
test('can be created - unlock', t => {
t.plan(1)
try {
fastify.route({
method: 'UNLOCK',
url: '*',
handler: function (req, reply) {
reply.code(204).send()
}
})
t.assert.ok(true)
} catch (e) {
t.assert.fail()
}
})
test('unlock test', async t => {
const fastifyServer = await fastify.listen({ port: 0 })
t.after(() => { fastify.close() })
await t.test('request - unlock', async t => {
t.plan(2)
const result = await fetch(`${fastifyServer}/test/a.txt`, {
method: 'UNLOCK',
headers: {
'Lock-Token': 'urn:uuid:a515cfa4-5da4-22e1-f5b5-00a0451e6bf7'
}
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 204)
})
})

182
node_modules/fastify/test/http2/closing.test.js generated vendored Normal file
View File

@@ -0,0 +1,182 @@
'use strict'
const { test } = require('node:test')
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')
test.before(buildCertificate)
const isNode24OrGreater = Number(process.versions.node.split('.')[0]) >= 24
test('http/2 request while fastify closing Node <24', { skip: isNode24OrGreater }, (t, done) => {
const fastify = Fastify({
http2: true
})
t.assert.ok('http2 successfully loaded')
fastify.get('/', () => Promise.resolve({}))
t.after(() => { fastify.close() })
fastify.listen({ port: 0 }, err => {
t.assert.ifError(err)
const url = getServerUrl(fastify)
const session = http2.connect(url, function () {
this.request({
':method': 'GET',
':path': '/'
}).on('response', headers => {
t.assert.strictEqual(headers[':status'], 503)
done()
this.destroy()
}).on('error', () => {
// Nothing to do here,
// we are not interested in this error that might
// happen or not
})
session.on('error', () => {
// Nothing to do here,
// we are not interested in this error that might
// happen or not
done()
})
fastify.close()
})
})
})
test('http/2 request while fastify closing Node >=24', { skip: !isNode24OrGreater }, (t, done) => {
const fastify = Fastify({
http2: true
})
t.assert.ok('http2 successfully loaded')
fastify.get('/', () => Promise.resolve({}))
t.after(() => { fastify.close() })
fastify.listen({ port: 0 }, err => {
t.assert.ifError(err)
const url = getServerUrl(fastify)
const session = http2.connect(url, function () {
session.on('error', () => {
// Nothing to do here,
// we are not interested in this error that might
// happen or not
})
session.on('close', () => {
done()
})
fastify.close()
})
})
})
test('http/2 request while fastify closing - return503OnClosing: false', { skip: isNode24OrGreater }, (t, done) => {
const fastify = Fastify({
http2: true,
return503OnClosing: false
})
t.after(() => { fastify.close() })
fastify.get('/', () => Promise.resolve({}))
fastify.listen({ port: 0 }, err => {
t.assert.ifError(err)
const url = getServerUrl(fastify)
const session = http2.connect(url, function () {
this.request({
':method': 'GET',
':path': '/'
}).on('response', headers => {
t.assert.strictEqual(headers[':status'], 200)
done()
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
done()
})
})
})
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()
})
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()
})
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.assert.strictEqual(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()
})

109
node_modules/fastify/test/http2/constraint.test.js generated vendored Normal file
View File

@@ -0,0 +1,109 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('../..')
const h2url = require('h2url')
const alpha = { res: 'alpha' }
const beta = { res: 'beta' }
const { buildCertificate } = require('../build-certificate')
test.before(buildCertificate)
test('A route supports host constraints under http2 protocol and secure connection', async (t) => {
t.plan(5)
let fastify
try {
fastify = Fastify({
http2: true,
https: {
key: global.context.key,
cert: global.context.cert
}
})
t.assert.ok(true, 'Key/cert successfully loaded')
} catch (e) {
t.assert.fail('Key/cert loading failed')
}
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.route({
method: 'GET',
url: '/hostname_port',
constraints: { host: constrain },
handler: function (req, reply) {
reply.code(200).send({ ...beta, hostname: req.hostname })
}
})
t.after(() => { fastify.close() })
await fastify.listen({ port: 0 })
await 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.assert.strictEqual(res.headers[':status'], 200)
t.assert.strictEqual(res.headers['content-length'], '' + JSON.stringify(alpha).length)
t.assert.deepStrictEqual(JSON.parse(res.body), alpha)
})
await 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.assert.strictEqual(res.headers[':status'], 200)
t.assert.strictEqual(res.headers['content-length'], '' + JSON.stringify(beta).length)
t.assert.deepStrictEqual(JSON.parse(res.body), beta)
})
await 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.assert.strictEqual(res.headers[':status'], 404)
})
await t.test('https get request - constrain - verify hostname and port from request', async (t) => {
t.plan(1)
const url = `https://localhost:${fastify.server.address().port}/hostname_port`
const res = await h2url.concat({
url,
headers: {
':authority': constrain
}
})
const body = JSON.parse(res.body)
t.assert.strictEqual(body.hostname, constrain)
})
})

34
node_modules/fastify/test/http2/head.test.js generated vendored Normal file
View File

@@ -0,0 +1,34 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('../..')
const h2url = require('h2url')
const msg = { hello: 'world' }
test('http2 HEAD test', async (t) => {
let fastify
try {
fastify = Fastify({
http2: true
})
t.assert.ok(true, 'http2 successfully loaded')
} catch (e) {
t.assert.fail('http2 loading failed')
}
fastify.all('/', function (req, reply) {
reply.code(200).send(msg)
})
t.after(() => { fastify.close() })
await fastify.listen({ port: 0 })
await t.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.assert.strictEqual(res.headers[':status'], 200)
})
})

68
node_modules/fastify/test/http2/plain.test.js generated vendored Normal file
View File

@@ -0,0 +1,68 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('../..')
const h2url = require('h2url')
const msg = { hello: 'world' }
test('http2 plain test', async t => {
let fastify
try {
fastify = Fastify({
http2: true
})
t.assert.ok(true, 'http2 successfully loaded')
} catch (e) {
t.assert.fail('http2 loading failed')
}
fastify.get('/', function (req, reply) {
reply.code(200).send(msg)
})
fastify.get('/host', function (req, reply) {
reply.code(200).send(req.host)
})
fastify.get('/hostname_port', function (req, reply) {
reply.code(200).send({ hostname: req.hostname, port: req.port })
})
t.after(() => { fastify.close() })
await fastify.listen({ port: 0 })
await t.test('http get request', async (t) => {
t.plan(3)
const url = `http://localhost:${fastify.server.address().port}`
const res = await h2url.concat({ url })
t.assert.strictEqual(res.headers[':status'], 200)
t.assert.strictEqual(res.headers['content-length'], '' + JSON.stringify(msg).length)
t.assert.deepStrictEqual(JSON.parse(res.body), msg)
})
await t.test('http host', async (t) => {
t.plan(1)
const host = `localhost:${fastify.server.address().port}`
const url = `http://${host}/host`
const res = await h2url.concat({ url })
t.assert.strictEqual(res.body, host)
})
await t.test('http hostname and port', async (t) => {
t.plan(2)
const host = `localhost:${fastify.server.address().port}`
const url = `http://${host}/hostname_port`
const res = await h2url.concat({ url })
t.assert.strictEqual(JSON.parse(res.body).hostname, host.split(':')[0])
t.assert.strictEqual(JSON.parse(res.body).port, parseInt(host.split(':')[1]))
})
})

View File

@@ -0,0 +1,113 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('../..')
const h2url = require('h2url')
const msg = { hello: 'world' }
const { buildCertificate } = require('../build-certificate')
const { Agent } = require('undici')
test.before(buildCertificate)
test('secure with fallback', async (t) => {
t.plan(6)
let fastify
try {
fastify = Fastify({
http2: true,
https: {
allowHTTP1: true,
key: global.context.key,
cert: global.context.cert
}
})
t.assert.ok(true, 'Key/cert successfully loaded')
} catch (e) {
t.assert.fail('Key/cert loading failed')
}
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')
})
t.after(() => fastify.close())
const fastifyServer = await fastify.listen({ port: 0 })
await t.test('https get error', async (t) => {
t.plan(1)
const url = `${fastifyServer}/error`
const res = await h2url.concat({ url })
t.assert.strictEqual(res.headers[':status'], 500)
})
await t.test('https post', async (t) => {
t.plan(2)
const res = await h2url.concat({
url: fastifyServer,
method: 'POST',
body: JSON.stringify({ hello: 'http2' }),
headers: {
'content-type': 'application/json'
}
})
t.assert.strictEqual(res.headers[':status'], 200)
t.assert.deepStrictEqual(JSON.parse(res.body), { hello: 'http2' })
})
await t.test('https get request', async (t) => {
t.plan(3)
const res = await h2url.concat({ url: fastifyServer })
t.assert.strictEqual(res.headers[':status'], 200)
t.assert.strictEqual(res.headers['content-length'], '' + JSON.stringify(msg).length)
t.assert.deepStrictEqual(JSON.parse(res.body), msg)
})
await t.test('http1 get request', async t => {
t.plan(4)
const result = await fetch(fastifyServer, {
dispatcher: new Agent({
connect: {
rejectUnauthorized: false
}
})
})
const body = await result.text()
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.strictEqual(result.headers.get('content-length'), '' + body.length)
t.assert.deepStrictEqual(JSON.parse(body), msg)
})
await t.test('http1 get error', async t => {
t.plan(2)
const result = await fetch(`${fastifyServer}/error`, {
dispatcher: new Agent({
connect: {
rejectUnauthorized: false
}
})
})
t.assert.ok(!result.ok)
t.assert.strictEqual(result.status, 500)
})
})

67
node_modules/fastify/test/http2/secure.test.js generated vendored Normal file
View File

@@ -0,0 +1,67 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('../..')
const h2url = require('h2url')
const msg = { hello: 'world' }
const { buildCertificate } = require('../build-certificate')
test.before(buildCertificate)
test('secure', async (t) => {
t.plan(4)
let fastify
try {
fastify = Fastify({
http2: true,
https: {
key: global.context.key,
cert: global.context.cert
}
})
t.assert.ok(true, 'Key/cert successfully loaded')
} catch (e) {
t.assert.fail('Key/cert loading failed')
}
fastify.get('/', function (req, reply) {
reply.code(200).send(msg)
})
fastify.get('/proto', function (req, reply) {
reply.code(200).send({ proto: req.protocol })
})
fastify.get('/hostname_port', function (req, reply) {
reply.code(200).send({ hostname: req.hostname, port: req.port })
})
t.after(() => { fastify.close() })
await fastify.listen({ port: 0 })
await 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.assert.strictEqual(res.headers[':status'], 200)
t.assert.strictEqual(res.headers['content-length'], '' + JSON.stringify(msg).length)
t.assert.deepStrictEqual(JSON.parse(res.body), msg)
})
await t.test('https get request without trust proxy - protocol', async (t) => {
t.plan(2)
const url = `https://localhost:${fastify.server.address().port}/proto`
t.assert.deepStrictEqual(JSON.parse((await h2url.concat({ url })).body), { proto: 'https' })
t.assert.deepStrictEqual(JSON.parse((await h2url.concat({ url, headers: { 'X-Forwarded-Proto': 'lorem' } })).body), { proto: 'https' })
})
await t.test('https get request - test hostname and port', async (t) => {
t.plan(2)
const url = `https://localhost:${fastify.server.address().port}/hostname_port`
const parsedbody = JSON.parse((await h2url.concat({ url })).body)
t.assert.strictEqual(parsedbody.hostname, 'localhost')
t.assert.strictEqual(parsedbody.port, fastify.server.address().port)
})
})

View File

@@ -0,0 +1,34 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('../..')
const h2url = require('h2url')
const msg = { hello: 'world' }
test('http2 unknown http method', async t => {
const fastify = Fastify({
http2: true
})
fastify.get('/', function (req, reply) {
reply.code(200).send(msg)
})
t.after(() => { fastify.close() })
await fastify.listen({ port: 0 })
await t.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.assert.strictEqual(res.headers[':status'], 404)
t.assert.deepStrictEqual(JSON.parse(res.body), {
statusCode: 404,
code: 'FST_ERR_NOT_FOUND',
error: 'Not Found',
message: 'Not Found'
})
})
})

View File

@@ -0,0 +1,58 @@
'use strict'
const { test } = require('node:test')
const Fastify = require('../..')
const https = require('node:https')
const dns = require('node:dns').promises
const { buildCertificate } = require('../build-certificate')
const { Agent } = require('undici')
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(5)
const fastify = Fastify({
serverFactory: (handler, opts) => {
t.assert.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.after(() => { fastify.close() })
fastify.get('/', (req, reply) => {
t.assert.ok(req.raw.custom)
reply.send({ hello: 'world' })
})
await fastify.listen({ port: 0 })
const result = await fetch('https://localhost:' + fastify.server.address().port, {
dispatcher: new Agent({
connect: {
rejectUnauthorized: false
}
})
})
t.assert.ok(result.ok)
t.assert.strictEqual(result.status, 200)
t.assert.deepStrictEqual(await result.json(), { hello: 'world' })
})
}
setup()

Some files were not shown because too many files have changed in this diff Show More