-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Fix flakey file system tests #10541
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
Fix flakey file system tests #10541
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -8,7 +8,8 @@ import * as fs from 'fs-extra'; | |||||||||||
import { convertStat, FileSystem, FileSystemUtils, RawFileSystem } from '../../../client/common/platform/fileSystem'; | ||||||||||||
import { FileSystemPaths, FileSystemPathUtils } from '../../../client/common/platform/fs-paths'; | ||||||||||||
import { FileType } from '../../../client/common/platform/types'; | ||||||||||||
import { sleep } from '../../../client/common/utils/async'; | ||||||||||||
import { createDeferred, sleep } from '../../../client/common/utils/async'; | ||||||||||||
import { noop } from '../../../client/common/utils/misc'; | ||||||||||||
import { | ||||||||||||
assertDoesNotExist, | ||||||||||||
assertFileText, | ||||||||||||
|
@@ -267,13 +268,24 @@ suite('FileSystem - raw', () => { | |||||||||||
} | ||||||||||||
}); | ||||||||||||
|
||||||||||||
async function writeToStream(filename: string, write: (str: fs.WriteStream) => void) { | ||||||||||||
const closeDeferred = createDeferred(); | ||||||||||||
const stream = fileSystem.createWriteStream(filename); | ||||||||||||
stream.on('close', () => closeDeferred.resolve()); | ||||||||||||
write(stream); | ||||||||||||
stream.end(); | ||||||||||||
stream.close(); | ||||||||||||
stream.destroy(); | ||||||||||||
await closeDeferred.promise; | ||||||||||||
return stream; | ||||||||||||
} | ||||||||||||
|
||||||||||||
test('returns the correct WriteStream', async () => { | ||||||||||||
const filename = await fix.resolve('x/y/z/spam.py'); | ||||||||||||
const expected = fs.createWriteStream(filename); | ||||||||||||
expected.destroy(); | ||||||||||||
|
||||||||||||
const stream = fileSystem.createWriteStream(filename); | ||||||||||||
stream.destroy(); | ||||||||||||
const stream = await writeToStream(filename, noop); | ||||||||||||
|
||||||||||||
expect(stream.path).to.deep.equal(expected.path); | ||||||||||||
}); | ||||||||||||
|
@@ -283,9 +295,7 @@ suite('FileSystem - raw', () => { | |||||||||||
await assertDoesNotExist(filename); | ||||||||||||
const data = 'line1\nline2\n'; | ||||||||||||
|
||||||||||||
const stream = fileSystem.createWriteStream(filename); | ||||||||||||
stream.write(data); | ||||||||||||
stream.destroy(); | ||||||||||||
await writeToStream(filename, s => s.write(data)); | ||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW, I'm a big believer of keeping as much of the test-targeted code in the test function as possible. The following variation on your solution would do that. It uses a sort of context-manager style that reduces the amount of code the test cares about without obscuring the code the test does care about:
Suggested change
This would rely on the following helper, derived from async function withClosing(stream: WriteStream, test: () => void) {
const closeDeferred = createDeferred();
stream.on('close', () => closeDeferred.resolve());
test()
stream.end();
stream.close();
stream.destroy();
await closeDeferred.promise;
} Other approaches (in order to most-to-least readable result):
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry already submitted. Feel free to update if you like. There is no flush method on a stream though, so don't add that: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's actually a 'finish' event that fires after all data has been written. That's likely better than the close event. |
||||||||||||
|
||||||||||||
await assertFileText(filename, data); | ||||||||||||
}); | ||||||||||||
|
@@ -294,9 +304,7 @@ suite('FileSystem - raw', () => { | |||||||||||
const filename = await fix.resolve('x/y/z/spam.py'); | ||||||||||||
const data = '... 😁 ...'; | ||||||||||||
|
||||||||||||
const stream = fileSystem.createWriteStream(filename); | ||||||||||||
stream.write(data); | ||||||||||||
stream.destroy(); | ||||||||||||
await writeToStream(filename, s => s.write(data)); | ||||||||||||
|
||||||||||||
await assertFileText(filename, data); | ||||||||||||
}); | ||||||||||||
|
@@ -305,9 +313,7 @@ suite('FileSystem - raw', () => { | |||||||||||
const filename = await fix.createFile('x/y/z/spam.py', '...'); | ||||||||||||
const data = 'line1\nline2\n'; | ||||||||||||
|
||||||||||||
const stream = fileSystem.createWriteStream(filename); | ||||||||||||
stream.write(data); | ||||||||||||
stream.destroy(); | ||||||||||||
await writeToStream(filename, s => s.write(data)); | ||||||||||||
|
||||||||||||
await assertFileText(filename, data); | ||||||||||||
}); | ||||||||||||
|
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.
Isn't the requirement to check whether
createWriteStream
returns awritable stream
.At the end of the day the API is
createWriteStream
and that's what needs to be tested, not testing the functionality ofstream
object returned by nodejs.There are other methods on streams that we're not testing here,
pipe
,event handlers
, etc..I think the test is testing the wrong thing. We're testing if node streams work.
I'd suggest removing all the tests and changing to:
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.
Also, listening to
close
isn't sufficient, we'd need to listen toflush
event to know if data was flushed. But that's not necessary.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.
There is no flush method on the write stream.
And I didn't want to change the tests here, just make them pass. Who ever owns these can make that change.
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.
flush
eventend
method.@karthiknadig do we need such tests (see my comments).
Its just more unnecessary flaky tests. Also slower
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 testing that it returns a writable stream should be enough. If I remember correctly this particular API was not completely supported or we had some asks on VSCode. /cc @ericsnowcurrently for more info.
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.
@ericsnowcurrently I can make the change suggested if you like.
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'm just going to submit. Eric can change the tests later if he likes.
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.
These functional tests verify the behavior that the extension relies on. This matters because the node and vscode APIs don't have exactly the same behavior. Other similar functional tests uncovered such cases, showing why it's important to verify the expected behavior (to an extent).
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.
@rchiodo, as to checking for flush and calling .end(), I don't see a problem offhand. I'd have to double-check the node docs, but honestly, I trust Don. 😄
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.
True. And if the extension relies on those then we should consider testing them. Then again, it probably isn't worth the effort until the VS Code FS API provides some sort of WriteStream. My vote is to not add more tests. Regardless, it should be handled in a separate issue.