Smoke-Test: Hot-exit / dataloss tests broken (#89905)

* smoke test - carefuly select untitled content based on file name to find it properly

* Fileservice: mkdirp() logic is prone to errors from race conditions (fixes #89834)
This commit is contained in:
Benjamin Pasero 2020-02-03 09:38:03 +01:00 committed by GitHub
parent 39e290dbbc
commit d6eb50caa4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 4 deletions

View file

@ -752,7 +752,22 @@ export class FileService extends Disposable implements IFileService {
// Create directories as needed
for (let i = directoriesToCreate.length - 1; i >= 0; i--) {
directory = joinPath(directory, directoriesToCreate[i]);
await provider.mkdir(directory);
try {
await provider.mkdir(directory);
} catch (error) {
if (toFileSystemProviderErrorCode(error) !== FileSystemProviderErrorCode.FileExists) {
// For mkdirp() we tolerate that the mkdir() call fails
// in case the folder already exists. This follows node.js
// own implementation of fs.mkdir({ recursive: true }) and
// reduces the chances of race conditions leading to errors
// if multiple calls try to create the same folders
// As such, we only throw an error here if it is other than
// the fact that the file already exists.
// (see also https://github.com/microsoft/vscode/issues/89834)
throw error;
}
}
}
}

View file

@ -19,7 +19,7 @@ import { FileOperation, FileOperationEvent, IFileStat, FileOperationResult, File
import { NullLogService } from 'vs/platform/log/common/log';
import { isLinux, isWindows } from 'vs/base/common/platform';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { isEqual } from 'vs/base/common/resources';
import { isEqual, joinPath } from 'vs/base/common/resources';
import { VSBuffer, VSBufferReadable, streamToBufferReadableStream, VSBufferReadableStream, bufferToReadable, bufferToStream, streamToBuffer } from 'vs/base/common/buffer';
import { find } from 'vs/base/common/arrays';
@ -1867,6 +1867,47 @@ suite('Disk File Service', function () {
assert.ok(!error);
});
test('writeFile - no error when writing to same non-existing folder multiple times different new files', async () => {
const newFolder = URI.file(join(testDir, 'some', 'new', 'folder'));
const file1 = joinPath(newFolder, 'file-1');
const file2 = joinPath(newFolder, 'file-2');
const file3 = joinPath(newFolder, 'file-3');
// this essentially verifies that the mkdirp logic implemented
// in the file service is able to receive multiple requests for
// the same folder and will not throw errors if another racing
// call succeeded first.
const newContent = 'Updates to the small file';
await Promise.all([
service.writeFile(file1, VSBuffer.fromString(newContent)),
service.writeFile(file2, VSBuffer.fromString(newContent)),
service.writeFile(file3, VSBuffer.fromString(newContent))
]);
assert.ok(service.exists(file1));
assert.ok(service.exists(file2));
assert.ok(service.exists(file3));
});
test('writeFile - error when writing to folder that is a file', async () => {
const existingFile = URI.file(join(testDir, 'my-file'));
await service.createFile(existingFile);
const newFile = joinPath(existingFile, 'file-1');
let error;
const newContent = 'Updates to the small file';
try {
await service.writeFile(newFile, VSBuffer.fromString(newContent));
} catch (e) {
error = e;
}
assert.ok(error);
});
const runWatchTests = isLinux;
(runWatchTests ? test : test.skip)('watch - file', done => {

View file

@ -12,7 +12,7 @@ export function setup() {
await app.workbench.editors.newUntitledFile();
const untitled = 'Untitled-1';
const textToTypeInUntitled = 'Hello, Untitled Code';
const textToTypeInUntitled = untitled;
await app.workbench.editor.waitForTypeInEditor(untitled, textToTypeInUntitled);
const readmeMd = 'readme.md';

View file

@ -66,7 +66,7 @@ export function setup(stableCodePath: string, testDataPath: string) {
await stableApp.workbench.editors.newUntitledFile();
const untitled = 'Untitled-1';
const textToTypeInUntitled = 'Hello, Untitled Code';
const textToTypeInUntitled = untitled;
await stableApp.workbench.editor.waitForTypeInEditor(untitled, textToTypeInUntitled);
const readmeMd = 'readme.md';