backupFileService.test.ts 14.2 KB
Newer Older
1 2 3 4 5 6 7 8
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

import * as assert from 'assert';
D
Daniel Imms 已提交
9
import * as platform from 'vs/base/common/platform';
10 11
import crypto = require('crypto');
import os = require('os');
12
import fs = require('fs');
13 14 15 16
import path = require('path');
import extfs = require('vs/base/node/extfs');
import pfs = require('vs/base/node/pfs');
import Uri from 'vs/base/common/uri';
B
Benjamin Pasero 已提交
17
import { BackupFileService, BackupFilesModel } from 'vs/workbench/services/backup/node/backupFileService';
18
import { FileService } from 'vs/workbench/services/files/node/fileService';
19
import { TextModel } from 'vs/editor/common/model/textModel';
20
import { TestContextService, TestTextResourceConfigurationService, getRandomTestPath, TestLifecycleService } from 'vs/workbench/test/workbenchTestServices';
21
import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
B
Benjamin Pasero 已提交
22
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
23 24
import { DefaultEndOfLine } from 'vs/editor/common/model';
import { snapshotToString } from 'vs/platform/files/common/files';
25

B
Benjamin Pasero 已提交
26
const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupfileservice');
D
Daniel Imms 已提交
27 28 29 30 31
const backupHome = path.join(parentDir, 'Backups');
const workspacesJsonPath = path.join(backupHome, 'workspaces.json');

const workspaceResource = Uri.file(platform.isWindows ? 'c:\\workspace' : '/workspace');
const workspaceBackupPath = path.join(backupHome, crypto.createHash('md5').update(workspaceResource.fsPath).digest('hex'));
32 33
const fooFile = Uri.file(platform.isWindows ? 'c:\\Foo' : '/Foo');
const barFile = Uri.file(platform.isWindows ? 'c:\\Bar' : '/Bar');
D
Daniel Imms 已提交
34 35 36
const untitledFile = Uri.from({ scheme: 'untitled', path: 'Untitled-1' });
const fooBackupPath = path.join(workspaceBackupPath, 'file', crypto.createHash('md5').update(fooFile.fsPath).digest('hex'));
const barBackupPath = path.join(workspaceBackupPath, 'file', crypto.createHash('md5').update(barFile.fsPath).digest('hex'));
37
const untitledBackupPath = path.join(workspaceBackupPath, 'untitled', crypto.createHash('md5').update(untitledFile.fsPath).digest('hex'));
D
Daniel Imms 已提交
38

39 40
class TestBackupFileService extends BackupFileService {
	constructor(workspace: Uri, backupHome: string, workspacesJsonPath: string) {
41
		const fileService = new FileService(new TestContextService(new Workspace(workspace.fsPath, workspace.fsPath, toWorkspaceFolders([{ path: workspace.fsPath }]))), new TestTextResourceConfigurationService(), new TestConfigurationService(), new TestLifecycleService(), { disableWatcher: true });
42

43
		super(workspaceBackupPath, fileService);
44 45
	}

46 47
	public toBackupResource(resource: Uri): Uri {
		return super.toBackupResource(resource);
48 49 50
	}
}

D
Daniel Imms 已提交
51
suite('BackupFileService', () => {
B
Benjamin Pasero 已提交
52
	let service: TestBackupFileService;
53 54

	setup(done => {
D
Daniel Imms 已提交
55
		service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath);
56

57 58 59
		// Delete any existing backups completely and then re-create it.
		extfs.del(backupHome, os.tmpdir(), () => {
			pfs.mkdirp(backupHome).then(() => {
60
				pfs.writeFile(workspacesJsonPath, '').then(() => {
61 62 63 64
					done();
				});
			});
		});
65 66 67
	});

	teardown(done => {
68
		extfs.del(backupHome, os.tmpdir(), done);
69 70
	});

D
Daniel Imms 已提交
71 72 73 74 75 76 77
	suite('getBackupResource', () => {
		test('should get the correct backup path for text files', () => {
			// Format should be: <backupHome>/<workspaceHash>/<scheme>/<filePathHash>
			const backupResource = fooFile;
			const workspaceHash = crypto.createHash('md5').update(workspaceResource.fsPath).digest('hex');
			const filePathHash = crypto.createHash('md5').update(backupResource.fsPath).digest('hex');
			const expectedPath = Uri.file(path.join(backupHome, workspaceHash, 'file', filePathHash)).fsPath;
78
			assert.equal(service.toBackupResource(backupResource).fsPath, expectedPath);
D
Daniel Imms 已提交
79
		});
80

D
Daniel Imms 已提交
81 82 83 84
		test('should get the correct backup path for untitled files', () => {
			// Format should be: <backupHome>/<workspaceHash>/<scheme>/<filePath>
			const backupResource = Uri.from({ scheme: 'untitled', path: 'Untitled-1' });
			const workspaceHash = crypto.createHash('md5').update(workspaceResource.fsPath).digest('hex');
85
			const filePathHash = crypto.createHash('md5').update(backupResource.fsPath).digest('hex');
D
Daniel Imms 已提交
86
			const expectedPath = Uri.file(path.join(backupHome, workspaceHash, 'untitled', filePathHash)).fsPath;
87
			assert.equal(service.toBackupResource(backupResource).fsPath, expectedPath);
D
Daniel Imms 已提交
88
		});
89 90
	});

91
	suite('loadBackupResource', () => {
D
Daniel Imms 已提交
92 93 94 95
		test('should return whether a backup resource exists', done => {
			pfs.mkdirp(path.dirname(fooBackupPath)).then(() => {
				fs.writeFileSync(fooBackupPath, 'foo');
				service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath);
96 97 98 99 100 101 102 103 104 105
				service.loadBackupResource(fooFile).then(resource => {
					assert.ok(resource);
					assert.equal(path.basename(resource.fsPath), path.basename(fooBackupPath));
					return service.hasBackups().then(hasBackups => {
						assert.ok(hasBackups);
						done();
					});
				});
			});
		});
D
Daniel Imms 已提交
106
	});
107

D
Daniel Imms 已提交
108 109 110 111 112 113
	suite('backupResource', () => {
		test('text file', function (done: () => void) {
			service.backupResource(fooFile, 'test').then(() => {
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1);
				assert.equal(fs.existsSync(fooBackupPath), true);
				assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\ntest`);
114 115 116 117
				done();
			});
		});

D
Daniel Imms 已提交
118 119 120 121 122
		test('untitled file', function (done: () => void) {
			service.backupResource(untitledFile, 'test').then(() => {
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1);
				assert.equal(fs.existsSync(untitledBackupPath), true);
				assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\ntest`);
123 124 125
				done();
			});
		});
126 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

		test('text file (ITextSnapshot)', function (done: () => void) {
			const model = TextModel.createFromString('test');

			service.backupResource(fooFile, model.createSnapshot()).then(() => {
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1);
				assert.equal(fs.existsSync(fooBackupPath), true);
				assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\ntest`);
				model.dispose();
				done();
			});
		});

		test('untitled file (ITextSnapshot)', function (done: () => void) {
			const model = TextModel.createFromString('test');

			service.backupResource(untitledFile, model.createSnapshot()).then(() => {
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1);
				assert.equal(fs.existsSync(untitledBackupPath), true);
				assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\ntest`);
				model.dispose();
				done();
			});
		});

		test('text file (large file, ITextSnapshot)', function (done: () => void) {
B
Benjamin Pasero 已提交
152
			const largeString = (new Array(10 * 1024)).join('Large String\n');
153 154 155 156 157 158 159 160 161 162 163 164
			const model = TextModel.createFromString(largeString);

			service.backupResource(fooFile, model.createSnapshot()).then(() => {
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1);
				assert.equal(fs.existsSync(fooBackupPath), true);
				assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\n${largeString}`);
				model.dispose();
				done();
			});
		});

		test('untitled file (large file, ITextSnapshot)', function (done: () => void) {
B
Benjamin Pasero 已提交
165
			const largeString = (new Array(10 * 1024)).join('Large String\n');
166 167 168 169 170 171 172 173 174 175
			const model = TextModel.createFromString(largeString);

			service.backupResource(untitledFile, model.createSnapshot()).then(() => {
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1);
				assert.equal(fs.existsSync(untitledBackupPath), true);
				assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\n${largeString}`);
				model.dispose();
				done();
			});
		});
176 177
	});

D
Daniel Imms 已提交
178 179 180 181 182
	suite('discardResourceBackup', () => {
		test('text file', function (done: () => void) {
			service.backupResource(fooFile, 'test').then(() => {
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1);
				service.discardResourceBackup(fooFile).then(() => {
183
					assert.equal(fs.existsSync(fooBackupPath), false);
D
Daniel Imms 已提交
184
					assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 0);
185 186 187 188 189
					done();
				});
			});
		});

D
Daniel Imms 已提交
190 191 192 193 194 195 196 197
		test('untitled file', function (done: () => void) {
			service.backupResource(untitledFile, 'test').then(() => {
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1);
				service.discardResourceBackup(untitledFile).then(() => {
					assert.equal(fs.existsSync(untitledBackupPath), false);
					assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 0);
					done();
				});
198 199 200
			});
		});
	});
B
Benjamin Pasero 已提交
201

D
Daniel Imms 已提交
202 203 204 205 206 207 208 209 210 211
	suite('discardAllWorkspaceBackups', () => {
		test('text file', function (done: () => void) {
			service.backupResource(fooFile, 'test').then(() => {
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1);
				service.backupResource(barFile, 'test').then(() => {
					assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 2);
					service.discardAllWorkspaceBackups().then(() => {
						assert.equal(fs.existsSync(fooBackupPath), false);
						assert.equal(fs.existsSync(barBackupPath), false);
						assert.equal(fs.existsSync(path.join(workspaceBackupPath, 'file')), false);
D
Daniel Imms 已提交
212 213 214 215 216 217
						done();
					});
				});
			});
		});

D
Daniel Imms 已提交
218 219 220 221 222 223 224 225
		test('untitled file', function (done: () => void) {
			service.backupResource(untitledFile, 'test').then(() => {
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1);
				service.discardAllWorkspaceBackups().then(() => {
					assert.equal(fs.existsSync(untitledBackupPath), false);
					assert.equal(fs.existsSync(path.join(workspaceBackupPath, 'untitled')), false);
					done();
				});
226 227
			});
		});
228 229 230 231 232 233 234 235 236

		test('should disable further backups', function (done: () => void) {
			service.discardAllWorkspaceBackups().then(() => {
				service.backupResource(untitledFile, 'test').then(() => {
					assert.equal(fs.existsSync(workspaceBackupPath), false);
					done();
				});
			});
		});
237 238
	});

D
Daniel Imms 已提交
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
	suite('getWorkspaceFileBackups', () => {
		test('("file") - text file', done => {
			service.backupResource(fooFile, `test`).then(() => {
				service.getWorkspaceFileBackups().then(textFiles => {
					assert.deepEqual(textFiles.map(f => f.fsPath), [fooFile.fsPath]);
					service.backupResource(barFile, `test`).then(() => {
						service.getWorkspaceFileBackups().then(textFiles => {
							assert.deepEqual(textFiles.map(f => f.fsPath), [fooFile.fsPath, barFile.fsPath]);
							done();
						});
					});
				});
			});
		});

		test('("file") - untitled file', done => {
			service.backupResource(untitledFile, `test`).then(() => {
				service.getWorkspaceFileBackups().then(textFiles => {
					assert.deepEqual(textFiles.map(f => f.fsPath), [untitledFile.fsPath]);
					done();
				});
			});
		});

		test('("untitled") - untitled file', done => {
			service.backupResource(untitledFile, `test`).then(() => {
				service.getWorkspaceFileBackups().then(textFiles => {
					assert.deepEqual(textFiles.map(f => f.fsPath), ['Untitled-1']);
					done();
				});
269 270 271 272
			});
		});
	});

273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
	test('resolveBackupContent', () => {
		test('should restore the original contents (untitled file)', () => {
			const contents = 'test\nand more stuff';
			service.backupResource(untitledFile, contents).then(() => {
				service.resolveBackupContent(service.toBackupResource(untitledFile)).then(factory => {
					assert.equal(contents, snapshotToString(factory.create(platform.isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(true)));
				});
			});
		});

		test('should restore the original contents (text file)', () => {
			const contents = [
				'Lorem ipsum ',
				'dolor öäü sit amet ',
				'consectetur ',
				'adipiscing ßß elit',
			].join('');

			service.backupResource(fooFile, contents).then(() => {
				service.resolveBackupContent(service.toBackupResource(untitledFile)).then(factory => {
					assert.equal(contents, snapshotToString(factory.create(platform.isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(true)));
				});
			});
D
Daniel Imms 已提交
296
		});
D
Daniel Imms 已提交
297
	});
D
Daniel Imms 已提交
298
});
D
Daniel Imms 已提交
299

D
Daniel Imms 已提交
300 301
suite('BackupFilesModel', () => {
	test('simple', () => {
B
Benjamin Pasero 已提交
302
		const model = new BackupFilesModel();
B
Benjamin Pasero 已提交
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347

		const resource1 = Uri.file('test.html');

		assert.equal(model.has(resource1), false);

		model.add(resource1);

		assert.equal(model.has(resource1), true);
		assert.equal(model.has(resource1, 0), true);
		assert.equal(model.has(resource1, 1), false);

		model.remove(resource1);

		assert.equal(model.has(resource1), false);

		model.add(resource1);

		assert.equal(model.has(resource1), true);
		assert.equal(model.has(resource1, 0), true);
		assert.equal(model.has(resource1, 1), false);

		model.clear();

		assert.equal(model.has(resource1), false);

		model.add(resource1, 1);

		assert.equal(model.has(resource1), true);
		assert.equal(model.has(resource1, 0), false);
		assert.equal(model.has(resource1, 1), true);

		const resource2 = Uri.file('test1.html');
		const resource3 = Uri.file('test2.html');
		const resource4 = Uri.file('test3.html');

		model.add(resource2);
		model.add(resource3);
		model.add(resource4);

		assert.equal(model.has(resource1), true);
		assert.equal(model.has(resource2), true);
		assert.equal(model.has(resource3), true);
		assert.equal(model.has(resource4), true);
	});

D
Daniel Imms 已提交
348
	test('resolve', (done) => {
B
Benjamin Pasero 已提交
349 350 351
		pfs.mkdirp(path.dirname(fooBackupPath)).then(() => {
			fs.writeFileSync(fooBackupPath, 'foo');

B
Benjamin Pasero 已提交
352
			const model = new BackupFilesModel();
B
Benjamin Pasero 已提交
353 354 355 356 357 358 359 360

			model.resolve(workspaceBackupPath).then(model => {
				assert.equal(model.has(Uri.file(fooBackupPath)), true);

				done();
			});
		});
	});
361

D
Daniel Imms 已提交
362
	test('get', () => {
363 364
		const model = new BackupFilesModel();

365
		assert.deepEqual(model.get(), []);
366

D
Daniel Imms 已提交
367 368 369
		const file1 = Uri.file('/root/file/foo.html');
		const file2 = Uri.file('/root/file/bar.html');
		const untitled = Uri.file('/root/untitled/bar.html');
370

D
Daniel Imms 已提交
371 372 373 374
		model.add(file1);
		model.add(file2);
		model.add(untitled);

375
		assert.deepEqual(model.get().map(f => f.fsPath), [file1.fsPath, file2.fsPath, untitled.fsPath]);
376
	});
377
});