backupMainService.test.ts 25.9 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';
D
Daniel Imms 已提交
10
import fs = require('fs');
11 12 13 14 15
import os = require('os');
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';
16 17
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { parseArgs } from 'vs/platform/environment/node/argv';
D
Daniel Imms 已提交
18
import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService';
19
import { IBackupWorkspacesFormat } from 'vs/platform/backup/common/backup';
20 21
import { HotExitConfiguration } from 'vs/platform/files/common/files';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
22
import { ConsoleLogMainService } from 'vs/platform/log/common/log';
B
Benjamin Pasero 已提交
23 24
import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { createHash } from 'crypto';
B
Benjamin Pasero 已提交
25
import { getRandomTestPath } from 'vs/workbench/test/workbenchTestServices';
26
import { Schemas } from 'vs/base/common/network';
27

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

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

35
	class TestBackupMainService extends BackupMainService {
36

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

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

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

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

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

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

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

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

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
		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();
	}
82 83 84 85

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

86
	let service: TestBackupMainService;
87
	let configService: TestConfigurationService;
88 89

	setup(done => {
90 91
		configService = new TestConfigurationService();
		service = new TestBackupMainService(backupHome, backupWorkspacesPath, configService);
92 93 94 95

		// Delete any existing backups completely and then re-create it.
		extfs.del(backupHome, os.tmpdir(), () => {
			pfs.mkdirp(backupHome).then(() => {
D
Daniel Imms 已提交
96
				done();
97 98 99 100 101 102 103 104
			});
		});
	});

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

105
	test('service validates backup workspaces on startup and cleans up (folder workspaces)', done => {
106

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

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

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

135 136
		// 4) backup workspace path points to a workspace that no longer exists
		// so it should convert the backup worspace to an empty workspace backup
137
		const fileBackups = path.join(service.toBackupPath(fooFile.fsPath), Schemas.file);
138 139 140
		fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
		fs.mkdirSync(service.toBackupPath(barFile.fsPath));
		fs.mkdirSync(fileBackups);
B
Benjamin Pasero 已提交
141
		service.registerFolderBackupSync(fooFile.fsPath);
142 143 144 145 146 147 148 149 150 151 152 153 154
		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);

		done();
	});

	test('service validates backup workspaces on startup and cleans up (root workspaces)', done => {

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

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

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

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

196 197 198
		done();
	});

199 200 201 202 203 204 205 206 207 208 209 210
	test('service supports to migrate backup data from another location', done => {
		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));

211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
		const emptyBackups = service.getEmptyWindowBackupPaths();
		assert.equal(0, emptyBackups.length);

		done();
	});

	test('service backup migration makes sure to preserve existing backups', done => {
		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);

238 239 240
		done();
	});

241
	suite('loadSync', () => {
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 284 285 286 287 288 289 290 291 292
		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(), []);
		});

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

297
		test('getWorkspaceBackups() should return [] when workspaces.json is not properly formed JSON', () => {
298 299
			fs.writeFileSync(backupWorkspacesPath, '');
			service.loadSync();
300
			assert.deepEqual(service.getWorkspaceBackups(), []);
301 302
			fs.writeFileSync(backupWorkspacesPath, '{]');
			service.loadSync();
303
			assert.deepEqual(service.getWorkspaceBackups(), []);
304 305
			fs.writeFileSync(backupWorkspacesPath, 'foo');
			service.loadSync();
306
			assert.deepEqual(service.getWorkspaceBackups(), []);
307
		});
D
Daniel Imms 已提交
308

309
		test('getWorkspaceBackups() should return [] when folderWorkspaces in workspaces.json is absent', () => {
310 311
			fs.writeFileSync(backupWorkspacesPath, '{}');
			service.loadSync();
312
			assert.deepEqual(service.getWorkspaceBackups(), []);
313 314
		});

315
		test('getWorkspaceBackups() should return [] when rootWorkspaces in workspaces.json is not a object array', () => {
316
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{}}');
317
			service.loadSync();
318
			assert.deepEqual(service.getWorkspaceBackups(), []);
319
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{"foo": ["bar"]}}');
320
			service.loadSync();
321
			assert.deepEqual(service.getWorkspaceBackups(), []);
322
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{"foo": []}}');
323
			service.loadSync();
324
			assert.deepEqual(service.getWorkspaceBackups(), []);
325
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{"foo": "bar"}}');
326
			service.loadSync();
327
			assert.deepEqual(service.getWorkspaceBackups(), []);
328
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":"foo"}');
329
			service.loadSync();
330
			assert.deepEqual(service.getWorkspaceBackups(), []);
331
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":1}');
332
			service.loadSync();
333
			assert.deepEqual(service.getWorkspaceBackups(), []);
334
		});
D
Daniel Imms 已提交
335

336 337 338 339
		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()]);
340 341
			configService.setUserConfiguration('files.hotExit', HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE);
			service.loadSync();
342
			assert.deepEqual(service.getWorkspaceBackups(), []);
343 344
		});

345
		test('getEmptyWorkspaceBackupPaths() should return [] when workspaces.json doesn\'t exist', () => {
346
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
347 348
		});

349
		test('getEmptyWorkspaceBackupPaths() should return [] when workspaces.json is not properly formed JSON', () => {
350 351
			fs.writeFileSync(backupWorkspacesPath, '');
			service.loadSync();
352
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
353 354
			fs.writeFileSync(backupWorkspacesPath, '{]');
			service.loadSync();
355
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
356 357
			fs.writeFileSync(backupWorkspacesPath, 'foo');
			service.loadSync();
358
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
359 360
		});

361
		test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is absent', () => {
362 363
			fs.writeFileSync(backupWorkspacesPath, '{}');
			service.loadSync();
364
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
365 366
		});

C
Christof Marti 已提交
367
		test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is not a string array', function () {
C
Christof Marti 已提交
368
			this.timeout(5000);
369 370
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{}}');
			service.loadSync();
371
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
372 373
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": ["bar"]}}');
			service.loadSync();
374
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
375 376
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": []}}');
			service.loadSync();
377
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
378 379
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": "bar"}}');
			service.loadSync();
380
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
381 382
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":"foo"}');
			service.loadSync();
383
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
384 385
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":1}');
			service.loadSync();
386
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
387
		});
D
Daniel Imms 已提交
388
	});
389

390
	suite('dedupeFolderWorkspaces', () => {
391
		test('should ignore duplicates on Windows and Mac (folder workspace)', () => {
392 393 394 395 396
			// Skip test on Linux
			if (platform.isLinux) {
				return;
			}

D
Daniel Imms 已提交
397
			const backups: IBackupWorkspacesFormat = {
398
				rootWorkspaces: [],
399
				folderWorkspaces: platform.isWindows ? ['c:\\FOO', 'C:\\FOO', 'c:\\foo'] : ['/FOO', '/foo'],
D
Daniel Imms 已提交
400 401 402
				emptyWorkspaces: []
			};

403
			service.dedupeBackups(backups);
404

405
			assert.equal(backups.folderWorkspaces.length, 1);
406
			if (platform.isWindows) {
407
				assert.deepEqual(backups.folderWorkspaces, ['c:\\FOO'], 'should return the first duplicated entry');
D
Daniel Imms 已提交
408
			} else {
409
				assert.deepEqual(backups.folderWorkspaces, ['/FOO'], 'should return the first duplicated entry');
410 411
			}
		});
412 413 414 415 416 417 418 419

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

			const backups: IBackupWorkspacesFormat = {
420
				rootWorkspaces: platform.isWindows ? [toWorkspace('c:\\FOO'), toWorkspace('C:\\FOO'), toWorkspace('c:\\foo')] : [toWorkspace('/FOO'), toWorkspace('/foo')],
421 422 423 424 425 426 427 428
				folderWorkspaces: [],
				emptyWorkspaces: []
			};

			service.dedupeBackups(backups);

			assert.equal(backups.rootWorkspaces.length, 1);
			if (platform.isWindows) {
429
				assert.deepEqual(backups.rootWorkspaces.map(r => r.configPath), ['c:\\FOO'], 'should return the first duplicated entry');
430
			} else {
431
				assert.deepEqual(backups.rootWorkspaces.map(r => r.configPath), ['/FOO'], 'should return the first duplicated entry');
432 433
			}
		});
D
Daniel Imms 已提交
434 435
	});

436
	suite('registerWindowForBackups', () => {
437
		test('should persist paths to workspaces.json (folder workspace)', done => {
B
Benjamin Pasero 已提交
438 439
			service.registerFolderBackupSync(fooFile.fsPath);
			service.registerFolderBackupSync(barFile.fsPath);
440
			assert.deepEqual(service.getFolderBackupPaths(), [fooFile.fsPath, barFile.fsPath]);
441 442 443
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.folderWorkspaces, [fooFile.fsPath, barFile.fsPath]);
D
Daniel Imms 已提交
444
				done();
445 446
			});
		});
D
Daniel Imms 已提交
447

448
		test('should persist paths to workspaces.json (root workspace)', done => {
449 450 451 452 453 454 455 456 457
			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);

458 459
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
460 461 462 463 464

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

465 466 467 468 469
				done();
			});
		});

		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)', done => {
B
Benjamin Pasero 已提交
470
			service.registerFolderBackupSync(fooFile.fsPath.toUpperCase());
471
			assert.deepEqual(service.getFolderBackupPaths(), [fooFile.fsPath.toUpperCase()]);
D
Daniel Imms 已提交
472 473 474 475 476 477
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.folderWorkspaces, [fooFile.fsPath.toUpperCase()]);
				done();
			});
		});
478 479

		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)', done => {
480 481
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath.toUpperCase()));
			assert.deepEqual(service.getWorkspaceBackups().map(b => b.configPath), [fooFile.fsPath.toUpperCase()]);
482 483
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
484
				assert.deepEqual(json.rootWorkspaces.map(b => b.configPath), [fooFile.fsPath.toUpperCase()]);
485 486 487
				done();
			});
		});
488 489
	});

490
	suite('removeBackupPathSync', () => {
491
		test('should remove folder workspaces from workspaces.json (folder workspace)', done => {
B
Benjamin Pasero 已提交
492 493
			service.registerFolderBackupSync(fooFile.fsPath);
			service.registerFolderBackupSync(barFile.fsPath);
494
			service.removeBackupPathSync(fooFile.fsPath, service.backupsData.folderWorkspaces);
495 496 497
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.folderWorkspaces, [barFile.fsPath]);
498
				service.removeBackupPathSync(barFile.fsPath, service.backupsData.folderWorkspaces);
499 500 501 502 503
				pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
					const json2 = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json2.folderWorkspaces, []);
					done();
				});
504 505
			});
		});
506

507
		test('should remove folder workspaces from workspaces.json (root workspace)', done => {
508 509 510 511 512
			const ws1 = toWorkspace(fooFile.fsPath);
			service.registerWorkspaceBackupSync(ws1);
			const ws2 = toWorkspace(barFile.fsPath);
			service.registerWorkspaceBackupSync(ws2);
			service.removeBackupPathSync(ws1, service.backupsData.rootWorkspaces);
513 514
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
515 516
				assert.deepEqual(json.rootWorkspaces.map(r => r.configPath), [barFile.fsPath]);
				service.removeBackupPathSync(ws2, service.backupsData.rootWorkspaces);
517 518 519 520 521 522 523 524
				pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
					const json2 = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json2.rootWorkspaces, []);
					done();
				});
			});
		});

D
Daniel Imms 已提交
525
		test('should remove empty workspaces from workspaces.json', done => {
B
Benjamin Pasero 已提交
526 527
			service.registerEmptyWindowBackupSync('foo');
			service.registerEmptyWindowBackupSync('bar');
528
			service.removeBackupPathSync('foo', service.backupsData.emptyWorkspaces);
D
Daniel Imms 已提交
529 530 531
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.emptyWorkspaces, ['bar']);
532
				service.removeBackupPathSync('bar', service.backupsData.emptyWorkspaces);
D
Daniel Imms 已提交
533 534 535 536 537 538 539 540
				pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
					const json2 = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json2.emptyWorkspaces, []);
					done();
				});
			});
		});

541
		test('should fail gracefully when removing a path that doesn\'t exist', done => {
542
			const workspacesJson: IBackupWorkspacesFormat = { rootWorkspaces: [], folderWorkspaces: [fooFile.fsPath], emptyWorkspaces: [] };
543
			pfs.writeFile(backupWorkspacesPath, JSON.stringify(workspacesJson)).then(() => {
544 545
				service.removeBackupPathSync(barFile.fsPath, service.backupsData.folderWorkspaces);
				service.removeBackupPathSync('test', service.backupsData.emptyWorkspaces);
546 547 548 549 550 551 552
				pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
					const json = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json.folderWorkspaces, [fooFile.fsPath]);
					done();
				});
			});
		});
553
	});
D
Daniel Imms 已提交
554

555
	suite('getWorkspaceHash', () => {
D
Daniel Imms 已提交
556
		test('should perform an md5 hash on the path', () => {
557
			assert.equal(service.getFolderHash('/foo'), '1effb2475fcfba4f9e8b8a1dbc8f3caf');
D
Daniel Imms 已提交
558 559
		});

560 561 562 563 564
		test('should ignore case on Windows and Mac', () => {
			// Skip test on Linux
			if (platform.isLinux) {
				return;
			}
D
Daniel Imms 已提交
565

566
			if (platform.isMacintosh) {
567
				assert.equal(service.getFolderHash('/foo'), service.getFolderHash('/FOO'));
568
			}
D
Daniel Imms 已提交
569

570
			if (platform.isWindows) {
571
				assert.equal(service.getFolderHash('c:\\foo'), service.getFolderHash('C:\\FOO'));
572 573
			}
		});
D
Daniel Imms 已提交
574
	});
575

576
	suite('mixed path casing', () => {
577
		test('should handle case insensitive paths properly (registerWindowForBackupsSync) (folder workspace)', done => {
B
Benjamin Pasero 已提交
578 579
			service.registerFolderBackupSync(fooFile.fsPath);
			service.registerFolderBackupSync(fooFile.fsPath.toUpperCase());
580

581 582 583 584 585 586 587 588 589 590
			if (platform.isLinux) {
				assert.equal(service.getFolderBackupPaths().length, 2);
			} else {
				assert.equal(service.getFolderBackupPaths().length, 1);
			}

			done();
		});

		test('should handle case insensitive paths properly (registerWindowForBackupsSync) (root workspace)', done => {
591 592
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath.toUpperCase()));
593

594
			if (platform.isLinux) {
595
				assert.equal(service.getWorkspaceBackups().length, 2);
596
			} else {
597
				assert.equal(service.getWorkspaceBackups().length, 1);
598 599 600 601 602
			}

			done();
		});

603
		test('should handle case insensitive paths properly (removeBackupPathSync) (folder workspace)', done => {
604 605

			// same case
B
Benjamin Pasero 已提交
606
			service.registerFolderBackupSync(fooFile.fsPath);
607 608
			service.removeBackupPathSync(fooFile.fsPath, service.backupsData.folderWorkspaces);
			assert.equal(service.getFolderBackupPaths().length, 0);
609 610

			// mixed case
B
Benjamin Pasero 已提交
611
			service.registerFolderBackupSync(fooFile.fsPath);
612 613 614 615 616 617 618 619 620 621
			service.removeBackupPathSync(fooFile.fsPath.toUpperCase(), service.backupsData.folderWorkspaces);

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

			done();
		});
622
	});
623
});