mirror of
https://github.com/Microsoft/vscode
synced 2024-08-27 21:09:43 +00:00
* tests - convert history tracker to in-memory (#149712) * fix warnings from missing service * sqlite slowness * disable flush on write in tests unless disk tests * more runWithFakedTimers * disable flush also in pfs * fix compile
This commit is contained in:
parent
070f29955d
commit
aeb4a695fc
|
@ -390,6 +390,9 @@ interface IEnsuredWriteFileOptions extends IWriteFileOptions {
|
||||||
}
|
}
|
||||||
|
|
||||||
let canFlush = true;
|
let canFlush = true;
|
||||||
|
export function configureFlushOnWrite(enabled: boolean): void {
|
||||||
|
canFlush = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
// Calls fs.writeFile() followed by a fs.sync() call to flush the changes to disk
|
// Calls fs.writeFile() followed by a fs.sync() call to flush the changes to disk
|
||||||
// We do this in cases where we want to make sure the data is really on disk and
|
// We do this in cases where we want to make sure the data is really on disk and
|
||||||
|
@ -421,7 +424,7 @@ function doWriteFileAndFlush(path: string, data: string | Buffer | Uint8Array, o
|
||||||
// In that case we disable flushing and warn to the console
|
// In that case we disable flushing and warn to the console
|
||||||
if (syncError) {
|
if (syncError) {
|
||||||
console.warn('[node.js fs] fdatasync is now disabled for this session because it failed: ', syncError);
|
console.warn('[node.js fs] fdatasync is now disabled for this session because it failed: ', syncError);
|
||||||
canFlush = false;
|
configureFlushOnWrite(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fs.close(fd, closeError => callback(closeError));
|
return fs.close(fd, closeError => callback(closeError));
|
||||||
|
@ -455,7 +458,7 @@ export function writeFileSync(path: string, data: string | Buffer, options?: IWr
|
||||||
fs.fdatasyncSync(fd); // https://github.com/microsoft/vscode/issues/9589
|
fs.fdatasyncSync(fd); // https://github.com/microsoft/vscode/issues/9589
|
||||||
} catch (syncError) {
|
} catch (syncError) {
|
||||||
console.warn('[node.js fs] fdatasyncSync is now disabled for this session because it failed: ', syncError);
|
console.warn('[node.js fs] fdatasyncSync is now disabled for this session because it failed: ', syncError);
|
||||||
canFlush = false;
|
configureFlushOnWrite(false);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
fs.closeSync(fd);
|
fs.closeSync(fd);
|
||||||
|
|
|
@ -670,7 +670,7 @@ flakySuite('SQLite Storage Library', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('multiple concurrent writes execute in sequence', async () => {
|
test('multiple concurrent writes execute in sequence', async () => {
|
||||||
|
return runWithFakedTimers({}, async () => {
|
||||||
class TestStorage extends Storage {
|
class TestStorage extends Storage {
|
||||||
getStorage(): IStorageDatabase {
|
getStorage(): IStorageDatabase {
|
||||||
return this.database;
|
return this.database;
|
||||||
|
@ -721,6 +721,7 @@ flakySuite('SQLite Storage Library', function () {
|
||||||
|
|
||||||
await storage.close();
|
await storage.close();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('lots of INSERT & DELETE (below inline max)', async () => {
|
test('lots of INSERT & DELETE (below inline max)', async () => {
|
||||||
const storage = new SQLiteStorageDatabase(join(testdir, 'storage.db'));
|
const storage = new SQLiteStorageDatabase(join(testdir, 'storage.db'));
|
||||||
|
|
|
@ -11,21 +11,28 @@ import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
import { randomPath } from 'vs/base/common/extpath';
|
import { randomPath } from 'vs/base/common/extpath';
|
||||||
import { join, sep } from 'vs/base/common/path';
|
import { join, sep } from 'vs/base/common/path';
|
||||||
import { isWindows } from 'vs/base/common/platform';
|
import { isWindows } from 'vs/base/common/platform';
|
||||||
import { Promises, RimRafMode, rimrafSync, SymlinkSupport, writeFileSync } from 'vs/base/node/pfs';
|
import { configureFlushOnWrite, Promises, RimRafMode, rimrafSync, SymlinkSupport, writeFileSync } from 'vs/base/node/pfs';
|
||||||
import { flakySuite, getPathFromAmdModule, getRandomTestPath } from 'vs/base/test/node/testUtils';
|
import { flakySuite, getPathFromAmdModule, getRandomTestPath } from 'vs/base/test/node/testUtils';
|
||||||
|
|
||||||
|
configureFlushOnWrite(false); // speed up all unit tests by disabling flush on write
|
||||||
|
|
||||||
flakySuite('PFS', function () {
|
flakySuite('PFS', function () {
|
||||||
|
|
||||||
let testDir: string;
|
let testDir: string;
|
||||||
|
|
||||||
setup(() => {
|
setup(() => {
|
||||||
|
configureFlushOnWrite(true); // but enable flushing for the purpose of these tests
|
||||||
testDir = getRandomTestPath(tmpdir(), 'vsctests', 'pfs');
|
testDir = getRandomTestPath(tmpdir(), 'vsctests', 'pfs');
|
||||||
|
|
||||||
return Promises.mkdir(testDir, { recursive: true });
|
return Promises.mkdir(testDir, { recursive: true });
|
||||||
});
|
});
|
||||||
|
|
||||||
teardown(() => {
|
teardown(async () => {
|
||||||
return Promises.rm(testDir);
|
try {
|
||||||
|
await Promises.rm(testDir);
|
||||||
|
} finally {
|
||||||
|
configureFlushOnWrite(false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('writeFile', async () => {
|
test('writeFile', async () => {
|
||||||
|
|
|
@ -143,6 +143,10 @@ export class InMemoryFileSystemProvider extends Disposable implements IFileSyste
|
||||||
}
|
}
|
||||||
|
|
||||||
async mkdir(resource: URI): Promise<void> {
|
async mkdir(resource: URI): Promise<void> {
|
||||||
|
if (this._lookup(resource, true)) {
|
||||||
|
throw new FileSystemProviderError('file exists already', FileSystemProviderErrorCode.FileExists);
|
||||||
|
}
|
||||||
|
|
||||||
const basename = resources.basename(resource);
|
const basename = resources.basename(resource);
|
||||||
const dirname = resources.dirname(resource);
|
const dirname = resources.dirname(resource);
|
||||||
const parent = this._lookupAsDirectory(dirname, false);
|
const parent = this._lookupAsDirectory(dirname, false);
|
||||||
|
|
|
@ -258,7 +258,12 @@ export class DiskFileSystemProvider extends AbstractDiskFileSystemProvider imple
|
||||||
private readonly mapHandleToLock = new Map<number, IDisposable>();
|
private readonly mapHandleToLock = new Map<number, IDisposable>();
|
||||||
|
|
||||||
private readonly writeHandles = new Map<number, URI>();
|
private readonly writeHandles = new Map<number, URI>();
|
||||||
private canFlush: boolean = true;
|
|
||||||
|
private static canFlush: boolean = true;
|
||||||
|
|
||||||
|
static configureFlushOnWrite(enabled: boolean): void {
|
||||||
|
DiskFileSystemProvider.canFlush = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
async open(resource: URI, opts: IFileOpenOptions): Promise<number> {
|
async open(resource: URI, opts: IFileOpenOptions): Promise<number> {
|
||||||
const filePath = this.toFilePath(resource);
|
const filePath = this.toFilePath(resource);
|
||||||
|
@ -389,13 +394,13 @@ export class DiskFileSystemProvider extends AbstractDiskFileSystemProvider imple
|
||||||
|
|
||||||
// If a handle is closed that was used for writing, ensure
|
// If a handle is closed that was used for writing, ensure
|
||||||
// to flush the contents to disk if possible.
|
// to flush the contents to disk if possible.
|
||||||
if (this.writeHandles.delete(fd) && this.canFlush) {
|
if (this.writeHandles.delete(fd) && DiskFileSystemProvider.canFlush) {
|
||||||
try {
|
try {
|
||||||
await Promises.fdatasync(fd); // https://github.com/microsoft/vscode/issues/9589
|
await Promises.fdatasync(fd); // https://github.com/microsoft/vscode/issues/9589
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// In some exotic setups it is well possible that node fails to sync
|
// In some exotic setups it is well possible that node fails to sync
|
||||||
// In that case we disable flushing and log the error to our logger
|
// In that case we disable flushing and log the error to our logger
|
||||||
this.canFlush = false;
|
DiskFileSystemProvider.configureFlushOnWrite(false);
|
||||||
this.logService.error(error);
|
this.logService.error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,6 +127,8 @@ export class TestDiskFileSystemProvider extends DiskFileSystemProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DiskFileSystemProvider.configureFlushOnWrite(false); // speed up all unit tests by disabling flush on write
|
||||||
|
|
||||||
flakySuite('Disk File Service', function () {
|
flakySuite('Disk File Service', function () {
|
||||||
|
|
||||||
const testSchema = 'test';
|
const testSchema = 'test';
|
||||||
|
@ -140,6 +142,8 @@ flakySuite('Disk File Service', function () {
|
||||||
const disposables = new DisposableStore();
|
const disposables = new DisposableStore();
|
||||||
|
|
||||||
setup(async () => {
|
setup(async () => {
|
||||||
|
DiskFileSystemProvider.configureFlushOnWrite(true); // but enable flushing for the purpose of these tests
|
||||||
|
|
||||||
const logService = new NullLogService();
|
const logService = new NullLogService();
|
||||||
|
|
||||||
service = new FileService(logService);
|
service = new FileService(logService);
|
||||||
|
@ -160,10 +164,14 @@ flakySuite('Disk File Service', function () {
|
||||||
await Promises.copy(sourceDir, testDir, { preserveSymlinks: false });
|
await Promises.copy(sourceDir, testDir, { preserveSymlinks: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
teardown(() => {
|
teardown(async () => {
|
||||||
|
try {
|
||||||
disposables.clear();
|
disposables.clear();
|
||||||
|
|
||||||
return Promises.rm(testDir);
|
await Promises.rm(testDir);
|
||||||
|
} finally {
|
||||||
|
DiskFileSystemProvider.configureFlushOnWrite(false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('createFolder', async () => {
|
test('createFolder', async () => {
|
||||||
|
|
|
@ -17,7 +17,7 @@ import { Range } from 'vs/editor/common/core/range';
|
||||||
import { Position } from 'vs/editor/common/core/position';
|
import { Position } from 'vs/editor/common/core/position';
|
||||||
import { IModelService } from 'vs/editor/common/services/model';
|
import { IModelService } from 'vs/editor/common/services/model';
|
||||||
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
import { EditOperation } from 'vs/editor/common/core/editOperation';
|
||||||
import { TestFileService, TestEditorService, TestEditorGroupsService, TestEnvironmentService, TestLifecycleService } from 'vs/workbench/test/browser/workbenchTestServices';
|
import { TestFileService, TestEditorService, TestEditorGroupsService, TestEnvironmentService, TestLifecycleService, TestWorkingCopyService } from 'vs/workbench/test/browser/workbenchTestServices';
|
||||||
import { BulkEditService } from 'vs/workbench/contrib/bulkEdit/browser/bulkEditService';
|
import { BulkEditService } from 'vs/workbench/contrib/bulkEdit/browser/bulkEditService';
|
||||||
import { NullLogService, ILogService } from 'vs/platform/log/common/log';
|
import { NullLogService, ILogService } from 'vs/platform/log/common/log';
|
||||||
import { ITextModelService, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
import { ITextModelService, IResolvedTextEditorModel } from 'vs/editor/common/services/resolverService';
|
||||||
|
@ -56,6 +56,7 @@ import { LanguageService } from 'vs/editor/common/services/languageService';
|
||||||
import { LanguageFeatureDebounceService } from 'vs/editor/common/services/languageFeatureDebounce';
|
import { LanguageFeatureDebounceService } from 'vs/editor/common/services/languageFeatureDebounce';
|
||||||
import { LanguageFeaturesService } from 'vs/editor/common/services/languageFeaturesService';
|
import { LanguageFeaturesService } from 'vs/editor/common/services/languageFeaturesService';
|
||||||
import { MainThreadBulkEdits } from 'vs/workbench/api/browser/mainThreadBulkEdits';
|
import { MainThreadBulkEdits } from 'vs/workbench/api/browser/mainThreadBulkEdits';
|
||||||
|
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
|
||||||
|
|
||||||
suite('MainThreadEditors', () => {
|
suite('MainThreadEditors', () => {
|
||||||
|
|
||||||
|
@ -114,6 +115,7 @@ suite('MainThreadEditors', () => {
|
||||||
services.set(IFileService, new TestFileService());
|
services.set(IFileService, new TestFileService());
|
||||||
services.set(IEditorService, new TestEditorService());
|
services.set(IEditorService, new TestEditorService());
|
||||||
services.set(ILifecycleService, new TestLifecycleService());
|
services.set(ILifecycleService, new TestLifecycleService());
|
||||||
|
services.set(IWorkingCopyService, new TestWorkingCopyService());
|
||||||
services.set(IEditorGroupsService, new TestEditorGroupsService());
|
services.set(IEditorGroupsService, new TestEditorGroupsService());
|
||||||
services.set(ITextFileService, new class extends mock<ITextFileService>() {
|
services.set(ITextFileService, new class extends mock<ITextFileService>() {
|
||||||
override isDirty() { return false; }
|
override isDirty() { return false; }
|
||||||
|
|
|
@ -83,7 +83,7 @@ class SurroundWithSnippetEditorAction extends EditorAction2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
SnippetController2.get(editor)?.insert(snippet.codeSnippet, { clipboardText });
|
SnippetController2.get(editor)?.insert(snippet.codeSnippet, { clipboardText });
|
||||||
snippetService.updateUsageTimestamp(snippet);
|
snippetsService.updateUsageTimestamp(snippet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -193,7 +193,8 @@ export class WorkingCopyHistoryTracker extends Disposable implements IWorkbenchC
|
||||||
private shouldTrackHistory(resource: URI, stat: IFileStatWithMetadata): boolean {
|
private shouldTrackHistory(resource: URI, stat: IFileStatWithMetadata): boolean {
|
||||||
if (
|
if (
|
||||||
resource.scheme !== this.pathService.defaultUriScheme && // track history for all workspace resources
|
resource.scheme !== this.pathService.defaultUriScheme && // track history for all workspace resources
|
||||||
resource.scheme !== Schemas.vscodeUserData // track history for all settings
|
resource.scheme !== Schemas.vscodeUserData && // track history for all settings
|
||||||
|
resource.scheme !== Schemas.inMemory // track history for tests that use in-memory
|
||||||
) {
|
) {
|
||||||
return false; // do not support unknown resources
|
return false; // do not support unknown resources
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor';
|
||||||
import { ResourceWorkingCopy } from 'vs/workbench/services/workingCopy/common/resourceWorkingCopy';
|
import { ResourceWorkingCopy } from 'vs/workbench/services/workingCopy/common/resourceWorkingCopy';
|
||||||
import { WorkingCopyCapabilities, IWorkingCopyBackup } from 'vs/workbench/services/workingCopy/common/workingCopy';
|
import { WorkingCopyCapabilities, IWorkingCopyBackup } from 'vs/workbench/services/workingCopy/common/workingCopy';
|
||||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||||
|
import { runWithFakedTimers } from 'vs/base/test/common/timeTravelScheduler';
|
||||||
|
|
||||||
suite('ResourceWorkingCopy', function () {
|
suite('ResourceWorkingCopy', function () {
|
||||||
|
|
||||||
|
@ -55,6 +56,7 @@ suite('ResourceWorkingCopy', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('orphaned tracking', async () => {
|
test('orphaned tracking', async () => {
|
||||||
|
runWithFakedTimers({}, async () => {
|
||||||
assert.strictEqual(workingCopy.isOrphaned(), false);
|
assert.strictEqual(workingCopy.isOrphaned(), false);
|
||||||
|
|
||||||
let onDidChangeOrphanedPromise = Event.toPromise(workingCopy.onDidChangeOrphaned);
|
let onDidChangeOrphanedPromise = Event.toPromise(workingCopy.onDidChangeOrphaned);
|
||||||
|
@ -71,6 +73,7 @@ suite('ResourceWorkingCopy', function () {
|
||||||
await onDidChangeOrphanedPromise;
|
await onDidChangeOrphanedPromise;
|
||||||
assert.strictEqual(workingCopy.isOrphaned(), false);
|
assert.strictEqual(workingCopy.isOrphaned(), false);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
test('dispose, isDisposed', async () => {
|
test('dispose, isDisposed', async () => {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { FileChangesEvent, FileChangeType, FileOperationError, FileOperationResu
|
||||||
import { SaveReason, SaveSourceRegistry } from 'vs/workbench/common/editor';
|
import { SaveReason, SaveSourceRegistry } from 'vs/workbench/common/editor';
|
||||||
import { Promises } from 'vs/base/common/async';
|
import { Promises } from 'vs/base/common/async';
|
||||||
import { consumeReadable, consumeStream, isReadableStream } from 'vs/base/common/stream';
|
import { consumeReadable, consumeStream, isReadableStream } from 'vs/base/common/stream';
|
||||||
|
import { runWithFakedTimers } from 'vs/base/test/common/timeTravelScheduler';
|
||||||
|
|
||||||
export class TestStoredFileWorkingCopyModel extends Disposable implements IStoredFileWorkingCopyModel {
|
export class TestStoredFileWorkingCopyModel extends Disposable implements IStoredFileWorkingCopyModel {
|
||||||
|
|
||||||
|
@ -126,6 +127,7 @@ suite('StoredFileWorkingCopy', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('orphaned tracking', async () => {
|
test('orphaned tracking', async () => {
|
||||||
|
runWithFakedTimers({}, async () => {
|
||||||
assert.strictEqual(workingCopy.hasState(StoredFileWorkingCopyState.ORPHAN), false);
|
assert.strictEqual(workingCopy.hasState(StoredFileWorkingCopyState.ORPHAN), false);
|
||||||
|
|
||||||
let onDidChangeOrphanedPromise = Event.toPromise(workingCopy.onDidChangeOrphaned);
|
let onDidChangeOrphanedPromise = Event.toPromise(workingCopy.onDidChangeOrphaned);
|
||||||
|
@ -142,6 +144,7 @@ suite('StoredFileWorkingCopy', function () {
|
||||||
await onDidChangeOrphanedPromise;
|
await onDidChangeOrphanedPromise;
|
||||||
assert.strictEqual(workingCopy.hasState(StoredFileWorkingCopyState.ORPHAN), false);
|
assert.strictEqual(workingCopy.hasState(StoredFileWorkingCopyState.ORPHAN), false);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('dirty', async () => {
|
test('dirty', async () => {
|
||||||
assert.strictEqual(workingCopy.isDirty(), false);
|
assert.strictEqual(workingCopy.isDirty(), false);
|
||||||
|
@ -294,6 +297,7 @@ suite('StoredFileWorkingCopy', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('resolve (with backup, preserves metadata and orphaned state)', async () => {
|
test('resolve (with backup, preserves metadata and orphaned state)', async () => {
|
||||||
|
runWithFakedTimers({}, async () => {
|
||||||
await workingCopy.resolve({ contents: bufferToStream(VSBuffer.fromString('hello backup')) });
|
await workingCopy.resolve({ contents: bufferToStream(VSBuffer.fromString('hello backup')) });
|
||||||
|
|
||||||
const orphanedPromise = Event.toPromise(workingCopy.onDidChangeOrphaned);
|
const orphanedPromise = Event.toPromise(workingCopy.onDidChangeOrphaned);
|
||||||
|
@ -319,8 +323,10 @@ suite('StoredFileWorkingCopy', function () {
|
||||||
const backup2 = await workingCopy.backup(CancellationToken.None);
|
const backup2 = await workingCopy.backup(CancellationToken.None);
|
||||||
assert.deepStrictEqual(backup.meta, backup2.meta);
|
assert.deepStrictEqual(backup.meta, backup2.meta);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('resolve (updates orphaned state accordingly)', async () => {
|
test('resolve (updates orphaned state accordingly)', async () => {
|
||||||
|
runWithFakedTimers({}, async () => {
|
||||||
await workingCopy.resolve();
|
await workingCopy.resolve();
|
||||||
|
|
||||||
const orphanedPromise = Event.toPromise(workingCopy.onDidChangeOrphaned);
|
const orphanedPromise = Event.toPromise(workingCopy.onDidChangeOrphaned);
|
||||||
|
@ -345,6 +351,7 @@ suite('StoredFileWorkingCopy', function () {
|
||||||
accessor.fileService.readShouldThrowError = undefined;
|
accessor.fileService.readShouldThrowError = undefined;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('resolve (FILE_NOT_MODIFIED_SINCE can be handled for resolved working copies)', async () => {
|
test('resolve (FILE_NOT_MODIFIED_SINCE can be handled for resolved working copies)', async () => {
|
||||||
await workingCopy.resolve();
|
await workingCopy.resolve();
|
||||||
|
@ -573,6 +580,7 @@ suite('StoredFileWorkingCopy', function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('save (no errors) - save clears orphaned', async () => {
|
test('save (no errors) - save clears orphaned', async () => {
|
||||||
|
runWithFakedTimers({}, async () => {
|
||||||
let savedCounter = 0;
|
let savedCounter = 0;
|
||||||
workingCopy.onDidSave(e => {
|
workingCopy.onDidSave(e => {
|
||||||
savedCounter++;
|
savedCounter++;
|
||||||
|
@ -600,6 +608,7 @@ suite('StoredFileWorkingCopy', function () {
|
||||||
assert.strictEqual(workingCopy.isDirty(), false);
|
assert.strictEqual(workingCopy.isDirty(), false);
|
||||||
assert.strictEqual(workingCopy.hasState(StoredFileWorkingCopyState.ORPHAN), false);
|
assert.strictEqual(workingCopy.hasState(StoredFileWorkingCopyState.ORPHAN), false);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('save (errors)', async () => {
|
test('save (errors)', async () => {
|
||||||
let savedCounter = 0;
|
let savedCounter = 0;
|
||||||
|
|
|
@ -30,12 +30,12 @@ import { firstOrDefault } from 'vs/base/common/arrays';
|
||||||
|
|
||||||
class TestWorkbenchEnvironmentService extends NativeWorkbenchEnvironmentService {
|
class TestWorkbenchEnvironmentService extends NativeWorkbenchEnvironmentService {
|
||||||
|
|
||||||
constructor(private readonly testDir: string) {
|
constructor(private readonly testDir: URI | string) {
|
||||||
super({ ...TestNativeWindowConfiguration, 'user-data-dir': testDir }, TestProductService);
|
super({ ...TestNativeWindowConfiguration, 'user-data-dir': URI.isUri(testDir) ? testDir.fsPath : testDir }, TestProductService);
|
||||||
}
|
}
|
||||||
|
|
||||||
override get localHistoryHome() {
|
override get localHistoryHome() {
|
||||||
return joinPath(URI.file(this.testDir), 'History');
|
return joinPath(URI.isUri(this.testDir) ? this.testDir : URI.file(this.testDir), 'History');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ export class TestWorkingCopyHistoryService extends NativeWorkingCopyHistoryServi
|
||||||
readonly _configurationService: TestConfigurationService;
|
readonly _configurationService: TestConfigurationService;
|
||||||
readonly _lifecycleService: TestLifecycleService;
|
readonly _lifecycleService: TestLifecycleService;
|
||||||
|
|
||||||
constructor(testDir: string) {
|
constructor(testDir: URI | string) {
|
||||||
const environmentService = new TestWorkbenchEnvironmentService(testDir);
|
const environmentService = new TestWorkbenchEnvironmentService(testDir);
|
||||||
const logService = new NullLogService();
|
const logService = new NullLogService();
|
||||||
const fileService = new FileService(logService);
|
const fileService = new FileService(logService);
|
||||||
|
|
|
@ -5,12 +5,10 @@
|
||||||
|
|
||||||
import * as assert from 'assert';
|
import * as assert from 'assert';
|
||||||
import { Event } from 'vs/base/common/event';
|
import { Event } from 'vs/base/common/event';
|
||||||
import { flakySuite } from 'vs/base/test/common/testUtils';
|
|
||||||
import { TestContextService, TestWorkingCopy } from 'vs/workbench/test/common/workbenchTestServices';
|
import { TestContextService, TestWorkingCopy } from 'vs/workbench/test/common/workbenchTestServices';
|
||||||
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
|
import { randomPath } from 'vs/base/common/extpath';
|
||||||
import { tmpdir } from 'os';
|
import { tmpdir } from 'os';
|
||||||
import { join } from 'vs/base/common/path';
|
import { join } from 'vs/base/common/path';
|
||||||
import { Promises } from 'vs/base/node/pfs';
|
|
||||||
import { URI } from 'vs/base/common/uri';
|
import { URI } from 'vs/base/common/uri';
|
||||||
import { TestWorkingCopyHistoryService } from 'vs/workbench/services/workingCopy/test/electron-browser/workingCopyHistoryService.test';
|
import { TestWorkingCopyHistoryService } from 'vs/workbench/services/workingCopy/test/electron-browser/workingCopyHistoryService.test';
|
||||||
import { WorkingCopyHistoryTracker } from 'vs/workbench/services/workingCopy/common/workingCopyHistoryTracker';
|
import { WorkingCopyHistoryTracker } from 'vs/workbench/services/workingCopy/common/workingCopyHistoryTracker';
|
||||||
|
@ -28,22 +26,26 @@ import { TestNotificationService } from 'vs/platform/notification/test/common/te
|
||||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
import { IWorkingCopyHistoryEntry, IWorkingCopyHistoryEntryDescriptor } from 'vs/workbench/services/workingCopy/common/workingCopyHistory';
|
import { IWorkingCopyHistoryEntry, IWorkingCopyHistoryEntryDescriptor } from 'vs/workbench/services/workingCopy/common/workingCopyHistory';
|
||||||
import { assertIsDefined } from 'vs/base/common/types';
|
import { assertIsDefined } from 'vs/base/common/types';
|
||||||
|
import { VSBuffer } from 'vs/base/common/buffer';
|
||||||
|
import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
|
||||||
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
|
|
||||||
flakySuite('WorkingCopyHistoryTracker', () => {
|
suite('WorkingCopyHistoryTracker', () => {
|
||||||
|
|
||||||
let testDir: string;
|
let testDir: URI;
|
||||||
let historyHome: string;
|
let historyHome: URI;
|
||||||
let workHome: string;
|
let workHome: URI;
|
||||||
|
|
||||||
let workingCopyHistoryService: TestWorkingCopyHistoryService;
|
let workingCopyHistoryService: TestWorkingCopyHistoryService;
|
||||||
let workingCopyService: WorkingCopyService;
|
let workingCopyService: WorkingCopyService;
|
||||||
let fileService: IFileService;
|
let fileService: IFileService;
|
||||||
let configurationService: TestConfigurationService;
|
let configurationService: TestConfigurationService;
|
||||||
|
let inMemoryFileSystemDisposable: IDisposable;
|
||||||
|
|
||||||
let tracker: WorkingCopyHistoryTracker;
|
let tracker: WorkingCopyHistoryTracker;
|
||||||
|
|
||||||
let testFile1Path: string;
|
let testFile1Path: URI;
|
||||||
let testFile2Path: string;
|
let testFile2Path: URI;
|
||||||
|
|
||||||
const testFile1PathContents = 'Hello Foo';
|
const testFile1PathContents = 'Hello Foo';
|
||||||
const testFile2PathContents = [
|
const testFile2PathContents = [
|
||||||
|
@ -65,25 +67,27 @@ flakySuite('WorkingCopyHistoryTracker', () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
setup(async () => {
|
setup(async () => {
|
||||||
testDir = getRandomTestPath(tmpdir(), 'vsctests', 'workingcopyhistorytracker');
|
testDir = URI.file(randomPath(join(tmpdir(), 'vsctests', 'workingcopyhistorytracker'))).with({ scheme: Schemas.inMemory });
|
||||||
historyHome = join(testDir, 'User', 'History');
|
historyHome = joinPath(testDir, 'User', 'History');
|
||||||
workHome = join(testDir, 'work');
|
workHome = joinPath(testDir, 'work');
|
||||||
|
|
||||||
workingCopyHistoryService = new TestWorkingCopyHistoryService(testDir);
|
workingCopyHistoryService = new TestWorkingCopyHistoryService(testDir);
|
||||||
workingCopyService = new WorkingCopyService();
|
workingCopyService = new WorkingCopyService();
|
||||||
fileService = workingCopyHistoryService._fileService;
|
fileService = workingCopyHistoryService._fileService;
|
||||||
configurationService = workingCopyHistoryService._configurationService;
|
configurationService = workingCopyHistoryService._configurationService;
|
||||||
|
|
||||||
|
inMemoryFileSystemDisposable = fileService.registerProvider(Schemas.inMemory, new InMemoryFileSystemProvider());
|
||||||
|
|
||||||
tracker = createTracker();
|
tracker = createTracker();
|
||||||
|
|
||||||
await Promises.mkdir(historyHome, { recursive: true });
|
await fileService.createFolder(historyHome);
|
||||||
await Promises.mkdir(workHome, { recursive: true });
|
await fileService.createFolder(workHome);
|
||||||
|
|
||||||
testFile1Path = join(workHome, 'foo.txt');
|
testFile1Path = joinPath(workHome, 'foo.txt');
|
||||||
testFile2Path = join(workHome, 'bar.txt');
|
testFile2Path = joinPath(workHome, 'bar.txt');
|
||||||
|
|
||||||
await Promises.writeFile(testFile1Path, testFile1PathContents);
|
await fileService.writeFile(testFile1Path, VSBuffer.fromString(testFile1PathContents));
|
||||||
await Promises.writeFile(testFile2Path, testFile2PathContents);
|
await fileService.writeFile(testFile2Path, VSBuffer.fromString(testFile2PathContents));
|
||||||
});
|
});
|
||||||
|
|
||||||
function createTracker() {
|
function createTracker() {
|
||||||
|
@ -99,17 +103,19 @@ flakySuite('WorkingCopyHistoryTracker', () => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
teardown(() => {
|
teardown(async () => {
|
||||||
workingCopyHistoryService.dispose();
|
workingCopyHistoryService.dispose();
|
||||||
workingCopyService.dispose();
|
workingCopyService.dispose();
|
||||||
tracker.dispose();
|
tracker.dispose();
|
||||||
|
|
||||||
return Promises.rm(testDir);
|
await fileService.del(testDir, { recursive: true });
|
||||||
|
|
||||||
|
inMemoryFileSystemDisposable.dispose();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('history entry added on save', async () => {
|
test('history entry added on save', async () => {
|
||||||
const workingCopy1 = new TestWorkingCopy(URI.file(testFile1Path));
|
const workingCopy1 = new TestWorkingCopy(testFile1Path);
|
||||||
const workingCopy2 = new TestWorkingCopy(URI.file(testFile2Path));
|
const workingCopy2 = new TestWorkingCopy(testFile2Path);
|
||||||
|
|
||||||
const stat1 = await fileService.resolve(workingCopy1.resource, { resolveMetadata: true });
|
const stat1 = await fileService.resolve(workingCopy1.resource, { resolveMetadata: true });
|
||||||
const stat2 = await fileService.resolve(workingCopy2.resource, { resolveMetadata: true });
|
const stat2 = await fileService.resolve(workingCopy2.resource, { resolveMetadata: true });
|
||||||
|
@ -136,7 +142,7 @@ flakySuite('WorkingCopyHistoryTracker', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('history entry skipped when setting disabled (globally)', async () => {
|
test('history entry skipped when setting disabled (globally)', async () => {
|
||||||
configurationService.setUserConfiguration('workbench.localHistory.enabled', false, URI.file(testFile1Path));
|
configurationService.setUserConfiguration('workbench.localHistory.enabled', false, testFile1Path);
|
||||||
|
|
||||||
return assertNoLocalHistoryEntryAddedWithSettingsConfigured();
|
return assertNoLocalHistoryEntryAddedWithSettingsConfigured();
|
||||||
});
|
});
|
||||||
|
@ -152,14 +158,14 @@ flakySuite('WorkingCopyHistoryTracker', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('history entry skipped when too large', async () => {
|
test('history entry skipped when too large', async () => {
|
||||||
configurationService.setUserConfiguration('workbench.localHistory.maxFileSize', 0, URI.file(testFile1Path));
|
configurationService.setUserConfiguration('workbench.localHistory.maxFileSize', 0, testFile1Path);
|
||||||
|
|
||||||
return assertNoLocalHistoryEntryAddedWithSettingsConfigured();
|
return assertNoLocalHistoryEntryAddedWithSettingsConfigured();
|
||||||
});
|
});
|
||||||
|
|
||||||
async function assertNoLocalHistoryEntryAddedWithSettingsConfigured(): Promise<void> {
|
async function assertNoLocalHistoryEntryAddedWithSettingsConfigured(): Promise<void> {
|
||||||
const workingCopy1 = new TestWorkingCopy(URI.file(testFile1Path));
|
const workingCopy1 = new TestWorkingCopy(testFile1Path);
|
||||||
const workingCopy2 = new TestWorkingCopy(URI.file(testFile2Path));
|
const workingCopy2 = new TestWorkingCopy(testFile2Path);
|
||||||
|
|
||||||
const stat1 = await fileService.resolve(workingCopy1.resource, { resolveMetadata: true });
|
const stat1 = await fileService.resolve(workingCopy1.resource, { resolveMetadata: true });
|
||||||
const stat2 = await fileService.resolve(workingCopy2.resource, { resolveMetadata: true });
|
const stat2 = await fileService.resolve(workingCopy2.resource, { resolveMetadata: true });
|
||||||
|
@ -187,7 +193,7 @@ flakySuite('WorkingCopyHistoryTracker', () => {
|
||||||
test('entries moved (file rename)', async () => {
|
test('entries moved (file rename)', async () => {
|
||||||
const entriesMoved = Event.toPromise(workingCopyHistoryService.onDidMoveEntries);
|
const entriesMoved = Event.toPromise(workingCopyHistoryService.onDidMoveEntries);
|
||||||
|
|
||||||
const workingCopy = new TestWorkingCopy(URI.file(testFile1Path));
|
const workingCopy = new TestWorkingCopy(testFile1Path);
|
||||||
|
|
||||||
const entry1 = await addEntry({ resource: workingCopy.resource, source: 'test-source' }, CancellationToken.None);
|
const entry1 = await addEntry({ resource: workingCopy.resource, source: 'test-source' }, CancellationToken.None);
|
||||||
const entry2 = await addEntry({ resource: workingCopy.resource, source: 'test-source' }, CancellationToken.None);
|
const entry2 = await addEntry({ resource: workingCopy.resource, source: 'test-source' }, CancellationToken.None);
|
||||||
|
@ -233,8 +239,8 @@ flakySuite('WorkingCopyHistoryTracker', () => {
|
||||||
test('entries moved (folder rename)', async () => {
|
test('entries moved (folder rename)', async () => {
|
||||||
const entriesMoved = Event.toPromise(workingCopyHistoryService.onDidMoveEntries);
|
const entriesMoved = Event.toPromise(workingCopyHistoryService.onDidMoveEntries);
|
||||||
|
|
||||||
const workingCopy1 = new TestWorkingCopy(URI.file(testFile1Path));
|
const workingCopy1 = new TestWorkingCopy(testFile1Path);
|
||||||
const workingCopy2 = new TestWorkingCopy(URI.file(testFile2Path));
|
const workingCopy2 = new TestWorkingCopy(testFile2Path);
|
||||||
|
|
||||||
const entry1A = await addEntry({ resource: workingCopy1.resource, source: 'test-source' }, CancellationToken.None);
|
const entry1A = await addEntry({ resource: workingCopy1.resource, source: 'test-source' }, CancellationToken.None);
|
||||||
const entry2A = await addEntry({ resource: workingCopy1.resource, source: 'test-source' }, CancellationToken.None);
|
const entry2A = await addEntry({ resource: workingCopy1.resource, source: 'test-source' }, CancellationToken.None);
|
||||||
|
@ -250,8 +256,8 @@ flakySuite('WorkingCopyHistoryTracker', () => {
|
||||||
entries = await workingCopyHistoryService.getEntries(workingCopy2.resource, CancellationToken.None);
|
entries = await workingCopyHistoryService.getEntries(workingCopy2.resource, CancellationToken.None);
|
||||||
assert.strictEqual(entries.length, 3);
|
assert.strictEqual(entries.length, 3);
|
||||||
|
|
||||||
const renamedWorkHome = joinPath(dirname(URI.file(workHome)), 'renamed');
|
const renamedWorkHome = joinPath(dirname(testDir), 'renamed');
|
||||||
await workingCopyHistoryService._fileService.move(URI.file(workHome), renamedWorkHome);
|
await workingCopyHistoryService._fileService.move(workHome, renamedWorkHome);
|
||||||
|
|
||||||
const renamedWorkingCopy1Resource = joinPath(renamedWorkHome, basename(workingCopy1.resource));
|
const renamedWorkingCopy1Resource = joinPath(renamedWorkHome, basename(workingCopy1.resource));
|
||||||
const renamedWorkingCopy2Resource = joinPath(renamedWorkHome, basename(workingCopy2.resource));
|
const renamedWorkingCopy2Resource = joinPath(renamedWorkHome, basename(workingCopy2.resource));
|
||||||
|
|
Loading…
Reference in a new issue