CoolFace
Apppublic

strong-tie/inbound-calls

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
request-error.test.js537 linesDownload Raw Back to test
1'use strict'2 3const { connect } = require('node:net')4const sget = require('simple-get').concat5const t = require('tap')6const test = t.test7const Fastify = require('..')8const { kRequest } = require('../lib/symbols.js')9 10test('default 400 on request error', t => {11  t.plan(4)12 13  const fastify = Fastify()14 15  fastify.post('/', function (req, reply) {16    reply.send({ hello: 'world' })17  })18 19  fastify.inject({20    method: 'POST',21    url: '/',22    simulate: {23      error: true24    },25    body: {26      text: '12345678901234567890123456789012345678901234567890'27    }28  }, (err, res) => {29    t.error(err)30    t.equal(res.statusCode, 400)31    t.equal(res.headers['content-type'], 'application/json; charset=utf-8')32    t.same(JSON.parse(res.payload), {33      error: 'Bad Request',34      message: 'Simulated',35      statusCode: 40036    })37  })38})39 40test('default 400 on request error with custom error handler', t => {41  t.plan(6)42 43  const fastify = Fastify()44 45  fastify.setErrorHandler(function (err, request, reply) {46    t.type(request, 'object')47    t.type(request, fastify[kRequest].parent)48    reply49      .code(err.statusCode)50      .type('application/json; charset=utf-8')51      .send(err)52  })53 54  fastify.post('/', function (req, reply) {55    reply.send({ hello: 'world' })56  })57 58  fastify.inject({59    method: 'POST',60    url: '/',61    simulate: {62      error: true63    },64    body: {65      text: '12345678901234567890123456789012345678901234567890'66    }67  }, (err, res) => {68    t.error(err)69    t.equal(res.statusCode, 400)70    t.equal(res.headers['content-type'], 'application/json; charset=utf-8')71    t.same(JSON.parse(res.payload), {72      error: 'Bad Request',73      message: 'Simulated',74      statusCode: 40075    })76  })77})78 79test('default clientError handler ignores ECONNRESET', t => {80  t.plan(3)81 82  let logs = ''83  let response = ''84 85  const fastify = Fastify({86    bodyLimit: 1,87    keepAliveTimeout: 100,88    logger: {89      level: 'trace',90      stream: {91        write () {92          logs += JSON.stringify(arguments)93        }94      }95    }96  })97 98  fastify.get('/', (request, reply) => {99    reply.send('OK')100 101    process.nextTick(() => {102      const error = new Error()103      error.code = 'ECONNRESET'104 105      fastify.server.emit('clientError', error, request.raw.socket)106    })107  })108 109  fastify.listen({ port: 0 }, function (err) {110    t.error(err)111    t.teardown(() => { fastify.close() })112 113    const client = connect(fastify.server.address().port)114 115    client.on('data', chunk => {116      response += chunk.toString('utf-8')117    })118 119    client.on('end', () => {120      t.match(response, /^HTTP\/1.1 200 OK/)121      t.notMatch(logs, /ECONNRESET/)122    })123 124    client.resume()125    client.write('GET / HTTP/1.1\r\n')126    client.write('Host: example.com\r\n')127    client.write('Connection: close\r\n')128    client.write('\r\n\r\n')129  })130})131 132test('default clientError handler ignores sockets in destroyed state', t => {133  t.plan(1)134 135  const fastify = Fastify({136    bodyLimit: 1,137    keepAliveTimeout: 100138  })139  fastify.server.on('clientError', () => {140    // this handler is called after default handler, so we can make sure end was not called141    t.pass()142  })143  fastify.server.emit('clientError', new Error(), {144    destroyed: true,145    end () {146      t.fail('end should not be called')147    },148    destroy () {149      t.fail('destroy should not be called')150    }151  })152})153 154test('default clientError handler destroys sockets in writable state', t => {155  t.plan(2)156 157  const fastify = Fastify({158    bodyLimit: 1,159    keepAliveTimeout: 100160  })161 162  fastify.server.emit('clientError', new Error(), {163    destroyed: false,164    writable: true,165    encrypted: true,166    end () {167      t.fail('end should not be called')168    },169    destroy () {170      t.pass('destroy should be called')171    },172    write (response) {173      t.match(response, /^HTTP\/1.1 400 Bad Request/)174    }175  })176})177 178test('default clientError handler destroys http sockets in non-writable state', t => {179  t.plan(1)180 181  const fastify = Fastify({182    bodyLimit: 1,183    keepAliveTimeout: 100184  })185 186  fastify.server.emit('clientError', new Error(), {187    destroyed: false,188    writable: false,189    end () {190      t.fail('end should not be called')191    },192    destroy () {193      t.pass('destroy should be called')194    },195    write (response) {196      t.fail('write should not be called')197    }198  })199})200 201test('error handler binding', t => {202  t.plan(5)203 204  const fastify = Fastify()205 206  fastify.setErrorHandler(function (err, request, reply) {207    t.equal(this, fastify)208    reply209      .code(err.statusCode)210      .type('application/json; charset=utf-8')211      .send(err)212  })213 214  fastify.post('/', function (req, reply) {215    reply.send({ hello: 'world' })216  })217 218  fastify.inject({219    method: 'POST',220    url: '/',221    simulate: {222      error: true223    },224    body: {225      text: '12345678901234567890123456789012345678901234567890'226    }227  }, (err, res) => {228    t.error(err)229    t.equal(res.statusCode, 400)230    t.equal(res.headers['content-type'], 'application/json; charset=utf-8')231    t.same(JSON.parse(res.payload), {232      error: 'Bad Request',233      message: 'Simulated',234      statusCode: 400235    })236  })237})238 239test('encapsulated error handler binding', t => {240  t.plan(7)241 242  const fastify = Fastify()243 244  fastify.register(function (app, opts, done) {245    app.decorate('hello', 'world')246    t.equal(app.hello, 'world')247    app.post('/', function (req, reply) {248      reply.send({ hello: 'world' })249    })250    app.setErrorHandler(function (err, request, reply) {251      t.equal(this.hello, 'world')252      reply253        .code(err.statusCode)254        .type('application/json; charset=utf-8')255        .send(err)256    })257    done()258  })259 260  fastify.inject({261    method: 'POST',262    url: '/',263    simulate: {264      error: true265    },266    body: {267      text: '12345678901234567890123456789012345678901234567890'268    }269  }, (err, res) => {270    t.error(err)271    t.equal(res.statusCode, 400)272    t.equal(res.headers['content-type'], 'application/json; charset=utf-8')273    t.same(res.json(), {274      error: 'Bad Request',275      message: 'Simulated',276      statusCode: 400277    })278    t.equal(fastify.hello, undefined)279  })280})281 282test('default clientError replies with bad request on reused keep-alive connection', t => {283  t.plan(2)284 285  let response = ''286 287  const fastify = Fastify({288    bodyLimit: 1,289    keepAliveTimeout: 100290  })291 292  fastify.get('/', (request, reply) => {293    reply.send('OK\n')294  })295 296  fastify.listen({ port: 0 }, function (err) {297    t.error(err)298    fastify.server.unref()299 300    const client = connect(fastify.server.address().port)301 302    client.on('data', chunk => {303      response += chunk.toString('utf-8')304    })305 306    client.on('end', () => {307      t.match(response, /^HTTP\/1.1 200 OK.*HTTP\/1.1 400 Bad Request/s)308    })309 310    client.resume()311    client.write('GET / HTTP/1.1\r\n')312    client.write('Host: example.com\r\n')313    client.write('\r\n\r\n')314    client.write('GET /?a b HTTP/1.1\r\n')315    client.write('Host: example.com\r\n')316    client.write('Connection: close\r\n')317    client.write('\r\n\r\n')318  })319})320 321test('request.routeOptions should be immutable', t => {322  t.plan(14)323  const fastify = Fastify()324  const handler = function (req, res) {325    t.equal('POST', req.routeOptions.method)326    t.equal('/', req.routeOptions.url)327    t.throws(() => { req.routeOptions = null }, new TypeError('Cannot set property routeOptions of #<Request> which has only a getter'))328    t.throws(() => { req.routeOptions.method = 'INVALID' }, new TypeError('Cannot assign to read only property \'method\' of object \'#<Object>\''))329    t.throws(() => { req.routeOptions.url = '//' }, new TypeError('Cannot assign to read only property \'url\' of object \'#<Object>\''))330    t.throws(() => { req.routeOptions.bodyLimit = 0xDEADBEEF }, new TypeError('Cannot assign to read only property \'bodyLimit\' of object \'#<Object>\''))331    t.throws(() => { req.routeOptions.attachValidation = true }, new TypeError('Cannot assign to read only property \'attachValidation\' of object \'#<Object>\''))332    t.throws(() => { req.routeOptions.logLevel = 'invalid' }, new TypeError('Cannot assign to read only property \'logLevel\' of object \'#<Object>\''))333    t.throws(() => { req.routeOptions.version = '95.0.1' }, new TypeError('Cannot assign to read only property \'version\' of object \'#<Object>\''))334    t.throws(() => { req.routeOptions.prefixTrailingSlash = true }, new TypeError('Cannot assign to read only property \'prefixTrailingSlash\' of object \'#<Object>\''))335    t.throws(() => { req.routeOptions.newAttribute = {} }, new TypeError('Cannot add property newAttribute, object is not extensible'))336 337    for (const key of Object.keys(req.routeOptions)) {338      if (typeof req.routeOptions[key] === 'object' && req.routeOptions[key] !== null) {339        t.fail('Object.freeze must run recursively on nested structures to ensure that routeOptions is immutable.')340      }341    }342 343    res.send({})344  }345  fastify.post('/', {346    bodyLimit: 1000,347    handler348  })349  fastify.listen({ port: 0 }, function (err) {350    t.error(err)351    t.teardown(() => { fastify.close() })352 353    sget({354      method: 'POST',355      url: 'http://localhost:' + fastify.server.address().port,356      headers: { 'Content-Type': 'application/json' },357      body: [],358      json: true359    }, (err, response, body) => {360      t.error(err)361      t.equal(response.statusCode, 200)362    })363  })364})365 366test('request.routeOptions.method is an uppercase string /1', t => {367  t.plan(4)368  const fastify = Fastify()369  const handler = function (req, res) {370    t.equal('POST', req.routeOptions.method)371    res.send({})372  }373 374  fastify.post('/', {375    bodyLimit: 1000,376    handler377  })378  fastify.listen({ port: 0 }, function (err) {379    t.error(err)380    t.teardown(() => { fastify.close() })381 382    sget({383      method: 'POST',384      url: 'http://localhost:' + fastify.server.address().port,385      headers: { 'Content-Type': 'application/json' },386      body: [],387      json: true388    }, (err, response, body) => {389      t.error(err)390      t.equal(response.statusCode, 200)391    })392  })393})394 395test('request.routeOptions.method is an uppercase string /2', t => {396  t.plan(4)397  const fastify = Fastify()398  const handler = function (req, res) {399    t.equal('POST', req.routeOptions.method)400    res.send({})401  }402 403  fastify.route({404    url: '/',405    method: 'POST',406    bodyLimit: 1000,407    handler408  })409  fastify.listen({ port: 0 }, function (err) {410    t.error(err)411    t.teardown(() => { fastify.close() })412 413    sget({414      method: 'POST',415      url: 'http://localhost:' + fastify.server.address().port,416      headers: { 'Content-Type': 'application/json' },417      body: [],418      json: true419    }, (err, response, body) => {420      t.error(err)421      t.equal(response.statusCode, 200)422    })423  })424})425 426test('request.routeOptions.method is an uppercase string /3', t => {427  t.plan(4)428  const fastify = Fastify()429  const handler = function (req, res) {430    t.equal('POST', req.routeOptions.method)431    res.send({})432  }433 434  fastify.route({435    url: '/',436    method: 'pOSt',437    bodyLimit: 1000,438    handler439  })440  fastify.listen({ port: 0 }, function (err) {441    t.error(err)442    t.teardown(() => { fastify.close() })443 444    sget({445      method: 'POST',446      url: 'http://localhost:' + fastify.server.address().port,447      headers: { 'Content-Type': 'application/json' },448      body: [],449      json: true450    }, (err, response, body) => {451      t.error(err)452      t.equal(response.statusCode, 200)453    })454  })455})456 457test('request.routeOptions.method is an array with uppercase string', t => {458  t.plan(4)459  const fastify = Fastify()460  const handler = function (req, res) {461    t.strictSame(['POST'], req.routeOptions.method)462    res.send({})463  }464 465  fastify.route({466    url: '/',467    method: ['pOSt'],468    bodyLimit: 1000,469    handler470  })471  fastify.listen({ port: 0 }, function (err) {472    t.error(err)473    t.teardown(() => { fastify.close() })474 475    sget({476      method: 'POST',477      url: 'http://localhost:' + fastify.server.address().port,478      headers: { 'Content-Type': 'application/json' },479      body: [],480      json: true481    }, (err, response, body) => {482      t.error(err)483      t.equal(response.statusCode, 200)484    })485  })486})487 488test('test request.routeOptions.version', t => {489  t.plan(7)490  const fastify = Fastify()491 492  fastify.route({493    method: 'POST',494    url: '/version',495    constraints: { version: '1.2.0' },496    handler: function (request, reply) {497      t.equal('1.2.0', request.routeOptions.version)498      reply.send({})499    }500  })501 502  fastify.route({503    method: 'POST',504    url: '/version-undefined',505    handler: function (request, reply) {506      t.equal(undefined, request.routeOptions.version)507      reply.send({})508    }509  })510  fastify.listen({ port: 0 }, function (err) {511    t.error(err)512    t.teardown(() => { fastify.close() })513 514    sget({515      method: 'POST',516      url: 'http://localhost:' + fastify.server.address().port + '/version',517      headers: { 'Content-Type': 'application/json', 'Accept-Version': '1.2.0' },518      body: [],519      json: true520    }, (err, response, body) => {521      t.error(err)522      t.equal(response.statusCode, 200)523    })524 525    sget({526      method: 'POST',527      url: 'http://localhost:' + fastify.server.address().port + '/version-undefined',528      headers: { 'Content-Type': 'application/json' },529      body: [],530      json: true531    }, (err, response, body) => {532      t.error(err)533      t.equal(response.statusCode, 200)534    })535  })536})537