test: make timers-blocking-callback more reliable · nodejs/node@7245082

11

'use strict';

2233

/*

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;

28292930

const TIMEOUT = 100;

303131-

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;

34413542

function initTest() {

3643

nbBlockingCallbackCalls = 0;

3744

latestDelay = 0;

3845

timeCallbackScheduled = 0;

3946

}

404741-

function blockingCallback(callback) {

48+

function blockingCallback(retry, callback) {

4249

++nbBlockingCallbackCalls;

43504451

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);

57715872

timeCallbackScheduled = Timer.now();

59-

setTimeout(blockingCallback.bind(null, callback), TIMEOUT);

73+

setTimeout(blockingCallback.bind(null, retry, callback), TIMEOUT);

6074

}

6175

}

627663-

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+

};

699670-

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+

}

7710978110

// 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+

);