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,61 @@ 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 ( null , null ,
64+ `timeout delayed by more than 100% (${ latestDelay } ms)` ) ;
65+ }
5266 if ( callback )
5367 return callback ( ) ;
5468 } else {
5569 // block by busy-looping to trigger the issue
5670 common . busyLoop ( TIMEOUT ) ;
5771
5872 timeCallbackScheduled = Timer . now ( ) ;
59- setTimeout ( blockingCallback . bind ( null , callback ) , TIMEOUT ) ;
73+ setTimeout ( blockingCallback . bind ( null , retry , callback ) , TIMEOUT ) ;
6074 }
6175}
6276
63- const testAddingTimerToEmptyTimersList = common . mustCall ( function ( callback ) {
77+ function testAddingTimerToEmptyTimersList ( callback ) {
6478 initTest ( ) ;
6579 // Call setTimeout just once to make sure the timers list is
6680 // empty when blockingCallback is called.
67- setTimeout ( blockingCallback . bind ( null , callback ) , TIMEOUT ) ;
68- } ) ;
81+ setTimeout (
82+ blockingCallback . bind ( null , testAddingTimerToEmptyTimersList , callback ) ,
83+ TIMEOUT
84+ ) ;
85+ }
86+
87+ function testAddingTimerToNonEmptyTimersList ( ) {
88+ // If both timers fail and attempt a retry, only actually do anything for one
89+ // of them.
90+ let retryOK = true ;
91+ const retry = ( ) => {
92+ if ( retryOK )
93+ testAddingTimerToNonEmptyTimersList ( ) ;
94+ retryOK = false ;
95+ } ;
6996
70- const testAddingTimerToNonEmptyTimersList = common . mustCall ( function ( ) {
7197 initTest ( ) ;
7298 // Call setTimeout twice with the same timeout to make
7399 // sure the timers list is not empty when blockingCallback is called.
74- setTimeout ( blockingCallback , TIMEOUT ) ;
75- setTimeout ( blockingCallback , TIMEOUT ) ;
76- } ) ;
100+ setTimeout (
101+ blockingCallback . bind ( null , retry ) ,
102+ TIMEOUT
103+ ) ;
104+ setTimeout (
105+ blockingCallback . bind ( null , retry ) ,
106+ TIMEOUT
107+ ) ;
108+ }
77109
78110// Run the test for the empty timers list case, and then for the non-empty
79- // timers list one
80- testAddingTimerToEmptyTimersList ( testAddingTimerToNonEmptyTimersList ) ;
111+ // timers list one.
112+ testAddingTimerToEmptyTimersList (
113+ common . mustCall ( testAddingTimerToNonEmptyTimersList )
114+ ) ;
0 commit comments