提交 e9be3303 编写于 作者: D Daniel Imms

Add backup tests for FileService

上级 36f1d703
......@@ -72,7 +72,7 @@ export class BackupService implements IBackupService {
public removeWorkspaceBackupPath(workspace: Uri): TPromise<void> {
return this.load().then(() => {
if (!this.fileContent.folderWorkspaces) {
return;
return TPromise.as(void 0);
}
delete this.fileContent.folderWorkspaces[workspace.fsPath];
return this.save();
......@@ -88,7 +88,7 @@ export class BackupService implements IBackupService {
public getWorkspaceUntitledFileBackupsSync(workspace: Uri): string[] {
// Hot exit is disabled for empty workspaces
if (!this.workspaceResource) {
return;
return [];
}
const workspaceHash = crypto.createHash('md5').update(workspace.fsPath).digest('hex');
......@@ -105,7 +105,7 @@ export class BackupService implements IBackupService {
public getBackupResource(resource: Uri): Uri {
// Hot exit is disabled for empty workspaces
if (!this.workspaceResource) {
return;
return null;
}
const workspaceHash = crypto.createHash('md5').update(this.workspaceResource.fsPath).digest('hex');
......@@ -135,7 +135,7 @@ export class BackupService implements IBackupService {
public deregisterResourceForBackup(resource: Uri): TPromise<void> {
// Hot exit is disabled for empty workspaces
if (!this.workspaceResource) {
return;
return TPromise.as(void 0);
}
return this.load().then(() => {
......@@ -149,14 +149,27 @@ export class BackupService implements IBackupService {
}
private load(): TPromise<void> {
return pfs.fileExists(this.environmentService.backupWorkspacesPath).then(exists => {
if (!exists) {
this.fileContent = {
folderWorkspaces: Object.create(null)
};
return TPromise.as(void 0);
}
return pfs.readFile(this.environmentService.backupWorkspacesPath, 'utf8').then(content => {
try {
return JSON.parse(content.toString());
}).then(null, () => Object.create(null)).then(content => {
} catch (ex) {
return Object.create(null);
}
}).then(content => {
this.fileContent = content;
if (!this.fileContent.folderWorkspaces) {
this.fileContent.folderWorkspaces = Object.create(null);
}
return void 0;
return TPromise.as(void 0);
});
});
}
......
......@@ -32,15 +32,11 @@ suite('BackupService', () => {
// Delete any existing backups completely, this in itself is a test to ensure that the
// the backupHome directory is re-created
nfcall(extfs.del, environmentService.backupHome, os.tmpdir()).then(() => {
done();
});
extfs.del(environmentService.backupHome, os.tmpdir(), done);
});
teardown(done => {
nfcall(extfs.del, environmentService.backupHome, os.tmpdir()).then(() => {
done();
});
extfs.del(environmentService.backupHome, os.tmpdir(), done);
});
test('pushWorkspaceBackupPathsSync should persist paths to workspaces.json', () => {
......
......@@ -175,7 +175,7 @@ export function workbenchInstantiationService(): IInstantiationService {
instantiationService.stub(IHistoryService, 'getHistory', []);
instantiationService.stub(IModelService, createMockModelService(instantiationService));
instantiationService.stub(IFileService, TestFileService);
instantiationService.stub(IBackupService, TestBackupService);
instantiationService.stub(IBackupService, new TestBackupService());
instantiationService.stub(ITelemetryService, NullTelemetryService);
instantiationService.stub(IMessageService, new TestMessageService());
instantiationService.stub(IUntitledEditorService, instantiationService.createInstance(UntitledEditorService));
......@@ -574,6 +574,10 @@ export const TestFileService = {
});
},
backupFile: function (resource: URI, content: string) {
return TPromise.as(void 0);
},
discardBackup: function (resource: URI) {
return TPromise.as(void 0);
},
......@@ -587,10 +591,50 @@ export const TestFileService = {
}
};
export const TestBackupService = {
removeWorkspaceBackupPath: function () {
export class TestBackupService implements IBackupService {
public _serviceBrand: any;
// Lists used for verification in tests
public registeredResources: URI[] = [];
public deregisteredResources: URI[] = [];
public getWorkspaceBackupPaths(): TPromise<string[]> {
return TPromise.as([]);
}
public getWorkspaceBackupPathsSync(): string[] {
return [];
}
public pushWorkspaceBackupPathsSync(workspaces: URI[]): void {
return null;
}
public removeWorkspaceBackupPath(workspace: URI): TPromise<void> {
return TPromise.as(void 0);
}
public getWorkspaceTextFilesWithBackupsSync(workspace: URI): string[] {
return [];
}
public getWorkspaceUntitledFileBackupsSync(workspace: URI): string[] {
return [];
}
public registerResourceForBackup(resource: URI): TPromise<void> {
this.registeredResources.push(resource);
return TPromise.as(void 0);
}
public deregisterResourceForBackup(resource: URI): TPromise<void> {
this.deregisteredResources.push(resource);
return TPromise.as(void 0);
}
public getBackupResource(resource: URI): URI {
return null;
}
};
export class TestConfigurationService extends EventEmitter implements IConfigurationService {
......
......@@ -87,7 +87,7 @@ suite('WorkspaceConfigurationEditingService - Node', () => {
const configurationService = new WorkspaceConfigurationService(workspaceContextService, new TestEventService(), environmentService);
const textFileService = workbenchInstantiationService().createInstance(TestDirtyTextFileService, dirty);
const events = new utils.TestEventService();
const fileService = new FileService(noWorkspace ? null : workspaceDir, { disableWatcher: true }, events, environmentService, configurationService, null, null);
const fileService = new FileService(noWorkspace ? null : workspaceDir, { disableWatcher: true }, events, environmentService, configurationService, null);
return configurationService.initialize().then(() => {
return {
......
......@@ -83,7 +83,7 @@ export class FileService implements IFileService {
// create service
const workspace = this.contextService.getWorkspace();
this.raw = new NodeFileService(workspace ? workspace.resource.fsPath : void 0, fileServiceConfig, this.eventService, this.environmentService, this.configurationService, this.backupService, this.contextService);
this.raw = new NodeFileService(workspace ? workspace.resource.fsPath : void 0, fileServiceConfig, this.eventService, this.environmentService, this.configurationService, this.backupService);
// Listeners
this.registerListeners();
......
......@@ -37,7 +37,6 @@ import { IBackupService } from 'vs/platform/backup/common/backup';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IFilesConfiguration } from 'vs/platform/files/common/files';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
export interface IEncodingOverride {
resource: uri;
......@@ -97,8 +96,7 @@ export class FileService implements IFileService {
private eventEmitter: IEventService,
private environmentService: IEnvironmentService,
private configurationService: IConfigurationService,
private backupService: IBackupService,
private contextService: IWorkspaceContextService
private backupService: IBackupService
) {
this.basePath = basePath ? paths.normalize(basePath) : void 0;
......@@ -519,12 +517,11 @@ export class FileService implements IFileService {
private getBackupRootPath(): string {
// Hot exit is disabled for empty workspaces
const workspace = this.contextService.getWorkspace();
if (!workspace) {
if (!this.basePath) {
return null;
}
const workspaceHash = crypto.createHash('md5').update(workspace.resource.fsPath).digest('hex');
const workspaceHash = crypto.createHash('md5').update(this.basePath).digest('hex');
return paths.join(this.environmentService.userDataPath, 'Backups', workspaceHash);
}
......
......@@ -9,11 +9,14 @@ import fs = require('fs');
import path = require('path');
import os = require('os');
import assert = require('assert');
import crypto = require('crypto');
import { TPromise } from 'vs/base/common/winjs.base';
import { FileService, IEncodingOverride } from 'vs/workbench/services/files/node/fileService';
import { EventType, FileChangesEvent, FileOperationResult, IFileOperationResult } from 'vs/platform/files/common/files';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { nfcall } from 'vs/base/common/async';
import { TestBackupService, TestEnvironmentService } from 'vs/test/utils/servicesTestUtils';
import uri from 'vs/base/common/uri';
import uuid = require('vs/base/common/uuid');
import extfs = require('vs/base/node/extfs');
......@@ -33,7 +36,7 @@ suite('FileService', () => {
extfs.copy(sourceDir, testDir, () => {
events = new utils.TestEventService();
service = new FileService(testDir, { disableWatcher: true }, events, null, null, null, null);
service = new FileService(testDir, { disableWatcher: true }, events, null, null, null);
done();
});
});
......@@ -275,6 +278,73 @@ suite('FileService', () => {
});
});
suite('backups', () => {
const environment = TestEnvironmentService;
const fooResource = uri.file('/foo');
const barResource = uri.file('/bar');
let _service: FileService;
let backup: TestBackupService;
let workspaceHash;
let workspaceBackupRoot;
let fooFileHash;
let barFileHash;
let fooBackupPath;
let barBackupPath;
setup((done) => {
extfs.del(TestEnvironmentService.backupHome, os.tmpdir(), done);
backup = new TestBackupService();
_service = new FileService(testDir, { disableWatcher: true }, events, environment, null, backup);
workspaceHash = crypto.createHash('md5').update(testDir).digest('hex');
workspaceBackupRoot = path.join(environment.backupHome, workspaceHash, 'file');
fooFileHash = crypto.createHash('md5').update(fooResource.fsPath).digest('hex');
barFileHash = crypto.createHash('md5').update(barResource.fsPath).digest('hex');
fooBackupPath = path.join(workspaceBackupRoot, fooFileHash);
barBackupPath = path.join(workspaceBackupRoot, barFileHash);
});
teardown((done) => {
extfs.del(TestEnvironmentService.backupHome, os.tmpdir(), done);
});
test('backupFile', function (done: () => void) {
_service.backupFile(fooResource, 'test').then(() => {
assert.equal(fs.readdirSync(workspaceBackupRoot).length, 1);
assert.equal(fs.existsSync(fooBackupPath), true);
assert.deepEqual(backup.registeredResources, [fooResource]);
assert.equal(fs.readFileSync(fooBackupPath), 'test');
done();
});
});
test('discardBackup', function (done: () => void) {
_service.backupFile(fooResource, 'test').then(() => {
assert.equal(fs.readdirSync(workspaceBackupRoot).length, 1);
_service.discardBackup(fooResource).then(() => {
assert.equal(fs.existsSync(fooBackupPath), false);
assert.equal(fs.readdirSync(workspaceBackupRoot).length, 0);
done();
});
});
});
test('discardBackups', function (done: () => void) {
_service.backupFile(fooResource, 'test').then(() => {
assert.equal(fs.readdirSync(workspaceBackupRoot).length, 1);
_service.backupFile(barResource, 'test').then(() => {
assert.equal(fs.readdirSync(workspaceBackupRoot).length, 2);
_service.discardBackups().then(() => {
assert.equal(fs.existsSync(fooBackupPath), false);
assert.equal(fs.existsSync(barBackupPath), false);
assert.equal(fs.existsSync(workspaceBackupRoot), false);
done();
});
});
});
});
});
test('resolveFile', function (done: () => void) {
service.resolveFile(uri.file(testDir), { resolveTo: [uri.file(path.join(testDir, 'deep'))] }).done(r => {
assert.equal(r.children.length, 6);
......@@ -494,7 +564,7 @@ suite('FileService', () => {
encoding: 'windows1252',
encodingOverride: encodingOverride,
disableWatcher: true
}, null, null, null, null, null);
}, null, null, null, null);
_service.resolveContent(uri.file(path.join(testDir, 'index.html'))).done(c => {
assert.equal(c.encoding, 'windows1252');
......@@ -520,7 +590,7 @@ suite('FileService', () => {
let _service = new FileService(_testDir, {
disableWatcher: true
}, null, null, null, null, null);
}, null, null, null, null);
extfs.copy(_sourceDir, _testDir, () => {
fs.readFile(resource.fsPath, (error, data) => {
......
......@@ -194,7 +194,7 @@ export abstract class TextFileService implements ITextFileService {
private cleanupBackupsBeforeShutdown(): boolean | TPromise<boolean> {
const workspace = this.contextService.getWorkspace();
if (!workspace) {
return TPromise.as(false); // no backups to cleanup, no eto
return false; // no backups to cleanup, no eto
}
return this.backupService.removeWorkspaceBackupPath(workspace.resource).then(() => {
return this.fileService.discardBackups().then(() => {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册