1// Flags: --expose-internals
2'use strict';
3const common = require('../common');
4const assert = require('assert');
5const { internalBinding } = require('internal/test/binding');
6const cares = internalBinding('cares_wrap');
7
8// Stub `getaddrinfo` to *always* error. This has to be done before we load the
9// `dns` module to guarantee that the `dns` module uses the stub.
10cares.getaddrinfo = () => internalBinding('uv').UV_ENOMEM;
11
12const dns = require('dns');
13const dnsPromises = dns.promises;
14
15{
16  const err = {
17    code: 'ERR_INVALID_ARG_TYPE',
18    name: 'TypeError',
19    message: /^The "hostname" argument must be of type string\. Received type number/
20  };
21
22  assert.throws(() => dns.lookup(1, {}), err);
23  assert.throws(() => dnsPromises.lookup(1, {}), err);
24}
25
26// This also verifies different expectWarning notations.
27common.expectWarning({
28  // For 'internal/test/binding' module.
29  'internal/test/binding': [
30    'These APIs are for internal testing only. Do not use them.',
31  ],
32  // For calling `dns.lookup` with falsy `hostname`.
33  'DeprecationWarning': {
34    DEP0118: 'The provided hostname "false" is not a valid ' +
35      'hostname, and is supported in the dns module solely for compatibility.'
36  }
37});
38
39assert.throws(() => {
40  dns.lookup(false, 'cb');
41}, {
42  code: 'ERR_INVALID_ARG_TYPE',
43  name: 'TypeError'
44});
45
46assert.throws(() => {
47  dns.lookup(false, 'options', 'cb');
48}, {
49  code: 'ERR_INVALID_ARG_TYPE',
50  name: 'TypeError'
51});
52
53{
54  const err = {
55    code: 'ERR_INVALID_ARG_VALUE',
56    name: 'TypeError',
57    message: "The argument 'hints' is invalid. Received 100"
58  };
59  const options = {
60    hints: 100,
61    family: 0,
62    all: false
63  };
64
65  assert.throws(() => { dnsPromises.lookup(false, options); }, err);
66  assert.throws(() => {
67    dns.lookup(false, options, common.mustNotCall());
68  }, err);
69}
70
71{
72  const family = 20;
73  const err = {
74    code: 'ERR_INVALID_ARG_VALUE',
75    name: 'TypeError',
76    message: `The property 'options.family' must be one of: 0, 4, 6. Received ${family}`
77  };
78  const options = {
79    hints: 0,
80    family,
81    all: false
82  };
83
84  assert.throws(() => { dnsPromises.lookup(false, options); }, err);
85  assert.throws(() => {
86    dns.lookup(false, options, common.mustNotCall());
87  }, err);
88}
89
90[1, 0n, 1n, '', '0', Symbol(), true, false, {}, [], () => {}]
91  .forEach((family) => {
92    const err = { code: 'ERR_INVALID_ARG_VALUE' };
93    const options = { family };
94    assert.throws(() => { dnsPromises.lookup(false, options); }, err);
95    assert.throws(() => {
96      dns.lookup(false, options, common.mustNotCall());
97    }, err);
98  });
99[0n, 1n, '', '0', Symbol(), true, false].forEach((family) => {
100  const err = { code: 'ERR_INVALID_ARG_TYPE' };
101  assert.throws(() => { dnsPromises.lookup(false, family); }, err);
102  assert.throws(() => {
103    dns.lookup(false, family, common.mustNotCall());
104  }, err);
105});
106assert.throws(() => dnsPromises.lookup(false, () => {}),
107              { code: 'ERR_INVALID_ARG_TYPE' });
108
109[0n, 1n, '', '0', Symbol(), true, false, {}, [], () => {}].forEach((hints) => {
110  const err = { code: 'ERR_INVALID_ARG_TYPE' };
111  const options = { hints };
112  assert.throws(() => { dnsPromises.lookup(false, options); }, err);
113  assert.throws(() => {
114    dns.lookup(false, options, common.mustNotCall());
115  }, err);
116});
117
118[0, 1, 0n, 1n, '', '0', Symbol(), {}, [], () => {}].forEach((all) => {
119  const err = { code: 'ERR_INVALID_ARG_TYPE' };
120  const options = { all };
121  assert.throws(() => { dnsPromises.lookup(false, options); }, err);
122  assert.throws(() => {
123    dns.lookup(false, options, common.mustNotCall());
124  }, err);
125});
126
127[0, 1, 0n, 1n, '', '0', Symbol(), {}, [], () => {}].forEach((verbatim) => {
128  const err = { code: 'ERR_INVALID_ARG_TYPE' };
129  const options = { verbatim };
130  assert.throws(() => { dnsPromises.lookup(false, options); }, err);
131  assert.throws(() => {
132    dns.lookup(false, options, common.mustNotCall());
133  }, err);
134});
135
136(async function() {
137  let res;
138
139  res = await dnsPromises.lookup(false, {
140    hints: 0,
141    family: 0,
142    all: true
143  });
144  assert.deepStrictEqual(res, []);
145
146  res = await dnsPromises.lookup('127.0.0.1', {
147    hints: 0,
148    family: 4,
149    all: true
150  });
151  assert.deepStrictEqual(res, [{ address: '127.0.0.1', family: 4 }]);
152
153  res = await dnsPromises.lookup('127.0.0.1', {
154    hints: 0,
155    family: 4,
156    all: false
157  });
158  assert.deepStrictEqual(res, { address: '127.0.0.1', family: 4 });
159})().then(common.mustCall());
160
161dns.lookup(false, {
162  hints: 0,
163  family: 0,
164  all: true
165}, common.mustSucceed((result, addressType) => {
166  assert.deepStrictEqual(result, []);
167  assert.strictEqual(addressType, undefined);
168}));
169
170dns.lookup('127.0.0.1', {
171  hints: 0,
172  family: 4,
173  all: true
174}, common.mustSucceed((result, addressType) => {
175  assert.deepStrictEqual(result, [{
176    address: '127.0.0.1',
177    family: 4
178  }]);
179  assert.strictEqual(addressType, undefined);
180}));
181
182dns.lookup('127.0.0.1', {
183  hints: 0,
184  family: 4,
185  all: false
186}, common.mustSucceed((result, addressType) => {
187  assert.strictEqual(result, '127.0.0.1');
188  assert.strictEqual(addressType, 4);
189}));
190
191let tickValue = 0;
192
193// Should fail due to stub.
194dns.lookup('example.com', common.mustCall((error, result, addressType) => {
195  assert(error);
196  assert.strictEqual(tickValue, 1);
197  assert.strictEqual(error.code, 'ENOMEM');
198  const descriptor = Object.getOwnPropertyDescriptor(error, 'message');
199  // The error message should be non-enumerable.
200  assert.strictEqual(descriptor.enumerable, false);
201}));
202
203// Make sure that the error callback is called on next tick.
204tickValue = 1;
205
206// Should fail due to stub.
207assert.rejects(dnsPromises.lookup('example.com'),
208               { code: 'ENOMEM', hostname: 'example.com' });
209