@@ -128,6 +128,159 @@ describe("Redis", () => {
128128 } ) ;
129129 } ) ;
130130
131+ describe ( ".options.familyFallback" , ( ) => {
132+ it ( "should fail to connect to invalid host" , ( done ) => {
133+ let errorEmitted = false ;
134+
135+ const redis = new Redis ( {
136+ host : "invalid-hostname" ,
137+ retryStrategy : null ,
138+ reconnectOnError : ( ) => false ,
139+ } ) ;
140+
141+ redis . on ( "error" , ( err ) => {
142+ if ( ! errorEmitted ) {
143+ try {
144+ expect ( err ) . to . be . instanceOf ( Error ) ;
145+ expect ( err . message ) . to . contain ( "ENOTFOUND" ) ;
146+ done ( ) ;
147+ } catch ( assertionError ) {
148+ done ( assertionError ) ;
149+ }
150+ }
151+ } ) ;
152+ } ) ;
153+
154+ it ( "should connect via IPv6 if family is 0" , ( done ) => {
155+ const redis = new Redis ( {
156+ host : "localhost" ,
157+ family : 0 ,
158+ retryStrategy : null ,
159+ reconnectOnError : ( ) => false ,
160+ } ) ;
161+
162+ redis . on ( "connect" , ( ) => {
163+ try {
164+ const remoteAddress = redis . stream . remoteAddress ;
165+ const remotePort = redis . stream . remotePort ;
166+ expect ( redis . options . family ) . to . equal ( 0 ) ;
167+ expect ( remoteAddress ) . not . to . equal ( "127.0.0.1" ) ;
168+ expect ( remoteAddress ) . to . equal ( "::1" ) ;
169+ expect ( remotePort ) . to . equal ( 6379 ) ;
170+ done ( ) ;
171+ } catch ( err ) {
172+ done ( err ) ;
173+ } finally {
174+ redis . disconnect ( ) ;
175+ }
176+ } ) ;
177+
178+ redis . on ( "error" , done ) ;
179+ } ) ;
180+
181+ it ( "should continue to connect via family 0 after connection failure" , ( done ) => {
182+ let errorEmitted = false ;
183+ let attempts = 0 ;
184+
185+ const redis = new Redis ( {
186+ host : "invalid-hostname" ,
187+ family : 0 ,
188+ // Make the test faster by reducing the initial delay
189+ retryStrategy : ( times ) => ( times > 1 ? null : 10 ) , // Only retry once after 10ms
190+ } ) ;
191+
192+ redis . on ( "close" , ( ) => {
193+ try {
194+ const family = redis . options . family ;
195+ if ( attempts === 0 ) {
196+ expect ( family ) . to . equal ( 0 ) ;
197+ } else {
198+ expect ( family ) . to . equal ( 6 ) ;
199+ }
200+ attempts ++ ;
201+ } catch ( err ) {
202+ done ( err ) ;
203+ } finally {
204+ if ( attempts === 2 ) {
205+ redis . disconnect ( ) ;
206+ done ( ) ;
207+ }
208+ }
209+ } ) ;
210+
211+ redis . on ( "error" , ( err ) => {
212+ if ( ! errorEmitted ) {
213+ try {
214+ expect ( err ) . to . be . instanceOf ( Error ) ;
215+ expect ( err . message ) . to . contain ( "ENOTFOUND" ) ;
216+ errorEmitted = true ;
217+ } catch ( assertionError ) {
218+ done ( assertionError ) ;
219+ }
220+ }
221+ } ) ;
222+ } ) ;
223+
224+ it ( "should attempt to reconnect with another family" , ( done ) => {
225+ let attempts = 0 ;
226+
227+ const redis = new Redis ( {
228+ familyFallback : true ,
229+ host : "invalid-hostname" ,
230+ // Make the test faster by reducing the initial delay
231+ retryStrategy : ( times ) => ( times > 1 ? null : 10 ) , // Only retry once after 10ms
232+ } ) ;
233+
234+ redis . on ( "close" , ( ) => {
235+ try {
236+ expect ( redis . options . familyFallback ) . to . equal ( true ) ;
237+ let testFamily = attempts === 0 ? 4 : 6 ;
238+ const family = redis . options . family ;
239+ // testFamily should be 4 on the first attempt and 6 on the second
240+ expect ( family ) . to . equal ( testFamily ) ;
241+ testFamily = family === 6 ? 4 : 6 ;
242+ } catch ( err ) {
243+ done ( err ) ;
244+ } finally {
245+ if ( attempts ++ === 1 ) {
246+ done ( ) ;
247+ redis . disconnect ( ) ;
248+ }
249+ }
250+ } ) ;
251+ } ) ;
252+
253+ it ( "should attempt to reconnect with another family (custom)" , ( done ) => {
254+ let attempts = 0 ;
255+ let testFamily = 6 ;
256+
257+ const redis = new Redis ( {
258+ familyFallback : true ,
259+ host : "invalid-hostname" ,
260+ family : testFamily ,
261+ // Make the test faster by reducing the initial delay
262+ retryStrategy : ( times ) => ( times > 1 ? null : 10 ) , // Only retry once after 10ms
263+ } ) ;
264+
265+ redis . on ( "close" , ( ) => {
266+ try {
267+ expect ( redis . options . familyFallback ) . to . equal ( true ) ;
268+ const family = redis . options . family ;
269+ // testFamily should be 6 on the first attempt and 4 on the second
270+ expect ( family ) . to . equal ( testFamily ) ;
271+ testFamily = family === 6 ? 4 : 6 ;
272+ } catch ( err ) {
273+ done ( err ) ;
274+ } finally {
275+ if ( attempts ++ === 1 ) {
276+ done ( ) ;
277+ redis . disconnect ( ) ;
278+ }
279+ }
280+ } ) ;
281+ } ) ;
282+ } ) ;
283+
131284 describe ( "#end" , ( ) => {
132285 it ( "should redirect to #disconnect" , ( done ) => {
133286 const redis = new Redis ( { lazyConnect : true } ) ;
0 commit comments