backupFileService.test.ts 15.3 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 12 13 14
import * as crypto from 'crypto';
import * as os from 'os';
import * as fs from 'fs';
import * as path from 'path';
import * as pfs from 'vs/base/node/pfs';
15
import Uri from 'vs/base/common/uri';
B
Benjamin Pasero 已提交
16
import { BackupFileService, BackupFilesModel } from 'vs/workbench/services/backup/node/backupFileService';
17
import { FileService } from 'vs/workbench/services/files/electron-browser/fileService';
18
import { TextModel, createTextBufferFactory } from 'vs/editor/common/model/textModel';
19 20
import { TestContextService, TestTextResourceConfigurationService, getRandomTestPath, TestLifecycleService, TestEnvironmentService, TestStorageService } from 'vs/workbench/test/workbenchTestServices';
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
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
import { Schemas } from 'vs/base/common/network';
26

B
Benjamin Pasero 已提交
27
const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupfileservice');
D
Daniel Imms 已提交
28 29 30 31 32
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'));
33 34
const fooFile = Uri.file(platform.isWindows ? 'c:\\Foo' : '/Foo');
const barFile = Uri.file(platform.isWindows ? 'c:\\Bar' : '/Bar');
35
const untitledFile = Uri.from({ scheme: Schemas.untitled, path: 'Untitled-1' });
D
Daniel Imms 已提交
36 37
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'));
38
const untitledBackupPath = path.join(workspaceBackupPath, 'untitled', crypto.createHash('md5').update(untitledFile.fsPath).digest('hex'));
D
Daniel Imms 已提交
39

40 41
class TestBackupFileService extends BackupFileService {
	constructor(workspace: Uri, backupHome: string, workspacesJsonPath: string) {
I
isidor 已提交
42
		const fileService = new FileService(new TestContextService(new Workspace(workspace.fsPath, toWorkspaceFolders([{ path: workspace.fsPath }]))), TestEnvironmentService, new TestTextResourceConfigurationService(), new TestConfigurationService(), new TestLifecycleService(), new TestStorageService(), new TestNotificationService(), { disableWatcher: true });
43

44
		super(workspaceBackupPath, fileService);
45 46
	}

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

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

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

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

66 67
	teardown(() => {
		return pfs.del(backupHome, os.tmpdir());
68 69
	});

D
Daniel Imms 已提交
70 71 72 73 74 75 76
	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;
77
			assert.equal(service.toBackupResource(backupResource).fsPath, expectedPath);
D
Daniel Imms 已提交
78
		});
79

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

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

D
Daniel Imms 已提交
106
	suite('backupResource', () => {
107 108
		test('text file', function () {
			return service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
D
Daniel Imms 已提交
109 110 111
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1);
				assert.equal(fs.existsSync(fooBackupPath), true);
				assert.equal(fs.readFileSync(fooBackupPath), `${fooFile.toString()}\ntest`);
112 113 114
			});
		});

115 116
		test('untitled file', function () {
			return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
D
Daniel Imms 已提交
117 118 119
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1);
				assert.equal(fs.existsSync(untitledBackupPath), true);
				assert.equal(fs.readFileSync(untitledBackupPath), `${untitledFile.toString()}\ntest`);
120 121
			});
		});
122

123
		test('text file (ITextSnapshot)', function () {
124 125
			const model = TextModel.createFromString('test');

126
			return service.backupResource(fooFile, model.createSnapshot()).then(() => {
127 128 129 130 131 132 133
				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();
			});
		});

134
		test('untitled file (ITextSnapshot)', function () {
135 136
			const model = TextModel.createFromString('test');

137
			return service.backupResource(untitledFile, model.createSnapshot()).then(() => {
138 139 140 141 142 143 144
				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();
			});
		});

145
		test('text file (large file, ITextSnapshot)', function () {
B
Benjamin Pasero 已提交
146
			const largeString = (new Array(10 * 1024)).join('Large String\n');
147 148
			const model = TextModel.createFromString(largeString);

149
			return service.backupResource(fooFile, model.createSnapshot()).then(() => {
150 151 152 153 154 155 156
				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();
			});
		});

157
		test('untitled file (large file, ITextSnapshot)', function () {
B
Benjamin Pasero 已提交
158
			const largeString = (new Array(10 * 1024)).join('Large String\n');
159 160
			const model = TextModel.createFromString(largeString);

161
			return service.backupResource(untitledFile, model.createSnapshot()).then(() => {
162 163 164 165 166 167
				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();
			});
		});
168 169
	});

D
Daniel Imms 已提交
170
	suite('discardResourceBackup', () => {
171 172
		test('text file', function () {
			return service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
D
Daniel Imms 已提交
173
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1);
174
				return service.discardResourceBackup(fooFile).then(() => {
175
					assert.equal(fs.existsSync(fooBackupPath), false);
D
Daniel Imms 已提交
176
					assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 0);
177 178 179 180
				});
			});
		});

181 182
		test('untitled file', function () {
			return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
D
Daniel Imms 已提交
183
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1);
184
				return service.discardResourceBackup(untitledFile).then(() => {
D
Daniel Imms 已提交
185 186 187
					assert.equal(fs.existsSync(untitledBackupPath), false);
					assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 0);
				});
188 189 190
			});
		});
	});
B
Benjamin Pasero 已提交
191

D
Daniel Imms 已提交
192
	suite('discardAllWorkspaceBackups', () => {
193 194
		test('text file', function () {
			return service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
D
Daniel Imms 已提交
195
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 1);
196
				return service.backupResource(barFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
D
Daniel Imms 已提交
197
					assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'file')).length, 2);
198
					return service.discardAllWorkspaceBackups().then(() => {
D
Daniel Imms 已提交
199 200 201
						assert.equal(fs.existsSync(fooBackupPath), false);
						assert.equal(fs.existsSync(barBackupPath), false);
						assert.equal(fs.existsSync(path.join(workspaceBackupPath, 'file')), false);
D
Daniel Imms 已提交
202 203 204 205 206
					});
				});
			});
		});

207 208
		test('untitled file', function () {
			return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
D
Daniel Imms 已提交
209
				assert.equal(fs.readdirSync(path.join(workspaceBackupPath, 'untitled')).length, 1);
210
				return service.discardAllWorkspaceBackups().then(() => {
D
Daniel Imms 已提交
211 212 213
					assert.equal(fs.existsSync(untitledBackupPath), false);
					assert.equal(fs.existsSync(path.join(workspaceBackupPath, 'untitled')), false);
				});
214 215
			});
		});
216

217 218 219
		test('should disable further backups', function () {
			return service.discardAllWorkspaceBackups().then(() => {
				return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
220 221 222 223
					assert.equal(fs.existsSync(workspaceBackupPath), false);
				});
			});
		});
224 225
	});

D
Daniel Imms 已提交
226
	suite('getWorkspaceFileBackups', () => {
227 228 229
		test('("file") - text file', () => {
			return service.backupResource(fooFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
				return service.getWorkspaceFileBackups().then(textFiles => {
D
Daniel Imms 已提交
230
					assert.deepEqual(textFiles.map(f => f.fsPath), [fooFile.fsPath]);
231 232
					return service.backupResource(barFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
						return service.getWorkspaceFileBackups().then(textFiles => {
D
Daniel Imms 已提交
233 234 235 236 237 238 239
							assert.deepEqual(textFiles.map(f => f.fsPath), [fooFile.fsPath, barFile.fsPath]);
						});
					});
				});
			});
		});

240 241 242
		test('("file") - untitled file', () => {
			return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
				return service.getWorkspaceFileBackups().then(textFiles => {
D
Daniel Imms 已提交
243 244 245 246 247
					assert.deepEqual(textFiles.map(f => f.fsPath), [untitledFile.fsPath]);
				});
			});
		});

248 249 250
		test('("untitled") - untitled file', () => {
			return service.backupResource(untitledFile, createTextBufferFactory('test').create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
				return service.getWorkspaceFileBackups().then(textFiles => {
D
Daniel Imms 已提交
251 252
					assert.deepEqual(textFiles.map(f => f.fsPath), ['Untitled-1']);
				});
253 254 255 256
			});
		});
	});

257 258 259
	test('resolveBackupContent', () => {
		test('should restore the original contents (untitled file)', () => {
			const contents = 'test\nand more stuff';
260
			service.backupResource(untitledFile, createTextBufferFactory(contents).create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
261 262 263 264 265 266 267 268 269 270 271 272 273 274
				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('');

275
			service.backupResource(fooFile, createTextBufferFactory(contents).create(DefaultEndOfLine.LF).createSnapshot(false)).then(() => {
276 277 278 279
				service.resolveBackupContent(service.toBackupResource(untitledFile)).then(factory => {
					assert.equal(contents, snapshotToString(factory.create(platform.isWindows ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF).createSnapshot(true)));
				});
			});
D
Daniel Imms 已提交
280
		});
D
Daniel Imms 已提交
281
	});
D
Daniel Imms 已提交
282
});
D
Daniel Imms 已提交
283

D
Daniel Imms 已提交
284 285
suite('BackupFilesModel', () => {
	test('simple', () => {
B
Benjamin Pasero 已提交
286
		const model = new BackupFilesModel();
B
Benjamin Pasero 已提交
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 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

		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);
	});

332 333
	test('resolve', () => {
		return pfs.mkdirp(path.dirname(fooBackupPath)).then(() => {
B
Benjamin Pasero 已提交
334 335
			fs.writeFileSync(fooBackupPath, 'foo');

B
Benjamin Pasero 已提交
336
			const model = new BackupFilesModel();
B
Benjamin Pasero 已提交
337

338
			return model.resolve(workspaceBackupPath).then(model => {
B
Benjamin Pasero 已提交
339 340 341 342
				assert.equal(model.has(Uri.file(fooBackupPath)), true);
			});
		});
	});
343

D
Daniel Imms 已提交
344
	test('get', () => {
345 346
		const model = new BackupFilesModel();

347
		assert.deepEqual(model.get(), []);
348

D
Daniel Imms 已提交
349 350 351
		const file1 = Uri.file('/root/file/foo.html');
		const file2 = Uri.file('/root/file/bar.html');
		const untitled = Uri.file('/root/untitled/bar.html');
352

D
Daniel Imms 已提交
353 354 355 356
		model.add(file1);
		model.add(file2);
		model.add(untitled);

357
		assert.deepEqual(model.get().map(f => f.fsPath), [file1.fsPath, file2.fsPath, untitled.fsPath]);
358
	});
359
});