1
1
'use strict' ;
2
2
3
3
/*
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.
6
7
*
7
8
* When a timer is added in another timer's callback, its underlying timer
8
9
* handle was started with a timeout that was actually incorrect.
@@ -28,17 +29,23 @@ const Timer = process.binding('timer_wrap').Timer;
28
29
29
30
const TIMEOUT = 100 ;
30
31
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 ;
34
41
35
42
function initTest ( ) {
36
43
nbBlockingCallbackCalls = 0 ;
37
44
latestDelay = 0 ;
38
45
timeCallbackScheduled = 0 ;
39
46
}
40
47
41
- function blockingCallback ( callback ) {
48
+ function blockingCallback ( retry , callback ) {
42
49
++ nbBlockingCallbackCalls ;
43
50
44
51
if ( nbBlockingCallbackCalls > 1 ) {
@@ -47,34 +54,60 @@ function blockingCallback(callback) {
47
54
// to fire, they shouldn't generally be more than 100% late in this case.
48
55
// But they are guaranteed to be at least 100ms late given the bug in
49
56
// 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
+ }
52
65
if ( callback )
53
66
return callback ( ) ;
54
67
} else {
55
68
// block by busy-looping to trigger the issue
56
69
common . busyLoop ( TIMEOUT ) ;
57
70
58
71
timeCallbackScheduled = Timer . now ( ) ;
59
- setTimeout ( blockingCallback . bind ( null , callback ) , TIMEOUT ) ;
72
+ setTimeout ( blockingCallback . bind ( null , retry , callback ) , TIMEOUT ) ;
60
73
}
61
74
}
62
75
63
- const testAddingTimerToEmptyTimersList = common . mustCall ( function ( callback ) {
76
+ function testAddingTimerToEmptyTimersList ( callback ) {
64
77
initTest ( ) ;
65
78
// Call setTimeout just once to make sure the timers list is
66
79
// 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
+ } ;
69
95
70
- const testAddingTimerToNonEmptyTimersList = common . mustCall ( function ( ) {
71
96
initTest ( ) ;
72
97
// Call setTimeout twice with the same timeout to make
73
98
// 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
+ }
77
108
78
109
// 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