Skip to content

Commit e9be330

Browse files
committed
Add backup tests for FileService
1 parent 36f1d70 commit e9be330

8 files changed

Lines changed: 152 additions & 32 deletions

File tree

src/vs/platform/backup/node/backupService.ts

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export class BackupService implements IBackupService {
7272
public removeWorkspaceBackupPath(workspace: Uri): TPromise<void> {
7373
return this.load().then(() => {
7474
if (!this.fileContent.folderWorkspaces) {
75-
return;
75+
return TPromise.as(void 0);
7676
}
7777
delete this.fileContent.folderWorkspaces[workspace.fsPath];
7878
return this.save();
@@ -88,7 +88,7 @@ export class BackupService implements IBackupService {
8888
public getWorkspaceUntitledFileBackupsSync(workspace: Uri): string[] {
8989
// Hot exit is disabled for empty workspaces
9090
if (!this.workspaceResource) {
91-
return;
91+
return [];
9292
}
9393

9494
const workspaceHash = crypto.createHash('md5').update(workspace.fsPath).digest('hex');
@@ -105,7 +105,7 @@ export class BackupService implements IBackupService {
105105
public getBackupResource(resource: Uri): Uri {
106106
// Hot exit is disabled for empty workspaces
107107
if (!this.workspaceResource) {
108-
return;
108+
return null;
109109
}
110110

111111
const workspaceHash = crypto.createHash('md5').update(this.workspaceResource.fsPath).digest('hex');
@@ -135,7 +135,7 @@ export class BackupService implements IBackupService {
135135
public deregisterResourceForBackup(resource: Uri): TPromise<void> {
136136
// Hot exit is disabled for empty workspaces
137137
if (!this.workspaceResource) {
138-
return;
138+
return TPromise.as(void 0);
139139
}
140140

141141
return this.load().then(() => {
@@ -149,14 +149,27 @@ export class BackupService implements IBackupService {
149149
}
150150

151151
private load(): TPromise<void> {
152-
return pfs.readFile(this.environmentService.backupWorkspacesPath, 'utf8').then(content => {
153-
return JSON.parse(content.toString());
154-
}).then(null, () => Object.create(null)).then(content => {
155-
this.fileContent = content;
156-
if (!this.fileContent.folderWorkspaces) {
157-
this.fileContent.folderWorkspaces = Object.create(null);
152+
return pfs.fileExists(this.environmentService.backupWorkspacesPath).then(exists => {
153+
if (!exists) {
154+
this.fileContent = {
155+
folderWorkspaces: Object.create(null)
156+
};
157+
return TPromise.as(void 0);
158158
}
159-
return void 0;
159+
160+
return pfs.readFile(this.environmentService.backupWorkspacesPath, 'utf8').then(content => {
161+
try {
162+
return JSON.parse(content.toString());
163+
} catch (ex) {
164+
return Object.create(null);
165+
}
166+
}).then(content => {
167+
this.fileContent = content;
168+
if (!this.fileContent.folderWorkspaces) {
169+
this.fileContent.folderWorkspaces = Object.create(null);
170+
}
171+
return TPromise.as(void 0);
172+
});
160173
});
161174
}
162175

src/vs/platform/backup/test/backupService.test.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,11 @@ suite('BackupService', () => {
3232

3333
// Delete any existing backups completely, this in itself is a test to ensure that the
3434
// the backupHome directory is re-created
35-
nfcall(extfs.del, environmentService.backupHome, os.tmpdir()).then(() => {
36-
done();
37-
});
35+
extfs.del(environmentService.backupHome, os.tmpdir(), done);
3836
});
3937

4038
teardown(done => {
41-
nfcall(extfs.del, environmentService.backupHome, os.tmpdir()).then(() => {
42-
done();
43-
});
39+
extfs.del(environmentService.backupHome, os.tmpdir(), done);
4440
});
4541

4642
test('pushWorkspaceBackupPathsSync should persist paths to workspaces.json', () => {

src/vs/test/utils/servicesTestUtils.ts

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ export function workbenchInstantiationService(): IInstantiationService {
175175
instantiationService.stub(IHistoryService, 'getHistory', []);
176176
instantiationService.stub(IModelService, createMockModelService(instantiationService));
177177
instantiationService.stub(IFileService, TestFileService);
178-
instantiationService.stub(IBackupService, TestBackupService);
178+
instantiationService.stub(IBackupService, new TestBackupService());
179179
instantiationService.stub(ITelemetryService, NullTelemetryService);
180180
instantiationService.stub(IMessageService, new TestMessageService());
181181
instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService));
@@ -574,6 +574,10 @@ export const TestFileService = {
574574
});
575575
},
576576

577+
backupFile: function (resource: URI, content: string) {
578+
return TPromise.as(void 0);
579+
},
580+
577581
discardBackup: function (resource: URI) {
578582
return TPromise.as(void 0);
579583
},
@@ -587,10 +591,50 @@ export const TestFileService = {
587591
}
588592
};
589593

590-
export const TestBackupService = {
591-
removeWorkspaceBackupPath: function () {
594+
export class TestBackupService implements IBackupService {
595+
public _serviceBrand: any;
596+
597+
// Lists used for verification in tests
598+
public registeredResources: URI[] = [];
599+
public deregisteredResources: URI[] = [];
600+
601+
public getWorkspaceBackupPaths(): TPromise<string[]> {
602+
return TPromise.as([]);
603+
}
604+
605+
public getWorkspaceBackupPathsSync(): string[] {
606+
return [];
607+
}
608+
609+
public pushWorkspaceBackupPathsSync(workspaces: URI[]): void {
610+
return null;
611+
}
612+
613+
public removeWorkspaceBackupPath(workspace: URI): TPromise<void> {
592614
return TPromise.as(void 0);
593615
}
616+
617+
public getWorkspaceTextFilesWithBackupsSync(workspace: URI): string[] {
618+
return [];
619+
}
620+
621+
public getWorkspaceUntitledFileBackupsSync(workspace: URI): string[] {
622+
return [];
623+
}
624+
625+
public registerResourceForBackup(resource: URI): TPromise<void> {
626+
this.registeredResources.push(resource);
627+
return TPromise.as(void 0);
628+
}
629+
630+
public deregisterResourceForBackup(resource: URI): TPromise<void> {
631+
this.deregisteredResources.push(resource);
632+
return TPromise.as(void 0);
633+
}
634+
635+
public getBackupResource(resource: URI): URI {
636+
return null;
637+
}
594638
};
595639

596640
export class TestConfigurationService extends EventEmitter implements IConfigurationService {

src/vs/workbench/services/configuration/test/node/configurationEditingService.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ suite('WorkspaceConfigurationEditingService - Node', () => {
8787
const configurationService = new WorkspaceConfigurationService(workspaceContextService, new TestEventService(), environmentService);
8888
const textFileService = workbenchInstantiationService().createInstance(TestDirtyTextFileService, dirty);
8989
const events = new utils.TestEventService();
90-
const fileService = new FileService(noWorkspace ? null : workspaceDir, { disableWatcher: true }, events, environmentService, configurationService, null, null);
90+
const fileService = new FileService(noWorkspace ? null : workspaceDir, { disableWatcher: true }, events, environmentService, configurationService, null);
9191

9292
return configurationService.initialize().then(() => {
9393
return {

src/vs/workbench/services/files/electron-browser/fileService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ export class FileService implements IFileService {
8383

8484
// create service
8585
const workspace = this.contextService.getWorkspace();
86-
this.raw = new NodeFileService(workspace ? workspace.resource.fsPath : void 0, fileServiceConfig, this.eventService, this.environmentService, this.configurationService, this.backupService, this.contextService);
86+
this.raw = new NodeFileService(workspace ? workspace.resource.fsPath : void 0, fileServiceConfig, this.eventService, this.environmentService, this.configurationService, this.backupService);
8787

8888
// Listeners
8989
this.registerListeners();

src/vs/workbench/services/files/node/fileService.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ import { IBackupService } from 'vs/platform/backup/common/backup';
3737
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
3838
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
3939
import { IFilesConfiguration } from 'vs/platform/files/common/files';
40-
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
4140

4241
export interface IEncodingOverride {
4342
resource: uri;
@@ -97,8 +96,7 @@ export class FileService implements IFileService {
9796
private eventEmitter: IEventService,
9897
private environmentService: IEnvironmentService,
9998
private configurationService: IConfigurationService,
100-
private backupService: IBackupService,
101-
private contextService: IWorkspaceContextService
99+
private backupService: IBackupService
102100
) {
103101
this.basePath = basePath ? paths.normalize(basePath) : void 0;
104102

@@ -519,12 +517,11 @@ export class FileService implements IFileService {
519517

520518
private getBackupRootPath(): string {
521519
// Hot exit is disabled for empty workspaces
522-
const workspace = this.contextService.getWorkspace();
523-
if (!workspace) {
520+
if (!this.basePath) {
524521
return null;
525522
}
526523

527-
const workspaceHash = crypto.createHash('md5').update(workspace.resource.fsPath).digest('hex');
524+
const workspaceHash = crypto.createHash('md5').update(this.basePath).digest('hex');
528525
return paths.join(this.environmentService.userDataPath, 'Backups', workspaceHash);
529526
}
530527

src/vs/workbench/services/files/test/node/fileService.test.ts

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,14 @@ import fs = require('fs');
99
import path = require('path');
1010
import os = require('os');
1111
import assert = require('assert');
12+
import crypto = require('crypto');
1213

1314
import { TPromise } from 'vs/base/common/winjs.base';
1415
import { FileService, IEncodingOverride } from 'vs/workbench/services/files/node/fileService';
1516
import { EventType, FileChangesEvent, FileOperationResult, IFileOperationResult } from 'vs/platform/files/common/files';
17+
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
1618
import { nfcall } from 'vs/base/common/async';
19+
import { TestBackupService, TestEnvironmentService } from 'vs/test/utils/servicesTestUtils';
1720
import uri from 'vs/base/common/uri';
1821
import uuid = require('vs/base/common/uuid');
1922
import extfs = require('vs/base/node/extfs');
@@ -33,7 +36,7 @@ suite('FileService', () => {
3336

3437
extfs.copy(sourceDir, testDir, () => {
3538
events = new utils.TestEventService();
36-
service = new FileService(testDir, { disableWatcher: true }, events, null, null, null, null);
39+
service = new FileService(testDir, { disableWatcher: true }, events, null, null, null);
3740
done();
3841
});
3942
});
@@ -275,6 +278,73 @@ suite('FileService', () => {
275278
});
276279
});
277280

281+
suite('backups', () => {
282+
const environment = TestEnvironmentService;
283+
const fooResource = uri.file('/foo');
284+
const barResource = uri.file('/bar');
285+
286+
let _service: FileService;
287+
let backup: TestBackupService;
288+
let workspaceHash;
289+
let workspaceBackupRoot;
290+
let fooFileHash;
291+
let barFileHash;
292+
let fooBackupPath;
293+
let barBackupPath;
294+
295+
setup((done) => {
296+
extfs.del(TestEnvironmentService.backupHome, os.tmpdir(), done);
297+
backup = new TestBackupService();
298+
_service = new FileService(testDir, { disableWatcher: true }, events, environment, null, backup);
299+
workspaceHash = crypto.createHash('md5').update(testDir).digest('hex');
300+
workspaceBackupRoot = path.join(environment.backupHome, workspaceHash, 'file');
301+
fooFileHash = crypto.createHash('md5').update(fooResource.fsPath).digest('hex');
302+
barFileHash = crypto.createHash('md5').update(barResource.fsPath).digest('hex');
303+
fooBackupPath = path.join(workspaceBackupRoot, fooFileHash);
304+
barBackupPath = path.join(workspaceBackupRoot, barFileHash);
305+
});
306+
307+
teardown((done) => {
308+
extfs.del(TestEnvironmentService.backupHome, os.tmpdir(), done);
309+
});
310+
311+
test('backupFile', function (done: () => void) {
312+
_service.backupFile(fooResource, 'test').then(() => {
313+
assert.equal(fs.readdirSync(workspaceBackupRoot).length, 1);
314+
assert.equal(fs.existsSync(fooBackupPath), true);
315+
assert.deepEqual(backup.registeredResources, [fooResource]);
316+
assert.equal(fs.readFileSync(fooBackupPath), 'test');
317+
done();
318+
});
319+
});
320+
321+
test('discardBackup', function (done: () => void) {
322+
_service.backupFile(fooResource, 'test').then(() => {
323+
assert.equal(fs.readdirSync(workspaceBackupRoot).length, 1);
324+
_service.discardBackup(fooResource).then(() => {
325+
assert.equal(fs.existsSync(fooBackupPath), false);
326+
assert.equal(fs.readdirSync(workspaceBackupRoot).length, 0);
327+
done();
328+
});
329+
});
330+
});
331+
332+
test('discardBackups', function (done: () => void) {
333+
_service.backupFile(fooResource, 'test').then(() => {
334+
assert.equal(fs.readdirSync(workspaceBackupRoot).length, 1);
335+
_service.backupFile(barResource, 'test').then(() => {
336+
assert.equal(fs.readdirSync(workspaceBackupRoot).length, 2);
337+
_service.discardBackups().then(() => {
338+
assert.equal(fs.existsSync(fooBackupPath), false);
339+
assert.equal(fs.existsSync(barBackupPath), false);
340+
assert.equal(fs.existsSync(workspaceBackupRoot), false);
341+
done();
342+
});
343+
});
344+
});
345+
});
346+
});
347+
278348
test('resolveFile', function (done: () => void) {
279349
service.resolveFile(uri.file(testDir), { resolveTo: [uri.file(path.join(testDir, 'deep'))] }).done(r => {
280350
assert.equal(r.children.length, 6);
@@ -494,7 +564,7 @@ suite('FileService', () => {
494564
encoding: 'windows1252',
495565
encodingOverride: encodingOverride,
496566
disableWatcher: true
497-
}, null, null, null, null, null);
567+
}, null, null, null, null);
498568

499569
_service.resolveContent(uri.file(path.join(testDir, 'index.html'))).done(c => {
500570
assert.equal(c.encoding, 'windows1252');
@@ -520,7 +590,7 @@ suite('FileService', () => {
520590

521591
let _service = new FileService(_testDir, {
522592
disableWatcher: true
523-
}, null, null, null, null, null);
593+
}, null, null, null, null);
524594

525595
extfs.copy(_sourceDir, _testDir, () => {
526596
fs.readFile(resource.fsPath, (error, data) => {

src/vs/workbench/services/textfile/browser/textFileService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ export abstract class TextFileService implements ITextFileService {
194194
private cleanupBackupsBeforeShutdown(): boolean | TPromise<boolean> {
195195
const workspace = this.contextService.getWorkspace();
196196
if (!workspace) {
197-
return TPromise.as(false); // no backups to cleanup, no eto
197+
return false; // no backups to cleanup, no eto
198198
}
199199
return this.backupService.removeWorkspaceBackupPath(workspace.resource).then(() => {
200200
return this.fileService.discardBackups().then(() => {

0 commit comments

Comments
 (0)