Dacpac - Showing error message to user if operation fails (#13830)

* Showing error message to user if operation fails.

* Added more tests
This commit is contained in:
Leila Lali
2020-12-17 10:27:36 -08:00
committed by GitHub
parent 60f556428f
commit f88e17a294
3 changed files with 135 additions and 7 deletions

View File

@@ -67,3 +67,5 @@ export const reservedValueErrorMessage = localize('dacfx.reservedValueErrorMessa
export const trailingWhitespaceErrorMessage = localize('dacfx.trailingWhitespaceErrorMessage', "File name cannot end with a whitespace"); export const trailingWhitespaceErrorMessage = localize('dacfx.trailingWhitespaceErrorMessage', "File name cannot end with a whitespace");
export const tooLongFilenameErrorMessage = localize('dacfx.tooLongFilenameErrorMessage', "File name is over 255 characters"); export const tooLongFilenameErrorMessage = localize('dacfx.tooLongFilenameErrorMessage', "File name is over 255 characters");
export function deployPlanErrorMessage(errorMessage: string): string { return localize('dacfx.deployPlanErrorMessage', "Generating deploy plan failed '{0}'", errorMessage ? errorMessage : 'Unknown'); } export function deployPlanErrorMessage(errorMessage: string): string { return localize('dacfx.deployPlanErrorMessage', "Generating deploy plan failed '{0}'", errorMessage ? errorMessage : 'Unknown'); }
export function generateDeployErrorMessage(errorMessage: string): string { return localize('dacfx.generateDeployErrorMessage', "Generating deploy script failed '{0}'", errorMessage ? errorMessage : 'Unknown'); }
export function operationErrorMessage(operation: string, errorMessage: string): string { return localize('dacfx.operationErrorMessage', "{0} operation failed '{1}'", operation, errorMessage ? errorMessage : 'Unknown'); }

View File

@@ -5,8 +5,11 @@
import 'mocha'; import 'mocha';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as vscode from 'vscode';
import * as should from 'should'; import * as should from 'should';
import * as sinon from 'sinon'; import * as sinon from 'sinon';
import * as TypeMoq from 'typemoq';
import * as loc from '../localizedConstants';
import { DataTierApplicationWizard, Operation } from '../wizard/dataTierApplicationWizard'; import { DataTierApplicationWizard, Operation } from '../wizard/dataTierApplicationWizard';
import { DacFxDataModel } from '../wizard/api/models'; import { DacFxDataModel } from '../wizard/api/models';
import { DacFxTestService, deployOperationId, extractOperationId, importOperationId, exportOperationId, generateDeployPlan } from './testDacFxService'; import { DacFxTestService, deployOperationId, extractOperationId, importOperationId, exportOperationId, generateDeployPlan } from './testDacFxService';
@@ -60,6 +63,95 @@ describe('Dacfx wizard with connection', function (): void {
await validateServiceCalls(wizard, Operation.export, exportOperationId); await validateServiceCalls(wizard, Operation.export, exportOperationId);
}); });
it('executeOperation should show error message if deploy fails', async () => {
let service = TypeMoq.Mock.ofInstance(new DacFxTestService());
service.setup(x => x.deployDacpac(TypeMoq.It.isAny(),TypeMoq.It.isAny(),TypeMoq.It.isAny(),TypeMoq.It.isAny(),TypeMoq.It.isAny(),TypeMoq.It.isAny())).returns(x => Promise.resolve({
errorMessage: 'error1',
success: false,
operationId: ''
}));
let wizard = new DataTierApplicationWizard(service.object);
wizard.model = <DacFxDataModel>{};
wizard.model.server = connectionProfileMock;
let showErrorMessageStub = sinon.stub(vscode.window, 'showErrorMessage').resolves();
wizard.selectedOperation = Operation.deploy;
await wizard.executeOperation();
should(showErrorMessageStub.calledOnce).be.true();
should.equal(showErrorMessageStub.getCall(0).args[0], loc.operationErrorMessage(loc.deploy, 'error1'));
});
it('executeOperation should show error message if export fails', async () => {
let service = TypeMoq.Mock.ofInstance(new DacFxTestService());
service.setup(x => x.exportBacpac(TypeMoq.It.isAny(),TypeMoq.It.isAny(),TypeMoq.It.isAny(),TypeMoq.It.isAny())).returns(x => Promise.resolve({
errorMessage: 'error1',
success: false,
operationId: ''
}));
let wizard = new DataTierApplicationWizard(service.object);
wizard.model = <DacFxDataModel>{};
wizard.model.server = connectionProfileMock;
let showErrorMessageStub = sinon.stub(vscode.window, 'showErrorMessage').resolves();
wizard.selectedOperation = Operation.export;
await wizard.executeOperation();
should(showErrorMessageStub.calledOnce).be.true();
should.equal(showErrorMessageStub.getCall(0).args[0], loc.operationErrorMessage(loc.exportText, 'error1'));
});
it('executeOperation should show error message if extract fails', async () => {
let service = TypeMoq.Mock.ofInstance(new DacFxTestService());
service.setup(x => x.extractDacpac(TypeMoq.It.isAny(),TypeMoq.It.isAny(),TypeMoq.It.isAny(),TypeMoq.It.isAny(),TypeMoq.It.isAny(),TypeMoq.It.isAny())).returns(x => Promise.resolve({
errorMessage: 'error1',
success: false,
operationId: ''
}));
let wizard = new DataTierApplicationWizard(service.object);
wizard.model = <DacFxDataModel>{};
wizard.model.server = connectionProfileMock;
let showErrorMessageStub = sinon.stub(vscode.window, 'showErrorMessage').resolves();
wizard.selectedOperation = Operation.extract;
await wizard.executeOperation();
should(showErrorMessageStub.calledOnce).be.true();
should.equal(showErrorMessageStub.getCall(0).args[0], loc.operationErrorMessage(loc.extract, 'error1'));
});
it('Should show error message if generateDeployScript fails', async () => {
let service = TypeMoq.Mock.ofInstance(new DacFxTestService());
service.setup(x => x.generateDeployScript(TypeMoq.It.isAny(),TypeMoq.It.isAny(),TypeMoq.It.isAny(),TypeMoq.It.isAny())).returns(x => Promise.resolve({
errorMessage: 'error1',
success: false,
operationId: ''
}));
let wizard = new DataTierApplicationWizard(service.object);
wizard.model = <DacFxDataModel>{};
wizard.model.server = connectionProfileMock;
let showErrorMessageStub = sinon.stub(vscode.window, 'showErrorMessage').resolves();
await wizard.generateDeployScript();
should(showErrorMessageStub.calledOnce).be.true();
should.equal(showErrorMessageStub.getCall(0).args[0], loc.generateDeployErrorMessage('error1'));
});
it('executeOperation should show error message if import fails', async () => {
let service = TypeMoq.Mock.ofInstance(new DacFxTestService());
service.setup(x => x.importBacpac(TypeMoq.It.isAny(),TypeMoq.It.isAny(),TypeMoq.It.isAny(),TypeMoq.It.isAny())).returns(x => Promise.resolve({
errorMessage: 'error1',
success: false,
operationId: ''
}));
let wizard = new DataTierApplicationWizard(service.object);
wizard.model = <DacFxDataModel>{};
wizard.model.server = connectionProfileMock;
let showErrorMessageStub = sinon.stub(vscode.window, 'showErrorMessage').resolves();
wizard.selectedOperation = Operation.import;
await wizard.executeOperation();
should(showErrorMessageStub.calledOnce).be.true();
should.equal(showErrorMessageStub.getCall(0).args[0], loc.operationErrorMessage(loc.importText, 'error1'));
});
it('Should call deploy plan generator correctly', async () => { it('Should call deploy plan generator correctly', async () => {
wizard.model.server = connectionProfileMock; wizard.model.server = connectionProfileMock;

View File

@@ -242,18 +242,47 @@ export class DataTierApplicationWizard {
} }
public async executeOperation(): Promise<mssql.DacFxResult> { public async executeOperation(): Promise<mssql.DacFxResult> {
let result: mssql.DacFxResult;
switch (this.selectedOperation) { switch (this.selectedOperation) {
case Operation.deploy: { case Operation.deploy: {
return await this.deploy(); result = await this.deploy();
break;
} }
case Operation.extract: { case Operation.extract: {
return await this.extract(); result = await this.extract();
break;
} }
case Operation.import: { case Operation.import: {
return await this.import(); result = await this.import();
break;
} }
case Operation.export: { case Operation.export: {
return await this.export(); result = await this.export();
break;
}
}
if (!result || !result.success) {
vscode.window.showErrorMessage(this.getOperationErrorMessage(this.selectedOperation, result?.errorMessage));
}
return result;
}
private getOperationErrorMessage(operation: Operation, error: any): string {
switch (this.selectedOperation) {
case Operation.deploy: {
return loc.operationErrorMessage(loc.deploy, error);
}
case Operation.extract: {
return loc.operationErrorMessage(loc.extract, error);
}
case Operation.import: {
return loc.operationErrorMessage(loc.importText, error);
}
case Operation.export: {
return loc.operationErrorMessage(loc.exportText, error);
} }
} }
} }
@@ -286,7 +315,7 @@ export class DataTierApplicationWizard {
return await service.importBacpac(this.model.filePath, this.model.database, ownerUri, azdata.TaskExecutionMode.execute); return await service.importBacpac(this.model.filePath, this.model.database, ownerUri, azdata.TaskExecutionMode.execute);
} }
private async generateDeployScript(): Promise<mssql.DacFxResult> { public async generateDeployScript(): Promise<mssql.DacFxResult> {
const service = await this.getService(msSqlProvider); const service = await this.getService(msSqlProvider);
const ownerUri = await azdata.connection.getUriForConnection(this.model.server.connectionId); const ownerUri = await azdata.connection.getUriForConnection(this.model.server.connectionId);
this.wizard.message = { this.wizard.message = {
@@ -295,7 +324,12 @@ export class DataTierApplicationWizard {
description: '' description: ''
}; };
return await service.generateDeployScript(this.model.filePath, this.model.database, ownerUri, azdata.TaskExecutionMode.script); let result = await service.generateDeployScript(this.model.filePath, this.model.database, ownerUri, azdata.TaskExecutionMode.script);
if (!result || !result.success) {
vscode.window.showErrorMessage(loc.generateDeployErrorMessage(result?.errorMessage));
}
return result;
} }
public getPage(idx: number): Page { public getPage(idx: number): Page {
@@ -344,7 +378,7 @@ export class DataTierApplicationWizard {
const result = await service.generateDeployPlan(this.model.filePath, this.model.database, ownerUri, azdata.TaskExecutionMode.execute); const result = await service.generateDeployPlan(this.model.filePath, this.model.database, ownerUri, azdata.TaskExecutionMode.execute);
if (!result || !result.success) { if (!result || !result.success) {
vscode.window.showErrorMessage(loc.deployPlanErrorMessage(result.errorMessage)); vscode.window.showErrorMessage(loc.deployPlanErrorMessage(result?.errorMessage));
} }
return result.report; return result.report;