|
1 | 1 | 'use strict'
|
2 | 2 |
|
| 3 | +const dns = require('node:dns') |
| 4 | +const http = require('node:http') |
3 | 5 | const { test } = require('node:test')
|
4 | 6 | const Fastify = require('..')
|
5 | 7 | const sget = require('simple-get').concat
|
@@ -186,3 +188,82 @@ test('#5180 - preClose should be called before closing secondary server', async
|
186 | 188 | // completed
|
187 | 189 | await new Promise((resolve) => { setTimeout(resolve, 1000) })
|
188 | 190 | })
|
| 191 | + |
| 192 | +test('closeAllConnections', async (t) => { |
| 193 | + const cases = [ |
| 194 | + { |
| 195 | + scenario: 'should be called when forceCloseConnections is set to true', |
| 196 | + forceCloseConnections: true, |
| 197 | + expectedCalls: 1 |
| 198 | + }, |
| 199 | + { |
| 200 | + scenario: 'should not be called when forceCloseConnections is set to false', |
| 201 | + forceCloseConnections: false, |
| 202 | + expectedCalls: 0 |
| 203 | + } |
| 204 | + ] |
| 205 | + |
| 206 | + for (const c of cases) { |
| 207 | + await t.test(c.scenario, (t, end) => { |
| 208 | + // dns.lookup uses the operating system’s resolver to return the list of addresses. |
| 209 | + // this results in cases where only IPv4 is returned (and secondary servers are not created) |
| 210 | + // mocking the method will ensure that the secondary server is always created when specifying localhost as host |
| 211 | + t.mock.method(dns, 'lookup', (hostname, options, callback) => { |
| 212 | + if (typeof options === 'function') { |
| 213 | + callback = options |
| 214 | + options = {} |
| 215 | + } |
| 216 | + if (typeof callback === 'function') { |
| 217 | + callback(null, [ |
| 218 | + { address: '127.0.0.1', family: 4 }, |
| 219 | + { address: '::1', family: 6 } |
| 220 | + ]) |
| 221 | + } else { |
| 222 | + return new Promise((resolve, reject) => { |
| 223 | + resolve([ |
| 224 | + { address: '127.0.0.1', family: 4 }, |
| 225 | + { address: '::1', family: 6 } |
| 226 | + ]) |
| 227 | + }) |
| 228 | + } |
| 229 | + }) |
| 230 | + |
| 231 | + // list of servers created by fastify (main and secondary) |
| 232 | + const servers = [] |
| 233 | + |
| 234 | + // in order to track calls to closeAllConnections we need to monkey patch http.createServer |
| 235 | + // and set a spy on closeAllConnections method for the returned server instances |
| 236 | + const originalCreateServer = http.createServer |
| 237 | + t.mock.method(http, 'createServer', (http, httpHandler) => { |
| 238 | + const server = originalCreateServer(http, httpHandler) |
| 239 | + |
| 240 | + t.mock.method(server, 'closeAllConnections') |
| 241 | + servers.push(server) |
| 242 | + |
| 243 | + return server |
| 244 | + }) |
| 245 | + |
| 246 | + const fastify = Fastify({ |
| 247 | + forceCloseConnections: c.forceCloseConnections |
| 248 | + }) |
| 249 | + |
| 250 | + fastify.addHook('onClose', (instance, done) => { |
| 251 | + // for each server created, check if closeAllConnections was called |
| 252 | + for (const server of servers) { |
| 253 | + t.assert.strictEqual(server.closeAllConnections.mock.callCount(), c.expectedCalls) |
| 254 | + } |
| 255 | + done() |
| 256 | + end() |
| 257 | + }) |
| 258 | + |
| 259 | + fastify.listen({ port: 0 }, (err) => { |
| 260 | + t.assert.ifError(err) |
| 261 | + // ensure that main and secondary server are created |
| 262 | + t.assert.strictEqual(servers.length, 2) |
| 263 | + |
| 264 | + // close the server |
| 265 | + fastify.close() |
| 266 | + }) |
| 267 | + }) |
| 268 | + } |
| 269 | +}) |
0 commit comments