backupMainService.test.ts 25.8 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*---------------------------------------------------------------------------------------------
 *  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';
import * as platform from 'vs/base/common/platform';
10 11 12 13
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import * as pfs from 'vs/base/node/pfs';
14
import Uri from 'vs/base/common/uri';
15 16
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { parseArgs } from 'vs/platform/environment/node/argv';
D
Daniel Imms 已提交
17
import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService';
18
import { IBackupWorkspacesFormat } from 'vs/platform/backup/common/backup';
19 20
import { HotExitConfiguration } from 'vs/platform/files/common/files';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
21
import { ConsoleLogMainService } from 'vs/platform/log/common/log';
B
Benjamin Pasero 已提交
22 23
import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { createHash } from 'crypto';
B
Benjamin Pasero 已提交
24
import { getRandomTestPath } from 'vs/workbench/test/workbenchTestServices';
25
import { Schemas } from 'vs/base/common/network';
26

27
suite('BackupMainService', () => {
B
Benjamin Pasero 已提交
28
	const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backupservice');
29 30
	const backupHome = path.join(parentDir, 'Backups');
	const backupWorkspacesPath = path.join(backupHome, 'workspaces.json');
31

32
	const environmentService = new EnvironmentService(parseArgs(process.argv), process.execPath);
33

34
	class TestBackupMainService extends BackupMainService {
35

36
		constructor(backupHome: string, backupWorkspacesPath: string, configService: TestConfigurationService) {
S
Sandeep Somavarapu 已提交
37
			super(environmentService, configService, new ConsoleLogMainService());
38

39 40
			this.backupHome = backupHome;
			this.workspacesJsonPath = backupWorkspacesPath;
41

42 43 44
			// Force a reload with the new paths
			this.loadSync();
		}
45

46 47 48
		public get backupsData(): IBackupWorkspacesFormat {
			return this.backups;
		}
D
Daniel Imms 已提交
49

50 51 52
		public removeBackupPathSync(workspaceIdentifier: string | IWorkspaceIdentifier, target: (string | IWorkspaceIdentifier)[]): void {
			return super.removeBackupPathSync(workspaceIdentifier, target);
		}
53

54 55 56
		public loadSync(): void {
			super.loadSync();
		}
57

58 59 60
		public dedupeBackups(backups: IBackupWorkspacesFormat): IBackupWorkspacesFormat {
			return super.dedupeBackups(backups);
		}
61

62 63 64
		public toBackupPath(workspacePath: string): string {
			return path.join(this.backupHome, super.getFolderHash(workspacePath));
		}
65

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
		public getFolderHash(folderPath: string): string {
			return super.getFolderHash(folderPath);
		}
	}

	function toWorkspace(path: string): IWorkspaceIdentifier {
		return {
			id: createHash('md5').update(sanitizePath(path)).digest('hex'),
			configPath: path
		};
	}

	function sanitizePath(p: string): string {
		return platform.isLinux ? p : p.toLowerCase();
	}
81 82 83 84

	const fooFile = Uri.file(platform.isWindows ? 'C:\\foo' : '/foo');
	const barFile = Uri.file(platform.isWindows ? 'C:\\bar' : '/bar');

85
	let service: TestBackupMainService;
86
	let configService: TestConfigurationService;
87

88
	setup(() => {
89 90
		configService = new TestConfigurationService();
		service = new TestBackupMainService(backupHome, backupWorkspacesPath, configService);
91 92

		// Delete any existing backups completely and then re-create it.
93 94
		return pfs.del(backupHome, os.tmpdir()).then(() => {
			return pfs.mkdirp(backupHome);
95 96 97
		});
	});

98 99
	teardown(() => {
		return pfs.del(backupHome, os.tmpdir());
100 101
	});

B
Benjamin Pasero 已提交
102 103
	test('service validates backup workspaces on startup and cleans up (folder workspaces)', function () {
		this.timeout(1000 * 10); // increase timeout for this test
104

105
		// 1) backup workspace path does not exist
B
Benjamin Pasero 已提交
106 107
		service.registerFolderBackupSync(fooFile.fsPath);
		service.registerFolderBackupSync(barFile.fsPath);
108
		service.loadSync();
109
		assert.deepEqual(service.getFolderBackupPaths(), []);
110 111 112 113

		// 2) backup workspace path exists with empty contents within
		fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
		fs.mkdirSync(service.toBackupPath(barFile.fsPath));
B
Benjamin Pasero 已提交
114 115
		service.registerFolderBackupSync(fooFile.fsPath);
		service.registerFolderBackupSync(barFile.fsPath);
116
		service.loadSync();
117
		assert.deepEqual(service.getFolderBackupPaths(), []);
B
Benjamin Pasero 已提交
118 119
		assert.ok(!fs.existsSync(service.toBackupPath(fooFile.fsPath)));
		assert.ok(!fs.existsSync(service.toBackupPath(barFile.fsPath)));
120 121 122 123

		// 3) backup workspace path exists with empty folders within
		fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
		fs.mkdirSync(service.toBackupPath(barFile.fsPath));
124 125
		fs.mkdirSync(path.join(service.toBackupPath(fooFile.fsPath), Schemas.file));
		fs.mkdirSync(path.join(service.toBackupPath(barFile.fsPath), Schemas.untitled));
B
Benjamin Pasero 已提交
126 127
		service.registerFolderBackupSync(fooFile.fsPath);
		service.registerFolderBackupSync(barFile.fsPath);
128
		service.loadSync();
129
		assert.deepEqual(service.getFolderBackupPaths(), []);
B
Benjamin Pasero 已提交
130 131
		assert.ok(!fs.existsSync(service.toBackupPath(fooFile.fsPath)));
		assert.ok(!fs.existsSync(service.toBackupPath(barFile.fsPath)));
132

133 134
		// 4) backup workspace path points to a workspace that no longer exists
		// so it should convert the backup worspace to an empty workspace backup
135
		const fileBackups = path.join(service.toBackupPath(fooFile.fsPath), Schemas.file);
136 137 138
		fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
		fs.mkdirSync(service.toBackupPath(barFile.fsPath));
		fs.mkdirSync(fileBackups);
B
Benjamin Pasero 已提交
139
		service.registerFolderBackupSync(fooFile.fsPath);
140 141 142 143 144 145 146 147
		assert.equal(service.getFolderBackupPaths().length, 1);
		assert.equal(service.getEmptyWindowBackupPaths().length, 0);
		fs.writeFileSync(path.join(fileBackups, 'backup.txt'), '');
		service.loadSync();
		assert.equal(service.getFolderBackupPaths().length, 0);
		assert.equal(service.getEmptyWindowBackupPaths().length, 1);
	});

B
Benjamin Pasero 已提交
148 149
	test('service validates backup workspaces on startup and cleans up (root workspaces)', function () {
		this.timeout(1000 * 10); // increase timeout for this test
150 151

		// 1) backup workspace path does not exist
152 153
		service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
		service.registerWorkspaceBackupSync(toWorkspace(barFile.fsPath));
154
		service.loadSync();
155
		assert.deepEqual(service.getWorkspaceBackups(), []);
156 157 158 159

		// 2) backup workspace path exists with empty contents within
		fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
		fs.mkdirSync(service.toBackupPath(barFile.fsPath));
160 161
		service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
		service.registerWorkspaceBackupSync(toWorkspace(barFile.fsPath));
162
		service.loadSync();
163
		assert.deepEqual(service.getWorkspaceBackups(), []);
B
Benjamin Pasero 已提交
164 165
		assert.ok(!fs.existsSync(service.toBackupPath(fooFile.fsPath)));
		assert.ok(!fs.existsSync(service.toBackupPath(barFile.fsPath)));
166 167 168 169

		// 3) backup workspace path exists with empty folders within
		fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
		fs.mkdirSync(service.toBackupPath(barFile.fsPath));
170 171
		fs.mkdirSync(path.join(service.toBackupPath(fooFile.fsPath), Schemas.file));
		fs.mkdirSync(path.join(service.toBackupPath(barFile.fsPath), Schemas.untitled));
172 173
		service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
		service.registerWorkspaceBackupSync(toWorkspace(barFile.fsPath));
174
		service.loadSync();
175
		assert.deepEqual(service.getWorkspaceBackups(), []);
B
Benjamin Pasero 已提交
176 177
		assert.ok(!fs.existsSync(service.toBackupPath(fooFile.fsPath)));
		assert.ok(!fs.existsSync(service.toBackupPath(barFile.fsPath)));
178 179 180

		// 4) backup workspace path points to a workspace that no longer exists
		// so it should convert the backup worspace to an empty workspace backup
181
		const fileBackups = path.join(service.toBackupPath(fooFile.fsPath), Schemas.file);
182 183 184
		fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
		fs.mkdirSync(service.toBackupPath(barFile.fsPath));
		fs.mkdirSync(fileBackups);
185 186
		service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
		assert.equal(service.getWorkspaceBackups().length, 1);
187
		assert.equal(service.getEmptyWindowBackupPaths().length, 0);
188 189
		fs.writeFileSync(path.join(fileBackups, 'backup.txt'), '');
		service.loadSync();
190
		assert.equal(service.getWorkspaceBackups().length, 0);
191
		assert.equal(service.getEmptyWindowBackupPaths().length, 1);
192 193
	});

194
	test('service supports to migrate backup data from another location', () => {
195 196 197 198 199 200 201 202 203 204 205
		const backupPathToMigrate = service.toBackupPath(fooFile.fsPath);
		fs.mkdirSync(backupPathToMigrate);
		fs.writeFileSync(path.join(backupPathToMigrate, 'backup.txt'), 'Some Data');
		service.registerFolderBackupSync(backupPathToMigrate);

		const workspaceBackupPath = service.registerWorkspaceBackupSync(toWorkspace(barFile.fsPath), backupPathToMigrate);

		assert.ok(fs.existsSync(workspaceBackupPath));
		assert.ok(fs.existsSync(path.join(workspaceBackupPath, 'backup.txt')));
		assert.ok(!fs.existsSync(backupPathToMigrate));

206 207 208 209
		const emptyBackups = service.getEmptyWindowBackupPaths();
		assert.equal(0, emptyBackups.length);
	});

210
	test('service backup migration makes sure to preserve existing backups', () => {
211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
		const backupPathToMigrate = service.toBackupPath(fooFile.fsPath);
		fs.mkdirSync(backupPathToMigrate);
		fs.writeFileSync(path.join(backupPathToMigrate, 'backup.txt'), 'Some Data');
		service.registerFolderBackupSync(backupPathToMigrate);

		const backupPathToPreserve = service.toBackupPath(barFile.fsPath);
		fs.mkdirSync(backupPathToPreserve);
		fs.writeFileSync(path.join(backupPathToPreserve, 'backup.txt'), 'Some Data');
		service.registerFolderBackupSync(backupPathToPreserve);

		const workspaceBackupPath = service.registerWorkspaceBackupSync(toWorkspace(barFile.fsPath), backupPathToMigrate);

		assert.ok(fs.existsSync(workspaceBackupPath));
		assert.ok(fs.existsSync(path.join(workspaceBackupPath, 'backup.txt')));
		assert.ok(!fs.existsSync(backupPathToMigrate));

		const emptyBackups = service.getEmptyWindowBackupPaths();
		assert.equal(1, emptyBackups.length);
		assert.equal(1, fs.readdirSync(path.join(backupHome, emptyBackups[0])).length);
230 231
	});

232
	suite('loadSync', () => {
233 234 235 236 237 238 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 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
		test('getFolderBackupPaths() should return [] when workspaces.json doesn\'t exist', () => {
			assert.deepEqual(service.getFolderBackupPaths(), []);
		});

		test('getFolderBackupPaths() should return [] when workspaces.json is not properly formed JSON', () => {
			fs.writeFileSync(backupWorkspacesPath, '');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
			fs.writeFileSync(backupWorkspacesPath, '{]');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
			fs.writeFileSync(backupWorkspacesPath, 'foo');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
		});

		test('getFolderBackupPaths() should return [] when folderWorkspaces in workspaces.json is absent', () => {
			fs.writeFileSync(backupWorkspacesPath, '{}');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
		});

		test('getFolderBackupPaths() should return [] when folderWorkspaces in workspaces.json is not a string array', () => {
			fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":{}}');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
			fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":{"foo": ["bar"]}}');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
			fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":{"foo": []}}');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
			fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":{"foo": "bar"}}');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
			fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":"foo"}');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
			fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":1}');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
		});

		test('getFolderBackupPaths() should return [] when files.hotExit = "onExitAndWindowClose"', () => {
			service.registerFolderBackupSync(fooFile.fsPath.toUpperCase());
			assert.deepEqual(service.getFolderBackupPaths(), [fooFile.fsPath.toUpperCase()]);
			configService.setUserConfiguration('files.hotExit', HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE);
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
		});

284 285
		test('getWorkspaceBackups() should return [] when workspaces.json doesn\'t exist', () => {
			assert.deepEqual(service.getWorkspaceBackups(), []);
286
		});
D
Daniel Imms 已提交
287

288
		test('getWorkspaceBackups() should return [] when workspaces.json is not properly formed JSON', () => {
289 290
			fs.writeFileSync(backupWorkspacesPath, '');
			service.loadSync();
291
			assert.deepEqual(service.getWorkspaceBackups(), []);
292 293
			fs.writeFileSync(backupWorkspacesPath, '{]');
			service.loadSync();
294
			assert.deepEqual(service.getWorkspaceBackups(), []);
295 296
			fs.writeFileSync(backupWorkspacesPath, 'foo');
			service.loadSync();
297
			assert.deepEqual(service.getWorkspaceBackups(), []);
298
		});
D
Daniel Imms 已提交
299

300
		test('getWorkspaceBackups() should return [] when folderWorkspaces in workspaces.json is absent', () => {
301 302
			fs.writeFileSync(backupWorkspacesPath, '{}');
			service.loadSync();
303
			assert.deepEqual(service.getWorkspaceBackups(), []);
304 305
		});

306
		test('getWorkspaceBackups() should return [] when rootWorkspaces in workspaces.json is not a object array', () => {
307
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{}}');
308
			service.loadSync();
309
			assert.deepEqual(service.getWorkspaceBackups(), []);
310
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{"foo": ["bar"]}}');
311
			service.loadSync();
312
			assert.deepEqual(service.getWorkspaceBackups(), []);
313
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{"foo": []}}');
314
			service.loadSync();
315
			assert.deepEqual(service.getWorkspaceBackups(), []);
316
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{"foo": "bar"}}');
317
			service.loadSync();
318
			assert.deepEqual(service.getWorkspaceBackups(), []);
319
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":"foo"}');
320
			service.loadSync();
321
			assert.deepEqual(service.getWorkspaceBackups(), []);
322
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":1}');
323
			service.loadSync();
324
			assert.deepEqual(service.getWorkspaceBackups(), []);
325
		});
D
Daniel Imms 已提交
326

327 328 329 330
		test('getWorkspaceBackups() should return [] when files.hotExit = "onExitAndWindowClose"', () => {
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath.toUpperCase()));
			assert.equal(service.getWorkspaceBackups().length, 1);
			assert.deepEqual(service.getWorkspaceBackups().map(r => r.configPath), [fooFile.fsPath.toUpperCase()]);
331 332
			configService.setUserConfiguration('files.hotExit', HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE);
			service.loadSync();
333
			assert.deepEqual(service.getWorkspaceBackups(), []);
334 335
		});

336
		test('getEmptyWorkspaceBackupPaths() should return [] when workspaces.json doesn\'t exist', () => {
337
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
338 339
		});

340
		test('getEmptyWorkspaceBackupPaths() should return [] when workspaces.json is not properly formed JSON', () => {
341 342
			fs.writeFileSync(backupWorkspacesPath, '');
			service.loadSync();
343
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
344 345
			fs.writeFileSync(backupWorkspacesPath, '{]');
			service.loadSync();
346
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
347 348
			fs.writeFileSync(backupWorkspacesPath, 'foo');
			service.loadSync();
349
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
350 351
		});

352
		test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is absent', () => {
353 354
			fs.writeFileSync(backupWorkspacesPath, '{}');
			service.loadSync();
355
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
356 357
		});

C
Christof Marti 已提交
358
		test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is not a string array', function () {
C
Christof Marti 已提交
359
			this.timeout(5000);
360 361
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{}}');
			service.loadSync();
362
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
363 364
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": ["bar"]}}');
			service.loadSync();
365
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
366 367
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": []}}');
			service.loadSync();
368
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
369 370
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": "bar"}}');
			service.loadSync();
371
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
372 373
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":"foo"}');
			service.loadSync();
374
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
375 376
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":1}');
			service.loadSync();
377
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
378
		});
D
Daniel Imms 已提交
379
	});
380

381
	suite('dedupeFolderWorkspaces', () => {
382
		test('should ignore duplicates on Windows and Mac (folder workspace)', () => {
383 384 385 386 387
			// Skip test on Linux
			if (platform.isLinux) {
				return;
			}

D
Daniel Imms 已提交
388
			const backups: IBackupWorkspacesFormat = {
389
				rootWorkspaces: [],
390
				folderWorkspaces: platform.isWindows ? ['c:\\FOO', 'C:\\FOO', 'c:\\foo'] : ['/FOO', '/foo'],
D
Daniel Imms 已提交
391 392 393
				emptyWorkspaces: []
			};

394
			service.dedupeBackups(backups);
395

396
			assert.equal(backups.folderWorkspaces.length, 1);
397
			if (platform.isWindows) {
398
				assert.deepEqual(backups.folderWorkspaces, ['c:\\FOO'], 'should return the first duplicated entry');
D
Daniel Imms 已提交
399
			} else {
400
				assert.deepEqual(backups.folderWorkspaces, ['/FOO'], 'should return the first duplicated entry');
401 402
			}
		});
403 404 405 406 407 408 409 410

		test('should ignore duplicates on Windows and Mac (root workspace)', () => {
			// Skip test on Linux
			if (platform.isLinux) {
				return;
			}

			const backups: IBackupWorkspacesFormat = {
411
				rootWorkspaces: platform.isWindows ? [toWorkspace('c:\\FOO'), toWorkspace('C:\\FOO'), toWorkspace('c:\\foo')] : [toWorkspace('/FOO'), toWorkspace('/foo')],
412 413 414 415 416 417 418 419
				folderWorkspaces: [],
				emptyWorkspaces: []
			};

			service.dedupeBackups(backups);

			assert.equal(backups.rootWorkspaces.length, 1);
			if (platform.isWindows) {
420
				assert.deepEqual(backups.rootWorkspaces.map(r => r.configPath), ['c:\\FOO'], 'should return the first duplicated entry');
421
			} else {
422
				assert.deepEqual(backups.rootWorkspaces.map(r => r.configPath), ['/FOO'], 'should return the first duplicated entry');
423 424
			}
		});
D
Daniel Imms 已提交
425 426
	});

427
	suite('registerWindowForBackups', () => {
428
		test('should persist paths to workspaces.json (folder workspace)', () => {
B
Benjamin Pasero 已提交
429 430
			service.registerFolderBackupSync(fooFile.fsPath);
			service.registerFolderBackupSync(barFile.fsPath);
431
			assert.deepEqual(service.getFolderBackupPaths(), [fooFile.fsPath, barFile.fsPath]);
432
			return pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
433 434
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.folderWorkspaces, [fooFile.fsPath, barFile.fsPath]);
435 436
			});
		});
D
Daniel Imms 已提交
437

438
		test('should persist paths to workspaces.json (root workspace)', () => {
439 440 441 442 443 444 445 446 447
			const ws1 = toWorkspace(fooFile.fsPath);
			service.registerWorkspaceBackupSync(ws1);
			const ws2 = toWorkspace(barFile.fsPath);
			service.registerWorkspaceBackupSync(ws2);

			assert.deepEqual(service.getWorkspaceBackups().map(b => b.configPath), [fooFile.fsPath, barFile.fsPath]);
			assert.equal(ws1.id, service.getWorkspaceBackups()[0].id);
			assert.equal(ws2.id, service.getWorkspaceBackups()[1].id);

448
			return pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
449
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
450 451 452 453

				assert.deepEqual(json.rootWorkspaces.map(b => b.configPath), [fooFile.fsPath, barFile.fsPath]);
				assert.equal(ws1.id, json.rootWorkspaces[0].id);
				assert.equal(ws2.id, json.rootWorkspaces[1].id);
454 455 456
			});
		});

457
		test('should always store the workspace path in workspaces.json using the case given, regardless of whether the file system is case-sensitive (folder workspace)', () => {
B
Benjamin Pasero 已提交
458
			service.registerFolderBackupSync(fooFile.fsPath.toUpperCase());
459
			assert.deepEqual(service.getFolderBackupPaths(), [fooFile.fsPath.toUpperCase()]);
460
			return pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
D
Daniel Imms 已提交
461 462 463 464
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.folderWorkspaces, [fooFile.fsPath.toUpperCase()]);
			});
		});
465

466
		test('should always store the workspace path in workspaces.json using the case given, regardless of whether the file system is case-sensitive (root workspace)', () => {
467 468
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath.toUpperCase()));
			assert.deepEqual(service.getWorkspaceBackups().map(b => b.configPath), [fooFile.fsPath.toUpperCase()]);
469
			return pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
470
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
471
				assert.deepEqual(json.rootWorkspaces.map(b => b.configPath), [fooFile.fsPath.toUpperCase()]);
472 473
			});
		});
474 475
	});

476
	suite('removeBackupPathSync', () => {
477
		test('should remove folder workspaces from workspaces.json (folder workspace)', () => {
B
Benjamin Pasero 已提交
478 479
			service.registerFolderBackupSync(fooFile.fsPath);
			service.registerFolderBackupSync(barFile.fsPath);
480
			service.removeBackupPathSync(fooFile.fsPath, service.backupsData.folderWorkspaces);
481
			return pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
482 483
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.folderWorkspaces, [barFile.fsPath]);
484
				service.removeBackupPathSync(barFile.fsPath, service.backupsData.folderWorkspaces);
485
				return pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
486 487 488
					const json2 = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json2.folderWorkspaces, []);
				});
489 490
			});
		});
491

492
		test('should remove folder workspaces from workspaces.json (root workspace)', () => {
493 494 495 496 497
			const ws1 = toWorkspace(fooFile.fsPath);
			service.registerWorkspaceBackupSync(ws1);
			const ws2 = toWorkspace(barFile.fsPath);
			service.registerWorkspaceBackupSync(ws2);
			service.removeBackupPathSync(ws1, service.backupsData.rootWorkspaces);
498
			return pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
499
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
500 501
				assert.deepEqual(json.rootWorkspaces.map(r => r.configPath), [barFile.fsPath]);
				service.removeBackupPathSync(ws2, service.backupsData.rootWorkspaces);
502
				return pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
503 504 505 506 507 508
					const json2 = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json2.rootWorkspaces, []);
				});
			});
		});

509
		test('should remove empty workspaces from workspaces.json', () => {
B
Benjamin Pasero 已提交
510 511
			service.registerEmptyWindowBackupSync('foo');
			service.registerEmptyWindowBackupSync('bar');
512
			service.removeBackupPathSync('foo', service.backupsData.emptyWorkspaces);
513
			return pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
D
Daniel Imms 已提交
514 515
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.emptyWorkspaces, ['bar']);
516
				service.removeBackupPathSync('bar', service.backupsData.emptyWorkspaces);
517
				return pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
D
Daniel Imms 已提交
518 519 520 521 522 523
					const json2 = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json2.emptyWorkspaces, []);
				});
			});
		});

524
		test('should fail gracefully when removing a path that doesn\'t exist', () => {
525
			const workspacesJson: IBackupWorkspacesFormat = { rootWorkspaces: [], folderWorkspaces: [fooFile.fsPath], emptyWorkspaces: [] };
526
			return pfs.writeFile(backupWorkspacesPath, JSON.stringify(workspacesJson)).then(() => {
527 528
				service.removeBackupPathSync(barFile.fsPath, service.backupsData.folderWorkspaces);
				service.removeBackupPathSync('test', service.backupsData.emptyWorkspaces);
529
				return pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
530 531 532 533 534
					const json = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json.folderWorkspaces, [fooFile.fsPath]);
				});
			});
		});
535
	});
D
Daniel Imms 已提交
536

537
	suite('getWorkspaceHash', () => {
D
Daniel Imms 已提交
538
		test('should perform an md5 hash on the path', () => {
539
			assert.equal(service.getFolderHash('/foo'), '1effb2475fcfba4f9e8b8a1dbc8f3caf');
D
Daniel Imms 已提交
540 541
		});

542 543 544 545 546
		test('should ignore case on Windows and Mac', () => {
			// Skip test on Linux
			if (platform.isLinux) {
				return;
			}
D
Daniel Imms 已提交
547

548
			if (platform.isMacintosh) {
549
				assert.equal(service.getFolderHash('/foo'), service.getFolderHash('/FOO'));
550
			}
D
Daniel Imms 已提交
551

552
			if (platform.isWindows) {
553
				assert.equal(service.getFolderHash('c:\\foo'), service.getFolderHash('C:\\FOO'));
554 555
			}
		});
D
Daniel Imms 已提交
556
	});
557

558
	suite('mixed path casing', () => {
559
		test('should handle case insensitive paths properly (registerWindowForBackupsSync) (folder workspace)', () => {
B
Benjamin Pasero 已提交
560 561
			service.registerFolderBackupSync(fooFile.fsPath);
			service.registerFolderBackupSync(fooFile.fsPath.toUpperCase());
562

563 564 565 566 567 568 569
			if (platform.isLinux) {
				assert.equal(service.getFolderBackupPaths().length, 2);
			} else {
				assert.equal(service.getFolderBackupPaths().length, 1);
			}
		});

570
		test('should handle case insensitive paths properly (registerWindowForBackupsSync) (root workspace)', () => {
571 572
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath.toUpperCase()));
573

574
			if (platform.isLinux) {
575
				assert.equal(service.getWorkspaceBackups().length, 2);
576
			} else {
577
				assert.equal(service.getWorkspaceBackups().length, 1);
578 579 580
			}
		});

581
		test('should handle case insensitive paths properly (removeBackupPathSync) (folder workspace)', () => {
582 583

			// same case
B
Benjamin Pasero 已提交
584
			service.registerFolderBackupSync(fooFile.fsPath);
585 586
			service.removeBackupPathSync(fooFile.fsPath, service.backupsData.folderWorkspaces);
			assert.equal(service.getFolderBackupPaths().length, 0);
587 588

			// mixed case
B
Benjamin Pasero 已提交
589
			service.registerFolderBackupSync(fooFile.fsPath);
590 591 592 593 594 595 596 597
			service.removeBackupPathSync(fooFile.fsPath.toUpperCase(), service.backupsData.folderWorkspaces);

			if (platform.isLinux) {
				assert.equal(service.getFolderBackupPaths().length, 1);
			} else {
				assert.equal(service.getFolderBackupPaths().length, 0);
			}
		});
598
	});
599
});