-
Notifications
You must be signed in to change notification settings - Fork 31.2k
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
readline: add stricter validation for functions called after closed #57680
base: main
Are you sure you want to change the base?
readline: add stricter validation for functions called after closed #57680
Conversation
c575cee
to
7f5b064
Compare
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #57680 +/- ##
=======================================
Coverage 90.24% 90.25%
=======================================
Files 630 630
Lines 185245 185206 -39
Branches 36299 36300 +1
=======================================
- Hits 167173 167153 -20
+ Misses 11018 10995 -23
- Partials 7054 7058 +4
🚀 New features to boost your workflow:
|
7f5b064
to
360e127
Compare
rli.question('What\'s your name?', common.mustCall((name) => { | ||
assert.strictEqual(name, 'Node.js'); | ||
rli.close(); | ||
assert.throws(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can have the rli.write
call here too? Seems like the behavior is the same for the three calls when the interface is closed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you asking if we could move rli.write
from line 1212 to here? and fully remove that test block?
Sure, we can 🙂, although I personally am a fan of small focused tests, so that if one thing breaks ideally only a single test fails, so my preference would be to keep them as they are, I am however happy to combine the two, especially if some other folks share your same preference 🙂
(PS: you could argue that I am already combining together pause
and resume
here, that's be a valid argument, but those feel to me like they go together that's why I put them in the same test 😅)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this is not a block. That's just all the functions end up with the same behavior when the interface is closed, hence the test is testing the same behavior and it would be good to have them together.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had another look and I remembered that there are already two separate testing blocks for question and question promisified, so I'm indeed (loosely) following this pattern with my additions, so if I were to combine things I feel like at that point it would make sense to combine all these blocks right?
but at that point we have a single big test/block which tests all the various functions being called after close 🤔 feels a untidy to me 🤔
I am not extremely against the idea but yeah it wouldn't be my personal preference 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I said, not a blocker at all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Unfortunately I think the additional throw here will make this semver-major
yeah I understand and agree 🙂, I also did think the same and mentioned this in my PR description 👍 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
this test - |
Hi @jakecastelli 👋 I just had a look, the
This, without the My guess now is that in CI the REPL can take more than 100ms to call Alternatively I could update the code in WDYT? could you try re-running the CI and see if the new timeout value helps? 🙏 |
Hi @dario-piotrowicz 👋 thanks for the detailed explanation, I didn't remember I've mentioned |
This comment was marked as outdated.
This comment was marked as outdated.
Hey @jakecastelli thanks for re-running the CI 🙂 (let's hope that it works now 😁🤞) No I don't think there was some confusion, in my comment I was explaining why the Regarding your comment about |
@@ -548,6 +551,9 @@ class Interface extends InterfaceConstructor { | |||
* @returns {void | Interface} | |||
*/ | |||
resume() { | |||
if (this.closed) { | |||
throw new ERR_USE_AFTER_CLOSE('readline'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a suggestion - any chance we could defer the throw in the nextTick
? Something like:
throw new ERR_USE_AFTER_CLOSE('readline'); | |
process.nextTick(()=> { | |
throw new ERR_USE_AFTER_CLOSE('readline'); | |
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mh... sorry but I think I'd be pretty against this 🤔
deferring it to the next tick would mean that:
- the rest of the function would incorrectly run, for example emitting events such as
resume
(this could cause subtle bugs with potential listeners of such events (rli.on('resume', () => {...})
)) - the error could no be try-catchable (e.g. it would not allow users to do
try { rli.resume(); } catch { ... }
)
Both of the above seem pretty incorrect behaviors to me 🤔
What would the benefit of deferring be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry mate, I missed a return
statement after the nextTick
in my code suggestion.
You are right that the error would not be try-catchable. But looking at the test test/parallel/test-repl-import-referrer.js
that needs setting a large number seems a bit flimsy, I just gave a try on my less powerful intel macbook pro (2020) and I need to set it to 400ms
to pass the test, so I am not too sure if 300ms
would be sufficient (as our CI has some underpowered machines).
That leads me to the deferred error throw path, but it is just a little bit too late for me to dive into it, I will try to take a look tomorrow if I can, but my suggestion / concern is definitely non-blocking.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, ok thanks for the input and interest here 🙂
If it's just to make the tests happy then I would really strongly prefer to instead try to rework the tests not to use setTimeout
at all, which is something I'd be completely happy to look into (as I mentioned before I already attempted that and it didn't look worth it, but given the issues you're seeing maybe it would be?)
WDYT? 🙂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think of this solution? 🙂 ff336e5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the rest of the function would incorrectly run, for example emitting events such as resume
(this could cause subtle bugs with potential listeners of such events (rli.on('resume', () => {...})))
Since I mentioned it I figured it'd be nice to test this too 👀 f6b9d13
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the solution is more robust indeed!
If it's just to make the tests happy then I would really strongly prefer to instead try to rework the tests not to use setTimeout at all
I think my concern was not only to make the tests happy but more from a user land perspective that .end
for example:
child.stdin.write('await import(\'./message.mjs\');\n');
child.stdin.write('.exit');
child.stdin.end();
taken from test test/parallel/test-repl-import-referrer.js
has an unpredictable behaviour. I've started a new CI and once its green let's kick started a CITGM and see the impact on the user land packages 👍
By default if no duration is passed in, |
I've added |
210cf04
to
a104b57
Compare
b571760
to
ff336e5
Compare
@jakecastelli no more |
c4e42bd
to
f6b9d13
Compare
Would you mind taking a look at the CI failure when you have time.
let me know if you need to rerun the failure CI again |
Fixes #57678
This PR makes it so that calling
pause()
,resume()
orwrite()
on a closed readline interface results inERR_USE_AFTER_CLOSE
errors being thrown (following the same behavior asquestion()
)Note
I'm slightly concerned regarding the tests I needed to update, as those might indicate that the stricted
readline checks might have some potential unwanted implications, if the changes here were to land it might be
safer to add them as a semver major I think 🤔