11'use strict' ;
22
33/*
4- * This is a regression test for https://github.com/joyent/node/issues/15447
5- * and https://github.com/joyent/node/issues/9333.
4+ * This is a regression test for
5+ * https://github.com/nodejs/node-v0.x-archive/issues/15447 and
6+ * and https://github.com/nodejs/node-v0.x-archive/issues/9333.
67 *
78 * When a timer is added in another timer's callback, its underlying timer
89 * handle was started with a timeout that was actually incorrect.
@@ -28,17 +29,23 @@ const Timer = process.binding('timer_wrap').Timer;
2829
2930const TIMEOUT = 100 ;
3031
31- let nbBlockingCallbackCalls = 0 ;
32- let latestDelay = 0 ;
33- let timeCallbackScheduled = 0 ;
32+ let nbBlockingCallbackCalls ;
33+ let latestDelay ;
34+ let timeCallbackScheduled ;
35+
36+ // These tests are timing dependent so they may fail even when the bug is
37+ // not present (if the host is sufficiently busy that the timers are delayed
38+ // significantly). However, they fail 100% of the time when the bug *is*
39+ // present, so to increase reliability, allow for a small number of retries.
40+ let retries = 2 ;
3441
3542function initTest ( ) {
3643 nbBlockingCallbackCalls = 0 ;
3744 latestDelay = 0 ;
3845 timeCallbackScheduled = 0 ;
3946}
4047
41- function blockingCallback ( callback ) {
48+ function blockingCallback ( retry , callback ) {
4249 ++ nbBlockingCallbackCalls ;
4350
4451 if ( nbBlockingCallbackCalls > 1 ) {
@@ -47,34 +54,60 @@ function blockingCallback(callback) {
4754 // to fire, they shouldn't generally be more than 100% late in this case.
4855 // But they are guaranteed to be at least 100ms late given the bug in
4956 // https://github.com/nodejs/node-v0.x-archive/issues/15447 and
50- // https://github.com/nodejs/node-v0.x-archive/issues/9333..
51- assert ( latestDelay < TIMEOUT * 2 ) ;
57+ // https://github.com/nodejs/node-v0.x-archive/issues/9333.
58+ if ( latestDelay >= TIMEOUT * 2 ) {
59+ if ( retries > 0 ) {
60+ retries -- ;
61+ return retry ( callback ) ;
62+ }
63+ assert . fail ( `timeout delayed by more than 100% (${ latestDelay } ms)` ) ;
64+ }
5265 if ( callback )
5366 return callback ( ) ;
5467 } else {
5568 // block by busy-looping to trigger the issue
5669 common . busyLoop ( TIMEOUT ) ;
5770
5871 timeCallbackScheduled = Timer . now ( ) ;
59- setTimeout ( blockingCallback . bind ( null , callback ) , TIMEOUT ) ;
72+ setTimeout ( blockingCallback . bind ( null , retry , callback ) , TIMEOUT ) ;
6073 }
6174}
6275
63- const testAddingTimerToEmptyTimersList = common . mustCall ( function ( callback ) {
76+ function testAddingTimerToEmptyTimersList ( callback ) {
6477 initTest ( ) ;
6578 // Call setTimeout just once to make sure the timers list is
6679 // empty when blockingCallback is called.
67- setTimeout ( blockingCallback . bind ( null , callback ) , TIMEOUT ) ;
68- } ) ;
80+ setTimeout (
81+ blockingCallback . bind ( null , testAddingTimerToEmptyTimersList , callback ) ,
82+ TIMEOUT
83+ ) ;
84+ }
85+
86+ function testAddingTimerToNonEmptyTimersList ( ) {
87+ // If both timers fail and attempt a retry, only actually do anything for one
88+ // of them.
89+ let retryOK = true ;
90+ const retry = ( ) => {
91+ if ( retryOK )
92+ testAddingTimerToNonEmptyTimersList ( ) ;
93+ retryOK = false ;
94+ } ;
6995
70- const testAddingTimerToNonEmptyTimersList = common . mustCall ( function ( ) {
7196 initTest ( ) ;
7297 // Call setTimeout twice with the same timeout to make
7398 // sure the timers list is not empty when blockingCallback is called.
74- setTimeout ( blockingCallback , TIMEOUT ) ;
75- setTimeout ( blockingCallback , TIMEOUT ) ;
76- } ) ;
99+ setTimeout (
100+ blockingCallback . bind ( null , retry ) ,
101+ TIMEOUT
102+ ) ;
103+ setTimeout (
104+ blockingCallback . bind ( null , retry ) ,
105+ TIMEOUT
106+ ) ;
107+ }
77108
78109// Run the test for the empty timers list case, and then for the non-empty
79- // timers list one
80- testAddingTimerToEmptyTimersList ( testAddingTimerToNonEmptyTimersList ) ;
110+ // timers list one.
111+ testAddingTimerToEmptyTimersList (
112+ common . mustCall ( testAddingTimerToNonEmptyTimersList )
113+ ) ;
0 commit comments