-
Notifications
You must be signed in to change notification settings - Fork 29.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
test: re-implement promises.setInterval() test robustly #37230
Conversation
If I understand this correctly, this doesn't exactly test what I wanted to check. I wanted to check the following: After 2 iterations, delay the current iteration long enough for the interval to create another value. Then, abort the controller, and see that the value that was created during the previous delay will be read. I believe that this will abort the controller only after the third iteration has already started. |
@Linkgoron Ah, I see. OK, I've modified it to use that behavior. Please take a look. I tested it with |
366054b
to
d676d1d
Compare
I still think that it isn't exactly what the original test tested. The test is supposed to check that if a value was generated before the controller was aborted and wasn't read yet ("backpressure"), the following call to |
@Linkgoron When you say "a value was generated", what do you mean? I thought it meant a value had been generated by the To check what's going on here, I added a logging variable {
let foo = '';
async function runInterval(fn, intervalTime, signal, emitter) {
const input = 'foobar';
const interval = setInterval(intervalTime, input, { signal });
let iteration = 0;
foo += 'entering for loop\n';
for await (const value of interval) {
foo += `got value ${value} from for await\n`;
if (emitter) {
// Next line uses `iteration + 1` because we haven't incremented `iteration` yet.
foo += `emitting the event from iteration ${iteration + 1}\n`;
emitter.emit('myevent');
}
assert.strictEqual(value, input);
iteration++;
foo += `about to await the passed callback for iteration ${iteration}\n`;
await fn(iteration);
foo += `finished awaiting the passed callback for iteration ${iteration}\n`;
}
}
{
// Check that if we abort when we have some unresolved callbacks,
// we actually call them.
const controller = new AbortController();
const myEvent = new EventEmitter();
const { signal } = controller;
const delay = 10;
let totalIterations = 0;
const timeoutLoop = runInterval(async (iterationNumber) => {
if (iterationNumber <= 2) {
assert.strictEqual(signal.aborted, false);
}
if (iterationNumber === 2) {
foo += 'adding the once listener in iteration 2\n';
myEvent.once('myevent', () => {
foo += 'aborting\n';
controller.abort();
foo += 'aborted\n';
});
}
if (iterationNumber > 2) {
assert.strictEqual(signal.aborted, true);
}
if (iterationNumber > totalIterations) {
totalIterations = iterationNumber;
}
}, delay, signal, myEvent);
timeoutLoop.catch(common.mustCall(() => {
console.log(foo);
assert.ok(totalIterations >= 3, `iterations was ${totalIterations} < 3`);
}));
}
} The results were this:
If I'm understanding correctly, then this appears to be doing the right thing--specifically, this at the end:
And if I"m not understanding correctly, are you able to see where I'm getting it wrong? |
Oh, I see the confusion. When I say that a value is generated, I'm talking about the setInterval that's ״running״ in the background "in" the generator. Every time that it's "invoked" (every
The case that the original test was trying to show was what happens if the So, generate the 2nd value -> wait for |
d676d1d
to
2f846a1
Compare
Ahhhhhh.... I think I see now. In that case, probably bumping the |
Yes, that'll work, although you could also do |
@nodejs/testing @nodejs/timers This needs a review. |
2f846a1
to
b4264b5
Compare
Landed in b4264b5 |
By using events, we can make sure the call to
controller.abort()
doesn't happen before the next iteration starts.
Fixes: #37226