diff --git a/lib/interceptor/dns.js b/lib/interceptor/dns.js index fc5dc1a4366..98ef376ecbb 100644 --- a/lib/interceptor/dns.js +++ b/lib/interceptor/dns.js @@ -213,6 +213,10 @@ class DNSInstance { this.#records.set(origin.hostname, records) } + deleteRecords (origin) { + this.#records.delete(origin.hostname) + } + getHandler (meta, opts) { return new DNSDispatchHandler(this, meta, opts) } @@ -261,7 +265,7 @@ class DNSDispatchHandler extends DecoratorHandler { break } case 'ENOTFOUND': - this.#state.deleteRecord(this.#origin) + this.#state.deleteRecords(this.#origin) // eslint-disable-next-line no-fallthrough default: super.onResponseError(controller, err) diff --git a/test/interceptors/dns.js b/test/interceptors/dns.js index 944c190492e..1468b669d73 100644 --- a/test/interceptors/dns.js +++ b/test/interceptors/dns.js @@ -1732,6 +1732,68 @@ test('Should handle max cached items', async t => { t.equal(await response3.body.text(), 'hello world! (x2)') }) +test('Should handle ENOTFOUND response error', async t => { + t = tspl(t, { plan: 4 }) + let lookupCounter = 0 + const hostname = 'something-which-should-result-in-enotfound.undici' + + const requestOptions = { + method: 'GET', + path: '/', + origin: 'http://localhost' + } + + const client = new Agent().compose([ + dispatch => { + return (opts, handler) => { + opts.origin = new URL(`http://${hostname}`) + return dispatch(opts, handler) + } + }, + dns({ + lookup (origin, opts, cb) { + lookupCounter++ + if (lookupCounter === 1) { + cb(null, [ + { + address: '127.0.0.1', + family: 4 + } + ]) + } else { + // Causes InformationalError + cb(null, []) + } + } + }) + ]) + + after(async () => { + await client.close() + }) + + let error1 + try { + await client.request(requestOptions) + } catch (err) { + error1 = err + } + t.equal(error1.code, 'ENOTFOUND') + t.equal(error1.hostname, hostname) + + // Test that the records in the dns interceptor were deleted after the + // previous request + let error2 + try { + await client.request(requestOptions) + } catch (err) { + error2 = err + } + t.equal(error2.name, 'InformationalError') + + t.equal(lookupCounter, 2) +}) + test('#3937 - Handle host correctly', async t => { t = tspl(t, { plan: 10 })