backupFileService.test.ts 15.0 KB
Newer Older
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  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';
D
Daniel Imms 已提交
7
import * as platform from 'vs/base/common/platform';
8 9
import * as os from 'os';
import * as fs from 'fs';
10
import * as path from 'vs/base/common/path';
11
import * as pfs from 'vs/base/node/pfs';
12
import { URI as Uri } from 'vs/base/common/uri';
13
import { BackupFileService, BackupFilesModel, hashPath } from 'vs/workbench/services/backup/node/backupFileService';
14
import { FileService } from 'vs/workbench/services/files/electron-browser/fileService';
15
import { TextModel, createTextBufferFactory } from 'vs/editor/common/model/textModel';
16 17
import { TestContextService, TestTextResourceConfigurationService, TestLifecycleService, TestEnvironmentService, TestStorageService } from 'vs/workbench/test/workbenchTestServices';
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
18
import { TestNotificationService } from 'vs/platform/notification/test/common/testNotificationService';
19
import { Workspace, toWorkspaceFolders } from 'vs/platform/workspace/common/workspace';
B
Benjamin Pasero 已提交
20
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
21 22
import { DefaultEndOfLine } from 'vs/editor/common/model';
import { snapshotToString } from 'vs/platform/files/common/files';
23
import { Schemas } from 'vs/base/common/network';
24

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

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

38 39
class TestBackupFileService extends BackupFileService {
	constructor(workspace: Uri, backupHome: string, workspacesJsonPath: string) {
I
isidor 已提交
40
		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 });
41

42
		super(workspaceBackupPath, fileService);
43 44
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

D
Daniel Imms 已提交
282 283
suite('BackupFilesModel', () => {
	test('simple', () => {
B
Benjamin Pasero 已提交
284
		const model = new BackupFilesModel();
B
Benjamin Pasero 已提交
285 286 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

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

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

B
Benjamin Pasero 已提交
334
			const model = new BackupFilesModel();
B
Benjamin Pasero 已提交
335

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

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

345
		assert.deepEqual(model.get(), []);
346

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

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

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