11const utils = require ( '../../utils' ) ;
2+ const mm = require ( 'egg-mock' ) ;
3+ const dns = require ( 'dns' ) ;
4+ const dnsPromise = require ( 'dns' ) . promises ;
25const assert = require ( 'assert' ) ;
36
47describe ( 'test/lib/core/dns_resolver.test.js' , ( ) => {
@@ -22,6 +25,8 @@ describe('test/lib/core/dns_resolver.test.js', () => {
2225 url2 = url2 . replace ( '127.0.0.2' , 'localhost' ) ;
2326 } ) ;
2427
28+ afterEach ( mm . restore ) ;
29+
2530 after ( ( ) => {
2631 if ( server1 ?. server ?. listening ) server1 . server . close ( ) ;
2732 if ( server2 ?. server ?. listening ) server2 . server . close ( ) ;
@@ -76,4 +81,114 @@ describe('test/lib/core/dns_resolver.test.js', () => {
7681 assert ( err . message . includes ( 'fetch failed' ) ) ;
7782 }
7883 } ) ;
84+
85+ it ( 'should not fail even if dns.lookup fail, because lookup is overridden' , async ( ) => {
86+ mm . error ( dnsPromise , 'lookup' , 'mock dns lookup error' ) ;
87+ const res = await app . curl ( url2 + '/get_headers' , { dataType : 'json' } ) ;
88+ assert ( res . status === 200 ) ;
89+ } ) ;
90+ } ) ;
91+
92+ describe ( 'test/lib/core/dns_resolver with dns error' , ( ) => {
93+ let server ;
94+ let app ;
95+ let url ;
96+ let originalDNSServers ;
97+
98+ const cache = new Map ( ) ;
99+ before ( async ( ) => {
100+ server = await utils . startNewLocalServer ( '127.0.0.1' ) ;
101+ if ( ! server ) {
102+ throw new Error ( 'start local server failed' ) ;
103+ }
104+ app = utils . app ( 'apps/dns_resolver' ) ;
105+ await app . ready ( ) ;
106+ app . config . httpclient . lookup = function ( hostname , options , callback ) {
107+ if ( cache . has ( hostname ) ) {
108+ const record = cache . get ( hostname ) ;
109+ if ( options && options . all ) {
110+ const addresses = record . map ( r => ( { address : r . address , family : 4 } ) ) ;
111+ callback ( null , addresses ) ;
112+ return ;
113+ }
114+ callback ( null , record [ 0 ] . address , 4 ) ;
115+ return ;
116+ }
117+ dnsPromise . resolve4 ( hostname , { ttl : true } ) . then ( addresses => {
118+ if ( addresses && addresses . length !== 0 ) {
119+ if ( Array . isArray ( addresses ) ) {
120+ cache . set ( hostname , addresses ) ;
121+ } else {
122+ cache . set ( hostname , [ addresses ] ) ;
123+ }
124+ if ( options && options . all ) {
125+ const addrList = addresses . map ( r => ( { address : r . address , family : 4 } ) ) ;
126+ callback ( null , addrList ) ;
127+ return ;
128+ }
129+ callback ( null , addresses [ 0 ] . address , 4 ) ;
130+ } else {
131+ callback ( new Error ( 'no addresses found' ) ) ;
132+ }
133+ } ) . catch ( err => {
134+ callback ( err ) ;
135+ } ) ;
136+
137+ } ;
138+ url = server . url ;
139+ url = url . replace ( '127.0.0.1' , 'localhost' ) ;
140+ originalDNSServers = dns . getServers ( ) ;
141+ dns . setServers ( [ '223.5.5.5' , '223.6.6.6' ] ) ;
142+ } ) ;
143+
144+ afterEach ( mm . restore ) ;
145+
146+ after ( ( ) => {
147+ dns . setServers ( originalDNSServers ) ;
148+ if ( server ?. server ?. listening ) server . server . close ( ) ;
149+ } ) ;
150+
151+
152+ it ( 'should cache work when dns fails' , async ( ) => {
153+ const res1 = await app . curl ( url + '/get_headers' , { dataType : 'json' } ) ;
154+ assert ( res1 . status === 200 ) ;
155+ assert ( cache . has ( 'localhost' ) ) ;
156+
157+ mm . error ( dnsPromise , 'resolve4' , 'mock dns lookup error' ) ;
158+ const res2 = await app . curl ( url + '/get_headers' , { dataType : 'json' } ) ;
159+ assert ( res2 . status === 200 ) ;
160+ cache . delete ( 'localhost' ) ;
161+ // should fail now
162+ // assert.error(app.curl(url + '/get_headers', { dataType: 'json' }))
163+ let shouldFail = false ;
164+ try {
165+ await app . curl ( url + '/get_headers' , { dataType : 'json' } ) ;
166+ } catch ( err ) {
167+ shouldFail = true ;
168+ assert ( err . message . includes ( 'mock dns lookup error' ) ) ;
169+ }
170+ assert ( shouldFail ) ;
171+ } ) ;
172+
173+ it ( 'should cache work when name server fails' , async ( ) => {
174+ const successRes = await app . curl ( url + '/get_headers' , { dataType : 'json' } ) ;
175+ assert ( successRes . status === 200 ) ;
176+ assert ( cache . has ( 'localhost' ) ) ;
177+ // can't resolve localhost now, but cache still works
178+ dns . setServers ( [ '8.8.8.8' ] ) ;
179+ const res = await app . curl ( url + '/get_headers' , { dataType : 'json' } ) ;
180+ assert ( res . status === 200 ) ;
181+
182+ // clear cache, should fail now
183+ cache . delete ( 'localhost' ) ;
184+ let shouldFail = false ;
185+ try {
186+ await app . curl ( url + '/get_headers' , { dataType : 'json' } ) ;
187+ } catch ( err ) {
188+ shouldFail = true ;
189+ assert ( err . message . includes ( 'queryA ENOTFOUND localhost' ) ) ;
190+ }
191+ assert ( shouldFail ) ;
192+ } ) ;
79193} ) ;
194+
0 commit comments