backupTracker.test.ts 6.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import * as assert from 'assert';
import * as platform from 'vs/base/common/platform';
import * as os from 'os';
import * as path from 'vs/base/common/path';
import * as pfs from 'vs/base/node/pfs';
import { URI } from 'vs/base/common/uri';
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { hashPath } from 'vs/workbench/services/backup/node/backupFileService';
import { BackupTracker } from 'vs/workbench/contrib/backup/common/backupTracker';
import { TestTextFileService, workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices';
import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { EditorService } from 'vs/workbench/services/editor/browser/editorService';
import { Registry } from 'vs/platform/registry/common/platform';
import { EditorInput } from 'vs/workbench/common/editor';
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
import { TextFileEditor } from 'vs/workbench/contrib/files/browser/editors/textFileEditor';
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
import { NodeTestBackupFileService } from 'vs/workbench/services/backup/test/electron-browser/backupFileService.test';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { toResource } from 'vs/base/test/common/utils';
import { IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { ILogService } from 'vs/platform/log/common/log';

const userdataDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backuprestorer');
const backupHome = path.join(userdataDir, 'Backups');
const workspacesJsonPath = path.join(backupHome, 'workspaces.json');

const workspaceResource = URI.file(platform.isWindows ? 'c:\\workspace' : '/workspace');
const workspaceBackupPath = path.join(backupHome, hashPath(workspaceResource));

class ServiceAccessor {
	constructor(
		@ITextFileService public textFileService: TestTextFileService,
		@IEditorService public editorService: IEditorService,
		@IBackupFileService public backupFileService: NodeTestBackupFileService
	) {
	}
}

class TestBackupTracker extends BackupTracker {

	constructor(
		@IBackupFileService backupFileService: IBackupFileService,
		@IFilesConfigurationService filesConfigurationService: IFilesConfigurationService,
		@IWorkingCopyService workingCopyService: IWorkingCopyService,
		@ILogService logService: ILogService
	) {
		super(backupFileService, filesConfigurationService, workingCopyService, logService);

		// Reduce timeout for tests
		BackupTracker.BACKUP_FROM_CONTENT_CHANGE_DELAY = 10;
	}
}

suite('BackupTracker', () => {
	let accessor: ServiceAccessor;

	let disposables: IDisposable[] = [];

	setup(async () => {
		disposables.push(Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
			EditorDescriptor.create(
				TextFileEditor,
				TextFileEditor.ID,
				'Text File Editor'
			),
			[new SyncDescriptor<EditorInput>(FileEditorInput)]
		));

		// Delete any existing backups completely and then re-create it.
		await pfs.rimraf(backupHome, pfs.RimRafMode.MOVE);
		await pfs.mkdirp(backupHome);

		return pfs.writeFile(workspacesJsonPath, '');
	});

	teardown(async () => {
		dispose(disposables);
		disposables = [];

93
		(<TextFileEditorModelManager>accessor.textFileService.files).dispose();
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125

		return pfs.rimraf(backupHome, pfs.RimRafMode.MOVE);
	});

	async function createTracker(): Promise<[ServiceAccessor, EditorPart, BackupTracker]> {
		const backupFileService = new NodeTestBackupFileService(workspaceBackupPath);
		const instantiationService = workbenchInstantiationService();
		instantiationService.stub(IBackupFileService, backupFileService);

		const part = instantiationService.createInstance(EditorPart);
		part.create(document.createElement('div'));
		part.layout(400, 300);

		instantiationService.stub(IEditorGroupsService, part);

		const editorService: EditorService = instantiationService.createInstance(EditorService);
		instantiationService.stub(IEditorService, editorService);

		accessor = instantiationService.createInstance(ServiceAccessor);

		await part.whenRestored;

		const tracker = instantiationService.createInstance(TestBackupTracker);

		return [accessor, part, tracker];
	}

	test('Track backups (untitled)', async function () {
		this.timeout(20000);

		const [accessor, part, tracker] = await createTracker();

126
		const untitledEditor = accessor.textFileService.untitled.create();
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
		await accessor.editorService.openEditor(untitledEditor, { pinned: true });

		const untitledModel = await untitledEditor.resolve();
		untitledModel.textEditorModel.setValue('Super Good');

		await accessor.backupFileService.joinBackupResource();

		assert.equal(accessor.backupFileService.hasBackupSync(untitledEditor.getResource()), true);

		untitledModel.dispose();

		await accessor.backupFileService.joinDiscardBackup();

		assert.equal(accessor.backupFileService.hasBackupSync(untitledEditor.getResource()), false);

		part.dispose();
		tracker.dispose();
	});

	test('Track backups (file)', async function () {
		this.timeout(20000);

		const [accessor, part, tracker] = await createTracker();

		const resource = toResource.call(this, '/path/index.txt');
		await accessor.editorService.openEditor({ resource, options: { pinned: true } });

154
		const fileModel = accessor.textFileService.files.get(resource);
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
		fileModel?.textEditorModel?.setValue('Super Good');

		await accessor.backupFileService.joinBackupResource();

		assert.equal(accessor.backupFileService.hasBackupSync(resource), true);

		fileModel?.dispose();

		await accessor.backupFileService.joinDiscardBackup();

		assert.equal(accessor.backupFileService.hasBackupSync(resource), false);

		part.dispose();
		tracker.dispose();
	});
});