Skip to content

Conversation

rchiodo
Copy link

@rchiodo rchiodo commented Mar 12, 2020

File system tests seem to fail randomly. I believe it's because they're not waiting for the file write to finish.

Here's an example failure:
https://dev.azure.com/ms/vscode-python/_build/results?buildId=67769&view=ms.vss-test-web.build-test-results-tab&runId=2169996&resultId=100021&paneView=debug

@rchiodo rchiodo added the no-changelog No news entry required label Mar 12, 2020
@rchiodo rchiodo self-assigned this Mar 12, 2020
@sonarqubecloud
Copy link

Kudos, SonarCloud Quality Gate passed!

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities (and Security Hotspot 0 Security Hotspots to review)
Code Smell A 0 Code Smells

No Coverage information No Coverage information
0.0% 0.0% Duplication

@codecov-io
Copy link

Codecov Report

Merging #10541 into master will decrease coverage by 0.02%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff             @@
##           master   #10541      +/-   ##
==========================================
- Coverage   60.76%   60.74%   -0.03%     
==========================================
  Files         578      578              
  Lines       31355    31355              
  Branches     4463     4464       +1     
==========================================
- Hits        19053    19046       -7     
- Misses      11335    11339       +4     
- Partials      967      970       +3     
Impacted Files Coverage Δ
src/datascience-ui/react-common/arePathsSame.ts 75.00% <0.00%> (-12.50%) ⬇️
src/client/common/utils/platform.ts 64.70% <0.00%> (-11.77%) ⬇️
src/client/linters/pydocstyle.ts 86.66% <0.00%> (-2.23%) ⬇️
src/client/datascience/debugLocationTracker.ts 76.56% <0.00%> (-1.57%) ⬇️
src/client/debugger/extension/adapter/factory.ts 94.28% <0.00%> (-1.43%) ⬇️
src/client/common/process/proc.ts 14.49% <0.00%> (-0.73%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1b04ed7...1dd6e49. Read the comment docs.

async function writeToStream(filename: string, write: (str: fs.WriteStream) => void) {
const closeDeferred = createDeferred();
const stream = fileSystem.createWriteStream(filename);
stream.on('close', () => closeDeferred.resolve());

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 a writable stream.
At the end of the day the API is createWriteStream and that's what needs to be tested, not testing the functionality of stream 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:

const isStream = require('is-stream');
const stream = fileSystem.createWriteStream(filename);
assert.isOk(isStream.writable(stream))

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 to flush event to know if data was flushed. But that's not necessary.

Copy link
Author

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.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Check for flush event
  • Call end method.

Who ever owns these can make that change.

@karthiknadig do we need such tests (see my comments).
Its just more unnecessary flaky tests. Also slower

Copy link
Member

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.

Copy link
Author

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.

Copy link
Author

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.

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

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. 😄

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are other methods on streams that we're not testing here, pipe, event handlers, etc..

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.

@rchiodo rchiodo merged commit ca776ab into master Mar 13, 2020
Copy link

@ericsnowcurrently ericsnowcurrently left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

I just have one comment about a slightly different helper approach that keeps the code-under-test in the test function.

Also, the flush/end thing Don suggested (if you agree it makes sense).

const stream = fileSystem.createWriteStream(filename);
stream.write(data);
stream.destroy();
await writeToStream(filename, s => s.write(data));

Choose a reason for hiding this comment

The 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
await writeToStream(filename, s => s.write(data));
const stream = fileSystem.createWriteStream(filename);
await withClosing(stream, () => {
stream.write(data);
});

This would rely on the following helper, derived from writeToStream():

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

  • for tests on operations on the stream (rather than its creation), we could use a helper to create the stream:
    • function createWriteStream(filename: string): [WriteStream, () => Promise<void>] { ... }
  • combine that with the context-manager style:
    • async function withStream(filename: string, (stream: WriteStream) => Promise<void>) { ... }
  • be more exliicit about it (1 helpers):
    • function getCloser(stream: WriteStream): () => Promise<void> { ... }
  • be more exliicit about it (2 helpers):
    • function prepForClose(stream: WriteStream): Promise<void> { ... }
    • function destroyStream(stream: WriteStream) { ... }

Copy link
Author

Choose a reason for hiding this comment

The 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:
https://nodejs.org/api/stream.html

Copy link
Author

Choose a reason for hiding this comment

The 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.

@rchiodo rchiodo deleted the rchiodo/fix_filestream_tests branch March 13, 2020 16:34
DonJayamanne added a commit that referenced this pull request Mar 13, 2020
* master:
  Fix flakey file system tests (#10541)
  Tweaks for gather (#10532)
  Fix #10437: Update launch.json handling to support "listen" and "connect" (#10517)
  Add conda support to nightly flake test (#10523)
  Rename datascience to datascience_modules (#10525)
  Clean up the extension activation code. (#10455)
  Allow escape and ctrl+U to clear the interactive window (#10513)
  Fix builtins so they don't interfere with our execution (#10511)
  Jupyter autocompletion will only show up on empty lines, (#10420)
  notify on missing kernel and interpreter with kernel (#10508)
karthiknadig pushed a commit to karthiknadig/vscode-python that referenced this pull request Mar 19, 2020
karthiknadig added a commit that referenced this pull request Mar 19, 2020
* Update version and change log

* Fix flakey file system tests (#10541)

Co-authored-by: Rich Chiodo <rchiodo@users.noreply.github.com>
@lock lock bot locked as resolved and limited conversation to collaborators Mar 21, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

no-changelog No news entry required

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants