strong-tie/inbound-calls
0
1'use strict'2 3const t = require('tap')4const test = t.test5const proxyquire = require('proxyquire')6const fs = require('node:fs')7const Readable = require('node:stream').Readable8const sget = require('simple-get').concat9const Fastify = require('..')10 11test('should destroy stream when response is ended', t => {12 t.plan(4)13 const stream = require('node:stream')14 const fastify = Fastify()15 16 fastify.get('/error', function (req, reply) {17 const reallyLongStream = new stream.Readable({18 read: function () { },19 destroy: function (err, callback) {20 t.ok('called')21 callback(err)22 }23 })24 reply.code(200).send(reallyLongStream)25 reply.raw.end(Buffer.from('hello\n'))26 })27 28 fastify.listen({ port: 0 }, err => {29 t.error(err)30 t.teardown(() => { fastify.close() })31 32 sget(`http://localhost:${fastify.server.address().port}/error`, function (err, response) {33 t.error(err)34 t.equal(response.statusCode, 200)35 })36 })37})38 39test('should mark reply as sent before pumping the payload stream into response for async route handler', t => {40 t.plan(3)41 42 const handleRequest = proxyquire('../lib/handleRequest', {43 './wrapThenable': (thenable, reply) => {44 thenable.then(function (payload) {45 t.equal(reply.sent, true)46 })47 }48 })49 50 const route = proxyquire('../lib/route', {51 './handleRequest': handleRequest52 })53 54 const Fastify = proxyquire('..', {55 './lib/route': route56 })57 58 const fastify = Fastify()59 60 fastify.get('/', async function (req, reply) {61 const stream = fs.createReadStream(__filename, 'utf8')62 return reply.code(200).send(stream)63 })64 65 fastify.inject({66 url: '/',67 method: 'GET'68 }, (err, res) => {69 t.error(err)70 t.equal(res.payload, fs.readFileSync(__filename, 'utf8'))71 fastify.close()72 })73})74 75test('reply.send handles aborted requests', t => {76 t.plan(2)77 78 const spyLogger = {79 level: 'error',80 fatal: () => { },81 error: () => {82 t.fail('should not log an error')83 },84 warn: () => { },85 info: () => { },86 debug: () => { },87 trace: () => { },88 child: () => { return spyLogger }89 }90 const fastify = Fastify({91 loggerInstance: spyLogger92 })93 94 fastify.get('/', (req, reply) => {95 setTimeout(() => {96 const stream = new Readable({97 read: function () {98 this.push(null)99 }100 })101 reply.send(stream)102 }, 6)103 })104 105 fastify.listen({ port: 0 }, err => {106 t.error(err)107 t.teardown(() => { fastify.close() })108 109 const port = fastify.server.address().port110 const http = require('node:http')111 const req = http.get(`http://localhost:${port}`)112 .on('error', (err) => {113 t.equal(err.code, 'ECONNRESET')114 fastify.close()115 })116 117 setTimeout(() => {118 req.abort()119 }, 1)120 })121})122 123test('request terminated should not crash fastify', t => {124 t.plan(10)125 126 const spyLogger = {127 level: 'error',128 fatal: () => { },129 error: () => {130 t.fail('should not log an error')131 },132 warn: () => { },133 info: () => { },134 debug: () => { },135 trace: () => { },136 child: () => { return spyLogger }137 }138 const fastify = Fastify({139 loggerInstance: spyLogger140 })141 142 fastify.get('/', async (req, reply) => {143 const stream = new Readable()144 stream._read = () => { }145 reply.header('content-type', 'text/html; charset=utf-8')146 reply.header('transfer-encoding', 'chunked')147 stream.push('<h1>HTML</h1>')148 149 reply.send(stream)150 151 await new Promise((resolve) => { setTimeout(resolve, 100).unref() })152 153 stream.push('<h1>should display on second stream</h1>')154 stream.push(null)155 return reply156 })157 158 fastify.listen({ port: 0 }, err => {159 t.error(err)160 t.teardown(() => { fastify.close() })161 162 const port = fastify.server.address().port163 const http = require('node:http')164 const req = http.get(`http://localhost:${port}`, function (res) {165 const { statusCode, headers } = res166 t.equal(statusCode, 200)167 t.equal(headers['content-type'], 'text/html; charset=utf-8')168 t.equal(headers['transfer-encoding'], 'chunked')169 res.on('data', function (chunk) {170 t.equal(chunk.toString(), '<h1>HTML</h1>')171 })172 173 setTimeout(() => {174 req.destroy()175 176 // the server is not crash, we can connect it177 http.get(`http://localhost:${port}`, function (res) {178 const { statusCode, headers } = res179 t.equal(statusCode, 200)180 t.equal(headers['content-type'], 'text/html; charset=utf-8')181 t.equal(headers['transfer-encoding'], 'chunked')182 let payload = ''183 res.on('data', function (chunk) {184 payload += chunk.toString()185 })186 res.on('end', function () {187 t.equal(payload, '<h1>HTML</h1><h1>should display on second stream</h1>')188 t.pass('should end properly')189 })190 })191 }, 1)192 })193 })194})195 