mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Adding unit tests for schema compare service (#13642)
This commit is contained in:
@@ -87,13 +87,15 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mocha": "^5.2.5",
|
||||
"@types/sinon": "^9.0.4",
|
||||
"@types/node": "^12.11.7",
|
||||
"mocha": "^5.2.0",
|
||||
"mocha-junit-reporter": "^1.17.0",
|
||||
"mocha-multi-reporters": "^1.1.7",
|
||||
"should": "^13.2.1",
|
||||
"typemoq": "^2.1.0",
|
||||
"vscodetestcover": "^1.1.0"
|
||||
"vscodetestcover": "^1.1.0",
|
||||
"sinon": "^9.0.2"
|
||||
},
|
||||
"__metadata": {
|
||||
"id": "37",
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as azdata from 'azdata';
|
||||
|
||||
/**
|
||||
* Wrapper class to act as a facade over VSCode and Data APIs and allow us to test / mock callbacks into
|
||||
* this API from our code
|
||||
*/
|
||||
export class ApiWrapper {
|
||||
public openConnectionDialog(providers?: string[],
|
||||
initialConnectionProfile?: azdata.IConnectionProfile,
|
||||
connectionCompletionOptions?: azdata.IConnectionCompletionOptions): Thenable<azdata.connection.Connection> {
|
||||
return azdata.connection.openConnectionDialog(providers, initialConnectionProfile, connectionCompletionOptions);
|
||||
}
|
||||
|
||||
public registerCommand(command: string, callback: (...args: any[]) => any, thisArg?: any): vscode.Disposable {
|
||||
return vscode.commands.registerCommand(command, callback, thisArg);
|
||||
}
|
||||
|
||||
public getUriForConnection(connectionId: string): Thenable<string> {
|
||||
return azdata.connection.getUriForConnection(connectionId);
|
||||
}
|
||||
|
||||
public getConnections(activeConnectionsOnly?: boolean): Thenable<azdata.connection.ConnectionProfile[]> {
|
||||
return azdata.connection.getConnections(activeConnectionsOnly);
|
||||
}
|
||||
|
||||
public connect(connectionProfile: azdata.IConnectionProfile, saveConnection?: boolean, showDashboard?: boolean): Thenable<azdata.ConnectionResult> {
|
||||
return azdata.connection.connect(connectionProfile, saveConnection, showDashboard);
|
||||
}
|
||||
|
||||
public showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined> {
|
||||
return vscode.window.showErrorMessage(message, ...items);
|
||||
}
|
||||
|
||||
public showWarningMessage(message: string, options?: vscode.MessageOptions, ...items: string[]): Thenable<string | undefined> {
|
||||
if (options) {
|
||||
return vscode.window.showWarningMessage(message, options, ...items);
|
||||
}
|
||||
else {
|
||||
return vscode.window.showWarningMessage(message, ...items);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,10 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { ApiWrapper } from './common/apiWrapper';
|
||||
import { SchemaCompareMainWindow } from './schemaCompareMainWindow';
|
||||
|
||||
export async function activate(extensionContext: vscode.ExtensionContext): Promise<void> {
|
||||
vscode.commands.registerCommand('schemaCompare.start', async (context: any) => { await new SchemaCompareMainWindow(new ApiWrapper(), undefined, extensionContext).start(context); });
|
||||
vscode.commands.registerCommand('schemaCompare.start', async (context: any) => { await new SchemaCompareMainWindow(undefined, extensionContext).start(context); });
|
||||
}
|
||||
|
||||
export function deactivate(): void {
|
||||
|
||||
@@ -14,7 +14,6 @@ import { TelemetryReporter, TelemetryViews } from './telemetry';
|
||||
import { getTelemetryErrorType, getEndpointName, verifyConnectionAndGetOwnerUri, getRootPath } from './utils';
|
||||
import { SchemaCompareDialog } from './dialogs/schemaCompareDialog';
|
||||
import { isNullOrUndefined } from 'util';
|
||||
import { ApiWrapper } from './common/apiWrapper';
|
||||
|
||||
// Do not localize this, this is used to decide the icon for the editor.
|
||||
// TODO : In future icon should be decided based on language id (scmp) and not resource name
|
||||
@@ -69,7 +68,7 @@ export class SchemaCompareMainWindow {
|
||||
public sourceEndpointInfo: mssql.SchemaCompareEndpointInfo;
|
||||
public targetEndpointInfo: mssql.SchemaCompareEndpointInfo;
|
||||
|
||||
constructor(private apiWrapper: ApiWrapper, private schemaCompareService?: mssql.ISchemaCompareService, private extensionContext?: vscode.ExtensionContext) {
|
||||
constructor(private schemaCompareService?: mssql.ISchemaCompareService, private extensionContext?: vscode.ExtensionContext) {
|
||||
this.SchemaCompareActionMap = new Map<Number, string>();
|
||||
this.SchemaCompareActionMap[mssql.SchemaUpdateAction.Delete] = loc.deleteAction;
|
||||
this.SchemaCompareActionMap[mssql.SchemaUpdateAction.Change] = loc.changeAction;
|
||||
@@ -87,7 +86,7 @@ export class SchemaCompareMainWindow {
|
||||
let profile = context ? <azdata.IConnectionProfile>context.connectionProfile : undefined;
|
||||
let sourceDacpac = context as string;
|
||||
if (profile) {
|
||||
let ownerUri = await this.apiWrapper.getUriForConnection((profile.id));
|
||||
let ownerUri = await azdata.connection.getUriForConnection((profile.id));
|
||||
this.sourceEndpointInfo = {
|
||||
endpointType: mssql.SchemaCompareEndpointType.Database,
|
||||
serverDisplayName: `${profile.serverName} ${profile.userName}`,
|
||||
@@ -295,11 +294,11 @@ export class SchemaCompareMainWindow {
|
||||
}
|
||||
this.comparisonResult = await service.schemaCompare(this.operationId, this.sourceEndpointInfo, this.targetEndpointInfo, azdata.TaskExecutionMode.execute, this.deploymentOptions);
|
||||
if (!this.comparisonResult || !this.comparisonResult.success) {
|
||||
TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaComparisonFailed', undefined, getTelemetryErrorType(this.comparisonResult.errorMessage))
|
||||
TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaComparisonFailed', undefined, getTelemetryErrorType(this.comparisonResult?.errorMessage))
|
||||
.withAdditionalProperties({
|
||||
operationId: this.comparisonResult.operationId
|
||||
}).send();
|
||||
this.apiWrapper.showErrorMessage(loc.compareErrorMessage(this.comparisonResult.errorMessage));
|
||||
vscode.window.showErrorMessage(loc.compareErrorMessage(this.comparisonResult?.errorMessage));
|
||||
return;
|
||||
}
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaComparisonFinished')
|
||||
@@ -407,69 +406,76 @@ export class SchemaCompareMainWindow {
|
||||
this.tablelistenersToDispose.push(this.differencesTable.onCellAction(async (rowState) => {
|
||||
let checkboxState = <azdata.ICheckboxCellActionEventArgs>rowState;
|
||||
if (checkboxState) {
|
||||
// show an info notification the first time when trying to exclude to notify the user that it may take some time to calculate affected dependencies
|
||||
if (this.showIncludeExcludeWaitingMessage) {
|
||||
this.showIncludeExcludeWaitingMessage = false;
|
||||
vscode.window.showInformationMessage(loc.includeExcludeInfoMessage);
|
||||
}
|
||||
|
||||
let diff = this.comparisonResult.differences[checkboxState.row];
|
||||
const result = await service.schemaCompareIncludeExcludeNode(this.comparisonResult.operationId, diff, checkboxState.checked, azdata.TaskExecutionMode.execute);
|
||||
let checkboxesToChange = [];
|
||||
if (result.success) {
|
||||
this.saveExcludeState(checkboxState);
|
||||
|
||||
// dependencies could have been included or excluded as a result, so save their exclude states
|
||||
result.affectedDependencies.forEach(difference => {
|
||||
// find the row of the difference and set its checkbox
|
||||
const diffEntryKey = this.createDiffEntryKey(difference);
|
||||
if (this.diffEntryRowMap.has(diffEntryKey)) {
|
||||
const row = this.diffEntryRowMap.get(diffEntryKey);
|
||||
checkboxesToChange.push({ row: row, column: 2, columnName: 'Include', checked: difference.included });
|
||||
const dependencyCheckBoxState: azdata.ICheckboxCellActionEventArgs = {
|
||||
checked: difference.included,
|
||||
row: row,
|
||||
column: 2,
|
||||
columnName: undefined
|
||||
};
|
||||
this.saveExcludeState(dependencyCheckBoxState);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// failed because of dependencies
|
||||
if (result.blockingDependencies) {
|
||||
// show the first dependent that caused this to fail in the warning message
|
||||
const diffEntryName = this.createName(diff.sourceValue ? diff.sourceValue : diff.targetValue);
|
||||
const firstDependentName = this.createName(result.blockingDependencies[0].sourceValue ? result.blockingDependencies[0].sourceValue : result.blockingDependencies[0].targetValue);
|
||||
let cannotExcludeMessage: string;
|
||||
let cannotIncludeMessage: string;
|
||||
if (firstDependentName) {
|
||||
cannotExcludeMessage = loc.cannotExcludeMessageDependent(diffEntryName, firstDependentName);
|
||||
cannotIncludeMessage = loc.cannotIncludeMessageDependent(diffEntryName, firstDependentName);
|
||||
} else {
|
||||
cannotExcludeMessage = loc.cannotExcludeMessage(diffEntryName);
|
||||
cannotIncludeMessage = loc.cannotIncludeMessage(diffEntryName);
|
||||
}
|
||||
vscode.window.showWarningMessage(checkboxState.checked ? cannotIncludeMessage : cannotExcludeMessage);
|
||||
} else {
|
||||
vscode.window.showWarningMessage(result.errorMessage);
|
||||
}
|
||||
|
||||
// set checkbox back to previous state
|
||||
checkboxesToChange.push({ row: checkboxState.row, column: checkboxState.column, columnName: 'Include', checked: !checkboxState.checked });
|
||||
}
|
||||
|
||||
if (checkboxesToChange.length > 0) {
|
||||
this.differencesTable.updateCells = checkboxesToChange;
|
||||
}
|
||||
await this.applyIncludeExclude(checkboxState);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public async applyIncludeExclude(checkboxState: azdata.ICheckboxCellActionEventArgs): Promise<void> {
|
||||
const service = await this.getService();
|
||||
// show an info notification the first time when trying to exclude to notify the user that it may take some time to calculate affected dependencies
|
||||
if (this.showIncludeExcludeWaitingMessage) {
|
||||
this.showIncludeExcludeWaitingMessage = false;
|
||||
vscode.window.showInformationMessage(loc.includeExcludeInfoMessage);
|
||||
}
|
||||
|
||||
let diff = this.comparisonResult.differences[checkboxState.row];
|
||||
const result = await service.schemaCompareIncludeExcludeNode(this.comparisonResult.operationId, diff, checkboxState.checked, azdata.TaskExecutionMode.execute);
|
||||
let checkboxesToChange = [];
|
||||
if (result.success) {
|
||||
this.saveExcludeState(checkboxState);
|
||||
|
||||
// dependencies could have been included or excluded as a result, so save their exclude states
|
||||
result.affectedDependencies.forEach(difference => {
|
||||
// find the row of the difference and set its checkbox
|
||||
const diffEntryKey = this.createDiffEntryKey(difference);
|
||||
if (this.diffEntryRowMap.has(diffEntryKey)) {
|
||||
const row = this.diffEntryRowMap.get(diffEntryKey);
|
||||
checkboxesToChange.push({ row: row, column: 2, columnName: 'Include', checked: difference.included });
|
||||
const dependencyCheckBoxState: azdata.ICheckboxCellActionEventArgs = {
|
||||
checked: difference.included,
|
||||
row: row,
|
||||
column: 2,
|
||||
columnName: undefined
|
||||
};
|
||||
this.saveExcludeState(dependencyCheckBoxState);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// failed because of dependencies
|
||||
if (result.blockingDependencies) {
|
||||
// show the first dependent that caused this to fail in the warning message
|
||||
const diffEntryName = this.createName(diff.sourceValue ? diff.sourceValue : diff.targetValue);
|
||||
const firstDependentName = this.createName(result.blockingDependencies[0].sourceValue ? result.blockingDependencies[0].sourceValue : result.blockingDependencies[0].targetValue);
|
||||
let cannotExcludeMessage: string;
|
||||
let cannotIncludeMessage: string;
|
||||
if (firstDependentName) {
|
||||
cannotExcludeMessage = loc.cannotExcludeMessageDependent(diffEntryName, firstDependentName);
|
||||
cannotIncludeMessage = loc.cannotIncludeMessageDependent(diffEntryName, firstDependentName);
|
||||
} else {
|
||||
cannotExcludeMessage = loc.cannotExcludeMessage(diffEntryName);
|
||||
cannotIncludeMessage = loc.cannotIncludeMessage(diffEntryName);
|
||||
}
|
||||
vscode.window.showWarningMessage(checkboxState.checked ? cannotIncludeMessage : cannotExcludeMessage);
|
||||
} else {
|
||||
vscode.window.showWarningMessage(result.errorMessage);
|
||||
}
|
||||
|
||||
// set checkbox back to previous state
|
||||
checkboxesToChange.push({ row: checkboxState.row, column: checkboxState.column, columnName: 'Include', checked: !checkboxState.checked });
|
||||
}
|
||||
|
||||
if (checkboxesToChange.length > 0) {
|
||||
this.differencesTable.updateCells = checkboxesToChange;
|
||||
}
|
||||
}
|
||||
|
||||
// save state based on source name if present otherwise target name (parity with SSDT)
|
||||
private saveExcludeState(rowState: azdata.ICheckboxCellActionEventArgs) {
|
||||
if (rowState) {
|
||||
this.differencesTable.data[rowState.row][2] = rowState.checked;
|
||||
if (this.differencesTable.data[rowState.row]?.length > 2) {
|
||||
this.differencesTable.data[rowState.row][2] = rowState.checked;
|
||||
}
|
||||
let diff = this.comparisonResult.differences[rowState.row];
|
||||
let key = (diff.sourceValue && diff.sourceValue.length > 0) ? this.createName(diff.sourceValue) : this.createName(diff.targetValue);
|
||||
if (key) {
|
||||
@@ -647,7 +653,7 @@ export class SchemaCompareMainWindow {
|
||||
});
|
||||
}
|
||||
|
||||
private async cancelCompare() {
|
||||
public async cancelCompare() {
|
||||
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareCancelStarted')
|
||||
.withAdditionalProperties({
|
||||
@@ -691,28 +697,32 @@ export class SchemaCompareMainWindow {
|
||||
}).component();
|
||||
|
||||
this.generateScriptButton.onDidClick(async (click) => {
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareGenerateScriptStarted')
|
||||
.withAdditionalProperties({
|
||||
'startTime': Date.now().toString(),
|
||||
'operationId': this.comparisonResult.operationId
|
||||
}).send();
|
||||
const service = await this.getService();
|
||||
const result = await service.schemaCompareGenerateScript(this.comparisonResult.operationId, this.targetEndpointInfo.serverName, this.targetEndpointInfo.databaseName, azdata.TaskExecutionMode.script);
|
||||
if (!result || !result.success) {
|
||||
TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareGenerateScriptFailed', undefined, getTelemetryErrorType(result.errorMessage))
|
||||
.withAdditionalProperties({
|
||||
'operationId': this.comparisonResult.operationId
|
||||
}).send();
|
||||
vscode.window.showErrorMessage(loc.generateScriptErrorMessage(result.errorMessage));
|
||||
}
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareGenerateScriptEnded')
|
||||
.withAdditionalProperties({
|
||||
'endTime': Date.now().toString(),
|
||||
'operationId': this.comparisonResult.operationId
|
||||
}).send();
|
||||
await this.generateScript();
|
||||
});
|
||||
}
|
||||
|
||||
public async generateScript(): Promise<void> {
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareGenerateScriptStarted')
|
||||
.withAdditionalProperties({
|
||||
'startTime': Date.now().toString(),
|
||||
'operationId': this.comparisonResult.operationId
|
||||
}).send();
|
||||
const service = await this.getService();
|
||||
const result = await service.schemaCompareGenerateScript(this.comparisonResult.operationId, this.targetEndpointInfo.serverName, this.targetEndpointInfo.databaseName, azdata.TaskExecutionMode.script);
|
||||
if (!result || !result.success) {
|
||||
TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareGenerateScriptFailed', undefined, getTelemetryErrorType(result.errorMessage))
|
||||
.withAdditionalProperties({
|
||||
'operationId': this.comparisonResult.operationId
|
||||
}).send();
|
||||
vscode.window.showErrorMessage(loc.generateScriptErrorMessage(result.errorMessage));
|
||||
}
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareGenerateScriptEnded')
|
||||
.withAdditionalProperties({
|
||||
'endTime': Date.now().toString(),
|
||||
'operationId': this.comparisonResult.operationId
|
||||
}).send();
|
||||
}
|
||||
|
||||
private createOptionsButton(view: azdata.ModelView) {
|
||||
this.optionsButton = view.modelBuilder.button().withProperties({
|
||||
label: loc.options,
|
||||
@@ -741,43 +751,47 @@ export class SchemaCompareMainWindow {
|
||||
},
|
||||
}).component();
|
||||
|
||||
this.applyButton.onDidClick(async (click) => {
|
||||
await this.publishChanges();
|
||||
});
|
||||
}
|
||||
|
||||
public async publishChanges(): Promise<void> {
|
||||
|
||||
// need only yes button - since the modal dialog has a default cancel
|
||||
const yesString = loc.YesButtonText;
|
||||
this.applyButton.onDidClick(async (click) => {
|
||||
await vscode.window.showWarningMessage(loc.applyConfirmation, { modal: true }, yesString).then(async (result) => {
|
||||
if (result === yesString) {
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareApplyStarted')
|
||||
.withAdditionalProperties({
|
||||
'startTime': Date.now().toString(),
|
||||
'operationId': this.comparisonResult.operationId
|
||||
}).send();
|
||||
|
||||
vscode.window.showWarningMessage(loc.applyConfirmation, { modal: true }, yesString).then(async (result) => {
|
||||
if (result === yesString) {
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareApplyStarted')
|
||||
// disable apply and generate script buttons because the results are no longer valid after applying the changes
|
||||
this.setButtonsForRecompare();
|
||||
|
||||
const service = await this.getService();
|
||||
const result = await service.schemaComparePublishChanges(this.comparisonResult.operationId, this.targetEndpointInfo.serverName, this.targetEndpointInfo.databaseName, azdata.TaskExecutionMode.execute);
|
||||
if (!result || !result.success) {
|
||||
TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareApplyFailed', undefined, getTelemetryErrorType(result.errorMessage))
|
||||
.withAdditionalProperties({
|
||||
'startTime': Date.now().toString(),
|
||||
'operationId': this.comparisonResult.operationId
|
||||
}).send();
|
||||
vscode.window.showErrorMessage(loc.applyErrorMessage(result.errorMessage));
|
||||
|
||||
// disable apply and generate script buttons because the results are no longer valid after applying the changes
|
||||
this.setButtonsForRecompare();
|
||||
|
||||
const service = await this.getService();
|
||||
const result = await service.schemaComparePublishChanges(this.comparisonResult.operationId, this.targetEndpointInfo.serverName, this.targetEndpointInfo.databaseName, azdata.TaskExecutionMode.execute);
|
||||
if (!result || !result.success) {
|
||||
TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareApplyFailed', undefined, getTelemetryErrorType(result.errorMessage))
|
||||
.withAdditionalProperties({
|
||||
'operationId': this.comparisonResult.operationId
|
||||
}).send();
|
||||
vscode.window.showErrorMessage(loc.applyErrorMessage(result.errorMessage));
|
||||
|
||||
// reenable generate script and apply buttons if apply failed
|
||||
this.generateScriptButton.enabled = true;
|
||||
this.generateScriptButton.title = loc.generateScriptEnabledMessage;
|
||||
this.applyButton.enabled = true;
|
||||
this.applyButton.title = loc.applyEnabledMessage;
|
||||
}
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareApplyEnded')
|
||||
.withAdditionalProperties({
|
||||
'endTime': Date.now().toString(),
|
||||
'operationId': this.comparisonResult.operationId
|
||||
}).send();
|
||||
// reenable generate script and apply buttons if apply failed
|
||||
this.generateScriptButton.enabled = true;
|
||||
this.generateScriptButton.title = loc.generateScriptEnabledMessage;
|
||||
this.applyButton.enabled = true;
|
||||
this.applyButton.title = loc.applyEnabledMessage;
|
||||
}
|
||||
});
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareApplyEnded')
|
||||
.withAdditionalProperties({
|
||||
'endTime': Date.now().toString(),
|
||||
'operationId': this.comparisonResult.operationId
|
||||
}).send();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -922,60 +936,64 @@ export class SchemaCompareMainWindow {
|
||||
}).component();
|
||||
|
||||
this.openScmpButton.onDidClick(async (click) => {
|
||||
TelemetryReporter.sendActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareOpenScmpStarted');
|
||||
const rootPath = getRootPath();
|
||||
let fileUris = await vscode.window.showOpenDialog(
|
||||
{
|
||||
canSelectFiles: true,
|
||||
canSelectFolders: false,
|
||||
canSelectMany: false,
|
||||
defaultUri: vscode.Uri.file(rootPath),
|
||||
openLabel: loc.open,
|
||||
filters: {
|
||||
'scmp Files': ['scmp'],
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (!fileUris || fileUris.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let fileUri = fileUris[0];
|
||||
const service = await this.getService();
|
||||
let startTime = Date.now();
|
||||
const result = await service.schemaCompareOpenScmp(fileUri.fsPath);
|
||||
if (!result || !result.success) {
|
||||
TelemetryReporter.sendErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareOpenScmpFailed', undefined, getTelemetryErrorType(result.errorMessage));
|
||||
vscode.window.showErrorMessage(loc.openScmpErrorMessage(result.errorMessage));
|
||||
return;
|
||||
}
|
||||
|
||||
this.sourceEndpointInfo = await this.constructEndpointInfo(result.sourceEndpointInfo, loc.sourceTitle, this.apiWrapper);
|
||||
this.targetEndpointInfo = await this.constructEndpointInfo(result.targetEndpointInfo, loc.targetTitle, this.apiWrapper);
|
||||
|
||||
this.updateSourceAndTarget();
|
||||
this.setDeploymentOptions(result.deploymentOptions);
|
||||
this.scmpSourceExcludes = result.excludedSourceElements;
|
||||
this.scmpTargetExcludes = result.excludedTargetElements;
|
||||
this.sourceTargetSwitched = result.originalTargetName !== this.targetEndpointInfo.databaseName;
|
||||
|
||||
// clear out any old results
|
||||
this.resetForNewCompare();
|
||||
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareOpenScmpEnded')
|
||||
.withAdditionalProperties({
|
||||
elapsedTime: (Date.now() - startTime).toString()
|
||||
}).send();
|
||||
await this.openScmp();
|
||||
});
|
||||
}
|
||||
|
||||
private async constructEndpointInfo(endpoint: mssql.SchemaCompareEndpointInfo, caller: string, apiWrapper: ApiWrapper): Promise<mssql.SchemaCompareEndpointInfo> {
|
||||
public async openScmp(): Promise<void> {
|
||||
TelemetryReporter.sendActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareOpenScmpStarted');
|
||||
const rootPath = getRootPath();
|
||||
let fileUris = await vscode.window.showOpenDialog(
|
||||
{
|
||||
canSelectFiles: true,
|
||||
canSelectFolders: false,
|
||||
canSelectMany: false,
|
||||
defaultUri: vscode.Uri.file(rootPath),
|
||||
openLabel: loc.open,
|
||||
filters: {
|
||||
'scmp Files': ['scmp'],
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (!fileUris || fileUris.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
let fileUri = fileUris[0];
|
||||
const service = await this.getService();
|
||||
let startTime = Date.now();
|
||||
const result = await service.schemaCompareOpenScmp(fileUri.fsPath);
|
||||
if (!result || !result.success) {
|
||||
TelemetryReporter.sendErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareOpenScmpFailed', undefined, getTelemetryErrorType(result.errorMessage));
|
||||
vscode.window.showErrorMessage(loc.openScmpErrorMessage(result.errorMessage));
|
||||
return;
|
||||
}
|
||||
|
||||
this.sourceEndpointInfo = await this.constructEndpointInfo(result.sourceEndpointInfo, loc.sourceTitle);
|
||||
this.targetEndpointInfo = await this.constructEndpointInfo(result.targetEndpointInfo, loc.targetTitle);
|
||||
|
||||
this.updateSourceAndTarget();
|
||||
this.setDeploymentOptions(result.deploymentOptions);
|
||||
this.scmpSourceExcludes = result.excludedSourceElements;
|
||||
this.scmpTargetExcludes = result.excludedTargetElements;
|
||||
this.sourceTargetSwitched = result.originalTargetName !== this.targetEndpointInfo.databaseName;
|
||||
|
||||
// clear out any old results
|
||||
this.resetForNewCompare();
|
||||
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareOpenScmpEnded')
|
||||
.withAdditionalProperties({
|
||||
elapsedTime: (Date.now() - startTime).toString()
|
||||
}).send();
|
||||
}
|
||||
|
||||
private async constructEndpointInfo(endpoint: mssql.SchemaCompareEndpointInfo, caller: string): Promise<mssql.SchemaCompareEndpointInfo> {
|
||||
let ownerUri;
|
||||
let endpointInfo;
|
||||
if (endpoint && endpoint.endpointType === mssql.SchemaCompareEndpointType.Database) {
|
||||
// only set endpoint info if able to connect to the database
|
||||
ownerUri = await verifyConnectionAndGetOwnerUri(endpoint, caller, apiWrapper);
|
||||
ownerUri = await verifyConnectionAndGetOwnerUri(endpoint, caller);
|
||||
}
|
||||
if (ownerUri) {
|
||||
endpointInfo = endpoint;
|
||||
@@ -1007,44 +1025,48 @@ export class SchemaCompareMainWindow {
|
||||
}).component();
|
||||
|
||||
this.saveScmpButton.onDidClick(async (click) => {
|
||||
const rootPath = getRootPath();
|
||||
const filePath = await vscode.window.showSaveDialog(
|
||||
{
|
||||
defaultUri: vscode.Uri.file(rootPath),
|
||||
saveLabel: loc.save,
|
||||
filters: {
|
||||
'scmp Files': ['scmp'],
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (!filePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
// convert include/exclude maps to arrays of object ids
|
||||
let sourceExcludes: mssql.SchemaCompareObjectId[] = this.convertExcludesToObjectIds(this.originalSourceExcludes);
|
||||
let targetExcludes: mssql.SchemaCompareObjectId[] = this.convertExcludesToObjectIds(this.originalTargetExcludes);
|
||||
|
||||
let startTime = Date.now();
|
||||
TelemetryReporter.sendActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareSaveScmp');
|
||||
const service = await this.getService();
|
||||
const result = await service.schemaCompareSaveScmp(this.sourceEndpointInfo, this.targetEndpointInfo, azdata.TaskExecutionMode.execute, this.deploymentOptions, filePath.fsPath, sourceExcludes, targetExcludes);
|
||||
if (!result || !result.success) {
|
||||
TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareSaveScmpFailed', undefined, getTelemetryErrorType(result.errorMessage))
|
||||
.withAdditionalProperties({
|
||||
operationId: this.comparisonResult.operationId
|
||||
}).send();
|
||||
vscode.window.showErrorMessage(loc.saveScmpErrorMessage(result.errorMessage));
|
||||
}
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareSaveScmpEnded')
|
||||
.withAdditionalProperties({
|
||||
elapsedTime: (Date.now() - startTime).toString(),
|
||||
operationId: this.comparisonResult.operationId
|
||||
});
|
||||
await this.saveScmp();
|
||||
});
|
||||
}
|
||||
|
||||
public async saveScmp(): Promise<void> {
|
||||
const rootPath = getRootPath();
|
||||
const filePath = await vscode.window.showSaveDialog(
|
||||
{
|
||||
defaultUri: vscode.Uri.file(rootPath),
|
||||
saveLabel: loc.save,
|
||||
filters: {
|
||||
'scmp Files': ['scmp'],
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (!filePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
// convert include/exclude maps to arrays of object ids
|
||||
let sourceExcludes: mssql.SchemaCompareObjectId[] = this.convertExcludesToObjectIds(this.originalSourceExcludes);
|
||||
let targetExcludes: mssql.SchemaCompareObjectId[] = this.convertExcludesToObjectIds(this.originalTargetExcludes);
|
||||
|
||||
let startTime = Date.now();
|
||||
TelemetryReporter.sendActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareSaveScmp');
|
||||
const service = await this.getService();
|
||||
const result = await service.schemaCompareSaveScmp(this.sourceEndpointInfo, this.targetEndpointInfo, azdata.TaskExecutionMode.execute, this.deploymentOptions, filePath.fsPath, sourceExcludes, targetExcludes);
|
||||
if (!result || !result.success) {
|
||||
TelemetryReporter.createErrorEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareSaveScmpFailed', undefined, getTelemetryErrorType(result.errorMessage))
|
||||
.withAdditionalProperties({
|
||||
operationId: this.comparisonResult.operationId
|
||||
}).send();
|
||||
vscode.window.showErrorMessage(loc.saveScmpErrorMessage(result.errorMessage));
|
||||
}
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.SchemaCompareMainWindow, 'SchemaCompareSaveScmpEnded')
|
||||
.withAdditionalProperties({
|
||||
elapsedTime: (Date.now() - startTime).toString(),
|
||||
operationId: this.comparisonResult.operationId
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts excluded diff entries into object ids which are needed to save them in an scmp
|
||||
*/
|
||||
@@ -1071,7 +1093,7 @@ export class SchemaCompareMainWindow {
|
||||
}
|
||||
|
||||
private async getService(): Promise<mssql.ISchemaCompareService> {
|
||||
if (isNullOrUndefined(this.schemaCompareService)) {
|
||||
if (this.schemaCompareService === null || this.schemaCompareService === undefined) {
|
||||
this.schemaCompareService = (vscode.extensions.getExtension(mssql.extension.name).exports as mssql.IExtension).schemaCompare;
|
||||
}
|
||||
return this.schemaCompareService;
|
||||
|
||||
@@ -4,13 +4,12 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as should from 'should';
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import * as mssql from '../../../mssql';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as loc from '../localizedConstants';
|
||||
import 'mocha';
|
||||
import { SchemaCompareDialog } from './../dialogs/schemaCompareDialog';
|
||||
import * as sinon from 'sinon';
|
||||
import { SchemaCompareMainWindow } from '../schemaCompareMainWindow';
|
||||
import { SchemaCompareTestService, testStateScmp } from './testSchemaCompareService';
|
||||
import { createContext, TestContext } from './testContext';
|
||||
@@ -28,15 +27,24 @@ before(function (): void {
|
||||
testContext = createContext();
|
||||
});
|
||||
|
||||
afterEach(function (): void {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
describe('SchemaCompareMainWindow.start', function (): void {
|
||||
before(() => {
|
||||
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
|
||||
mockExtensionContext.setup(x => x.extensionPath).returns(() => '');
|
||||
});
|
||||
|
||||
this.afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it('Should be correct when created.', async function (): Promise<void> {
|
||||
let sc = new SchemaCompareTestService();
|
||||
|
||||
let result = new SchemaCompareMainWindowTest(testContext.apiWrapper.object, sc, mockExtensionContext.object);
|
||||
let result = new SchemaCompareMainWindowTest(sc, mockExtensionContext.object);
|
||||
await result.start(undefined);
|
||||
|
||||
should(result.getComparisonResult() === undefined);
|
||||
@@ -52,7 +60,7 @@ describe('SchemaCompareMainWindow.start', function (): void {
|
||||
it('Should start with the source as undefined', async function (): Promise<void> {
|
||||
let sc = new SchemaCompareTestService();
|
||||
|
||||
let result = new SchemaCompareMainWindowTest(testContext.apiWrapper.object, sc, mockExtensionContext.object);
|
||||
let result = new SchemaCompareMainWindowTest(sc, mockExtensionContext.object);
|
||||
await result.start(undefined);
|
||||
|
||||
should.equal(result.sourceEndpointInfo, undefined);
|
||||
@@ -62,8 +70,8 @@ describe('SchemaCompareMainWindow.start', function (): void {
|
||||
it('Should start with the source as database', async function (): Promise<void> {
|
||||
let sc = new SchemaCompareTestService();
|
||||
|
||||
let result = new SchemaCompareMainWindowTest(testContext.apiWrapper.object, sc, mockExtensionContext.object);
|
||||
await result.start({connectionProfile: mockIConnectionProfile});
|
||||
let result = new SchemaCompareMainWindowTest(sc, mockExtensionContext.object);
|
||||
await result.start({ connectionProfile: mockIConnectionProfile });
|
||||
|
||||
should.notEqual(result.sourceEndpointInfo, undefined);
|
||||
should.equal(result.sourceEndpointInfo.endpointType, mssql.SchemaCompareEndpointType.Database);
|
||||
@@ -75,7 +83,7 @@ describe('SchemaCompareMainWindow.start', function (): void {
|
||||
it('Should start with the source as dacpac.', async function (): Promise<void> {
|
||||
let sc = new SchemaCompareTestService();
|
||||
|
||||
let result = new SchemaCompareMainWindowTest(testContext.apiWrapper.object, sc, mockExtensionContext.object);
|
||||
let result = new SchemaCompareMainWindowTest(sc, mockExtensionContext.object);
|
||||
const dacpacPath = mockFilePath;
|
||||
await result.start(dacpacPath);
|
||||
|
||||
@@ -85,7 +93,287 @@ describe('SchemaCompareMainWindow.start', function (): void {
|
||||
should.equal(result.targetEndpointInfo, undefined);
|
||||
});
|
||||
});
|
||||
let showErrorMessageSpy: any;
|
||||
let showWarningMessageStub: any;
|
||||
let showOpenDialogStub: any;
|
||||
|
||||
describe('SchemaCompareMainWindow.results', function (): void {
|
||||
before(() => {
|
||||
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
|
||||
mockExtensionContext.setup(x => x.extensionPath).returns(() => '');
|
||||
});
|
||||
|
||||
this.afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
this.beforeEach(() => {
|
||||
sinon.restore();
|
||||
showErrorMessageSpy = sinon.spy(vscode.window, 'showErrorMessage');
|
||||
});
|
||||
|
||||
it('Should show error if publish changes fails', async function (): Promise<void> {
|
||||
let service = createServiceMock();
|
||||
service.setup(x => x.schemaComparePublishChanges(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({
|
||||
success: false,
|
||||
errorMessage: 'error1'
|
||||
}));
|
||||
|
||||
showWarningMessageStub = sinon.stub(vscode.window, 'showWarningMessage').returns(<any>Promise.resolve('Yes'));
|
||||
|
||||
let schemaCompareResult = new SchemaCompareMainWindow(service.object, mockExtensionContext.object);
|
||||
await schemaCompareResult.start(undefined);
|
||||
|
||||
schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource);
|
||||
schemaCompareResult.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
|
||||
await schemaCompareResult.execute();
|
||||
await schemaCompareResult.publishChanges();
|
||||
|
||||
should(showErrorMessageSpy.calledOnce).be.true();
|
||||
should.equal(showErrorMessageSpy.getCall(0).args[0], loc.applyErrorMessage('error1'));
|
||||
});
|
||||
|
||||
it('Should show not error if publish changes succeed', async function (): Promise<void> {
|
||||
let service = createServiceMock();
|
||||
service.setup(x => x.schemaComparePublishChanges(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({
|
||||
success: true,
|
||||
errorMessage: ''
|
||||
}));
|
||||
showWarningMessageStub = sinon.stub(vscode.window, 'showWarningMessage').returns(<any>Promise.resolve('Yes'));
|
||||
let schemaCompareResult = new SchemaCompareMainWindow(service.object, mockExtensionContext.object);
|
||||
await schemaCompareResult.start(undefined);
|
||||
|
||||
schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource);
|
||||
schemaCompareResult.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
|
||||
await schemaCompareResult.execute();
|
||||
await schemaCompareResult.publishChanges();
|
||||
should(showErrorMessageSpy.notCalled).be.true();
|
||||
});
|
||||
|
||||
it('Should show error if openScmp fails', async function (): Promise<void> {
|
||||
let service = createServiceMock();
|
||||
let files: vscode.Uri[] = [vscode.Uri.parse('file:///test')];
|
||||
service.setup(x => x.schemaCompareOpenScmp(TypeMoq.It.isAny())).returns(() => Promise.resolve({
|
||||
sourceEndpointInfo: undefined,
|
||||
targetEndpointInfo: undefined,
|
||||
originalTargetName: 'string',
|
||||
originalConnectionString: '',
|
||||
deploymentOptions: undefined,
|
||||
excludedSourceElements: [],
|
||||
excludedTargetElements: [],
|
||||
success: false,
|
||||
errorMessage: 'error1'
|
||||
}));
|
||||
|
||||
showWarningMessageStub = sinon.stub(vscode.window, 'showWarningMessage').returns(<any>Promise.resolve('Yes'));
|
||||
showOpenDialogStub = sinon.stub(vscode.window, 'showOpenDialog').returns(<any>Promise.resolve(files));
|
||||
|
||||
let schemaCompareResult = new SchemaCompareMainWindow(service.object, mockExtensionContext.object);
|
||||
await schemaCompareResult.start(undefined);
|
||||
|
||||
schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource);
|
||||
schemaCompareResult.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
|
||||
await schemaCompareResult.openScmp();
|
||||
|
||||
should(showErrorMessageSpy.calledOnce).be.true();
|
||||
should.equal(showErrorMessageSpy.getCall(0).args[0], loc.openScmpErrorMessage('error1'));
|
||||
});
|
||||
|
||||
it('Should show error if saveScmp fails', async function (): Promise<void> {
|
||||
let service = createServiceMock();
|
||||
let file: vscode.Uri = vscode.Uri.parse('file:///test');
|
||||
service.setup(x => x.schemaCompareSaveScmp(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({
|
||||
sourceEndpointInfo: undefined,
|
||||
targetEndpointInfo: undefined,
|
||||
originalTargetName: 'string',
|
||||
originalConnectionString: '',
|
||||
deploymentOptions: undefined,
|
||||
excludedSourceElements: [],
|
||||
excludedTargetElements: [],
|
||||
success: false,
|
||||
errorMessage: 'error1'
|
||||
}));
|
||||
|
||||
showWarningMessageStub = sinon.stub(vscode.window, 'showWarningMessage').returns(<any>Promise.resolve('Yes'));
|
||||
showOpenDialogStub = sinon.stub(vscode.window, 'showSaveDialog').returns(<any>Promise.resolve(file));
|
||||
let schemaCompareResult = new SchemaCompareMainWindow(service.object, mockExtensionContext.object);
|
||||
await schemaCompareResult.start(undefined);
|
||||
|
||||
schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource);
|
||||
schemaCompareResult.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
|
||||
await schemaCompareResult.execute();
|
||||
await schemaCompareResult.saveScmp();
|
||||
|
||||
should(showErrorMessageSpy.calledOnce).be.true();
|
||||
should.equal(showErrorMessageSpy.getCall(0).args[0], loc.saveScmpErrorMessage('error1'));
|
||||
});
|
||||
|
||||
|
||||
it('Should show error if generateScript fails', async function (): Promise<void> {
|
||||
let service = createServiceMock();
|
||||
service.setup(x => x.schemaCompareGenerateScript(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({
|
||||
success: false,
|
||||
errorMessage: 'error1'
|
||||
}));
|
||||
|
||||
showWarningMessageStub = sinon.stub(vscode.window, 'showWarningMessage').returns(<any>Promise.resolve('Yes'));
|
||||
let schemaCompareResult = new SchemaCompareMainWindow(service.object, mockExtensionContext.object);
|
||||
await schemaCompareResult.start(undefined);
|
||||
|
||||
schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource);
|
||||
schemaCompareResult.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
|
||||
await schemaCompareResult.execute();
|
||||
await schemaCompareResult.generateScript();
|
||||
|
||||
should(showErrorMessageSpy.calledOnce).be.true();
|
||||
should.equal(showErrorMessageSpy.getCall(0).args[0], loc.generateScriptErrorMessage('error1'));
|
||||
});
|
||||
|
||||
it('Should show error if cancel fails', async function (): Promise<void> {
|
||||
let service = createServiceMock();
|
||||
service.setup(x => x.schemaCompareCancel(TypeMoq.It.isAny())).returns(() => Promise.resolve({
|
||||
success: false,
|
||||
errorMessage: 'error1'
|
||||
}));
|
||||
|
||||
showWarningMessageStub = sinon.stub(vscode.window, 'showWarningMessage').returns(<any>Promise.resolve('Yes'));
|
||||
let schemaCompareResult = new SchemaCompareMainWindow(service.object, mockExtensionContext.object);
|
||||
await schemaCompareResult.start(undefined);
|
||||
|
||||
schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource);
|
||||
schemaCompareResult.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
|
||||
await schemaCompareResult.execute();
|
||||
await schemaCompareResult.cancelCompare();
|
||||
|
||||
should(showErrorMessageSpy.calledOnce).be.true();
|
||||
should.equal(showErrorMessageSpy.getCall(0).args[0], loc.cancelErrorMessage('error1'));
|
||||
});
|
||||
|
||||
it('Should show error if IncludeExcludeNode fails', async function (): Promise<void> {
|
||||
let service = createServiceMock();
|
||||
service.setup(x => x.schemaCompareIncludeExcludeNode(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({
|
||||
success: false,
|
||||
errorMessage: '',
|
||||
affectedDependencies: [],
|
||||
blockingDependencies: [{
|
||||
updateAction: 2,
|
||||
differenceType: 0,
|
||||
name: 'SqlTable',
|
||||
sourceValue: ['dbo', 'table1'],
|
||||
targetValue: null,
|
||||
parent: null,
|
||||
children: [{
|
||||
updateAction: 2,
|
||||
differenceType: 0,
|
||||
name: 'SqlSimpleColumn',
|
||||
sourceValue: ['dbo', 'table1', 'id'],
|
||||
targetValue: null,
|
||||
parent: null,
|
||||
children: [],
|
||||
sourceScript: '',
|
||||
targetScript: null,
|
||||
included: false
|
||||
}],
|
||||
sourceScript: 'CREATE TABLE [dbo].[table1](id int)',
|
||||
targetScript: null,
|
||||
included: true
|
||||
}]
|
||||
}));
|
||||
|
||||
showWarningMessageStub = sinon.stub(vscode.window, 'showWarningMessage').returns(<any>Promise.resolve(''));
|
||||
let schemaCompareResult = new SchemaCompareMainWindow(service.object, mockExtensionContext.object);
|
||||
await schemaCompareResult.start(undefined);
|
||||
|
||||
schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource);
|
||||
schemaCompareResult.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
|
||||
await schemaCompareResult.execute();
|
||||
await schemaCompareResult.applyIncludeExclude({
|
||||
row: 0,
|
||||
column: 0,
|
||||
columnName: 1,
|
||||
checked: true
|
||||
});
|
||||
|
||||
should(showWarningMessageStub.calledOnce).be.true();
|
||||
});
|
||||
|
||||
it('Should not show warning if IncludeExcludeNode succeed', async function (): Promise<void> {
|
||||
let service = createServiceMock();
|
||||
service.setup(x => x.schemaCompareIncludeExcludeNode(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({
|
||||
success: true,
|
||||
errorMessage: '',
|
||||
affectedDependencies: [],
|
||||
blockingDependencies: [{
|
||||
updateAction: 2,
|
||||
differenceType: 0,
|
||||
name: 'SqlTable',
|
||||
sourceValue: ['dbo', 'table1'],
|
||||
targetValue: null,
|
||||
parent: null,
|
||||
children: [{
|
||||
updateAction: 2,
|
||||
differenceType: 0,
|
||||
name: 'SqlSimpleColumn',
|
||||
sourceValue: ['dbo', 'table1', 'id'],
|
||||
targetValue: null,
|
||||
parent: null,
|
||||
children: [],
|
||||
sourceScript: '',
|
||||
targetScript: null,
|
||||
included: false
|
||||
}],
|
||||
sourceScript: 'CREATE TABLE [dbo].[table1](id int)',
|
||||
targetScript: null,
|
||||
included: true
|
||||
}]
|
||||
}));
|
||||
|
||||
showWarningMessageStub = sinon.stub(vscode.window, 'showWarningMessage').returns(<any>Promise.resolve(''));
|
||||
let schemaCompareResult = new SchemaCompareMainWindow(service.object, mockExtensionContext.object);
|
||||
await schemaCompareResult.start(undefined);
|
||||
|
||||
schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource);
|
||||
schemaCompareResult.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
|
||||
await schemaCompareResult.execute();
|
||||
await schemaCompareResult.applyIncludeExclude({
|
||||
row: 0,
|
||||
column: 0,
|
||||
columnName: 1,
|
||||
checked: false
|
||||
});
|
||||
|
||||
should(showWarningMessageStub.notCalled).be.true();
|
||||
});
|
||||
|
||||
it('Should not show error if user does not want to publish', async function (): Promise<void> {
|
||||
let service = createServiceMock();
|
||||
service.setup(x => x.schemaComparePublishChanges(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve({
|
||||
success: true,
|
||||
errorMessage: ''
|
||||
}));
|
||||
|
||||
showWarningMessageStub = sinon.stub(vscode.window, 'showWarningMessage').returns(<any>Promise.resolve('No'));
|
||||
let schemaCompareResult = new SchemaCompareMainWindow(service.object, mockExtensionContext.object);
|
||||
await schemaCompareResult.start(undefined);
|
||||
|
||||
schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource);
|
||||
schemaCompareResult.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
|
||||
await schemaCompareResult.execute();
|
||||
await schemaCompareResult.publishChanges();
|
||||
|
||||
should(showErrorMessageSpy.notCalled).be.true();
|
||||
});
|
||||
|
||||
function createServiceMock() {
|
||||
let sc = new SchemaCompareTestService(testStateScmp.SUCCESS_NOT_EQUAL);
|
||||
let service = TypeMoq.Mock.ofInstance(new SchemaCompareTestService());
|
||||
service.setup(x => x.schemaCompareGetDefaultOptions()).returns(x => sc.schemaCompareGetDefaultOptions());
|
||||
service.setup(x => x.schemaCompare(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => sc.schemaCompare('', undefined, undefined, undefined, undefined));
|
||||
return service;
|
||||
}
|
||||
});
|
||||
|
||||
let showErrorMessageStub: any;
|
||||
describe('SchemaCompareMainWindow.execute', function (): void {
|
||||
before(() => {
|
||||
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
|
||||
@@ -93,16 +381,22 @@ describe('SchemaCompareMainWindow.execute', function (): void {
|
||||
testContext = createContext();
|
||||
});
|
||||
|
||||
beforeEach(function (): void {
|
||||
testContext.apiWrapper.reset();
|
||||
this.afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
this.beforeEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it('Should fail for failing Schema Compare service', async function (): Promise<void> {
|
||||
let sc = new SchemaCompareTestService(testStateScmp.FAILURE);
|
||||
|
||||
testContext.apiWrapper.setup(x => x.showErrorMessage(TypeMoq.It.isAny())).returns((s) => { throw new Error(s); });
|
||||
let result = new SchemaCompareMainWindowTest(testContext.apiWrapper.object, sc, mockExtensionContext.object);
|
||||
showErrorMessageStub = sinon.stub(vscode.window, 'showErrorMessage').callsFake((message) => {
|
||||
throw new Error(message);
|
||||
});
|
||||
|
||||
let result = new SchemaCompareMainWindowTest(sc, mockExtensionContext.object);
|
||||
await result.start(undefined);
|
||||
|
||||
should(result.getComparisonResult() === undefined);
|
||||
@@ -116,8 +410,7 @@ describe('SchemaCompareMainWindow.execute', function (): void {
|
||||
it('Should exit for failing Schema Compare service', async function (): Promise<void> {
|
||||
let sc = new SchemaCompareTestService(testStateScmp.FAILURE);
|
||||
|
||||
testContext.apiWrapper.setup(x => x.showErrorMessage(TypeMoq.It.isAny())).returns(() => Promise.resolve(''));
|
||||
let result = new SchemaCompareMainWindowTest(testContext.apiWrapper.object, sc, mockExtensionContext.object);
|
||||
let result = new SchemaCompareMainWindowTest(sc, mockExtensionContext.object);
|
||||
|
||||
await result.start(undefined);
|
||||
|
||||
@@ -127,13 +420,12 @@ describe('SchemaCompareMainWindow.execute', function (): void {
|
||||
result.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
|
||||
|
||||
await result.execute();
|
||||
testContext.apiWrapper.verify(x => x.showErrorMessage(TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
});
|
||||
|
||||
it('Should disable script button and apply button for Schema Compare service for dacpac', async function (): Promise<void> {
|
||||
let sc = new SchemaCompareTestService(testStateScmp.SUCCESS_NOT_EQUAL);
|
||||
|
||||
let result = new SchemaCompareMainWindowTest(testContext.apiWrapper.object, sc, mockExtensionContext.object);
|
||||
let result = new SchemaCompareMainWindowTest(sc, mockExtensionContext.object);
|
||||
|
||||
await result.start(undefined);
|
||||
|
||||
@@ -145,7 +437,7 @@ describe('SchemaCompareMainWindow.execute', function (): void {
|
||||
await result.execute();
|
||||
|
||||
//Generate script button and apply button should be disabled for dacpac comparison
|
||||
result.verifyButtonsState( {
|
||||
result.verifyButtonsState({
|
||||
compareButtonState: true,
|
||||
optionsButtonState: true,
|
||||
switchButtonState: true,
|
||||
@@ -156,13 +448,13 @@ describe('SchemaCompareMainWindow.execute', function (): void {
|
||||
selectTargetButtonState: true,
|
||||
generateScriptButtonState: false,
|
||||
applyButtonState: false
|
||||
} );
|
||||
});
|
||||
});
|
||||
|
||||
it('Should disable script button and apply button for Schema Compare service for database', async function (): Promise<void> {
|
||||
let sc = new SchemaCompareTestService(testStateScmp.SUCCESS_NOT_EQUAL);
|
||||
|
||||
let result = new SchemaCompareMainWindowTest(testContext.apiWrapper.object, sc, mockExtensionContext.object);
|
||||
let result = new SchemaCompareMainWindowTest(sc, mockExtensionContext.object);
|
||||
|
||||
await result.start(undefined);
|
||||
|
||||
@@ -174,7 +466,7 @@ describe('SchemaCompareMainWindow.execute', function (): void {
|
||||
await result.execute();
|
||||
|
||||
//Generate script button and apply button should be enabled for database comparison
|
||||
result.verifyButtonsState( {
|
||||
result.verifyButtonsState({
|
||||
compareButtonState: true,
|
||||
optionsButtonState: true,
|
||||
switchButtonState: true,
|
||||
@@ -185,7 +477,7 @@ describe('SchemaCompareMainWindow.execute', function (): void {
|
||||
selectTargetButtonState: true,
|
||||
generateScriptButtonState: true,
|
||||
applyButtonState: true
|
||||
} );
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -201,18 +493,18 @@ describe('SchemaCompareMainWindow.updateSourceAndTarget', function (): void {
|
||||
let sc = new SchemaCompareTestService();
|
||||
let endpointInfo: mssql.SchemaCompareEndpointInfo;
|
||||
|
||||
let result = new SchemaCompareMainWindowTest(testContext.apiWrapper.object, sc, mockExtensionContext.object);
|
||||
let result = new SchemaCompareMainWindowTest(sc, mockExtensionContext.object);
|
||||
|
||||
await result.start(undefined);
|
||||
|
||||
should(result.getComparisonResult() === undefined);
|
||||
|
||||
result.sourceEndpointInfo = {...endpointInfo};
|
||||
result.targetEndpointInfo = {...endpointInfo};
|
||||
result.sourceEndpointInfo = { ...endpointInfo };
|
||||
result.targetEndpointInfo = { ...endpointInfo };
|
||||
|
||||
result.updateSourceAndTarget();
|
||||
|
||||
result.verifyButtonsState( {
|
||||
result.verifyButtonsState({
|
||||
compareButtonState: false,
|
||||
optionsButtonState: false,
|
||||
switchButtonState: false,
|
||||
@@ -223,25 +515,25 @@ describe('SchemaCompareMainWindow.updateSourceAndTarget', function (): void {
|
||||
selectTargetButtonState: true,
|
||||
generateScriptButtonState: false,
|
||||
applyButtonState: false
|
||||
} );
|
||||
});
|
||||
});
|
||||
|
||||
it('Should set buttons appropriately when source endpoint is empty and target endpoint is populated', async function (): Promise<void> {
|
||||
let sc = new SchemaCompareTestService();
|
||||
let endpointInfo: mssql.SchemaCompareEndpointInfo;
|
||||
|
||||
let result = new SchemaCompareMainWindowTest(testContext.apiWrapper.object, sc, mockExtensionContext.object);
|
||||
let result = new SchemaCompareMainWindowTest(sc, mockExtensionContext.object);
|
||||
|
||||
await result.start(undefined);
|
||||
|
||||
should(result.getComparisonResult() === undefined);
|
||||
|
||||
result.sourceEndpointInfo = {...endpointInfo};
|
||||
result.sourceEndpointInfo = { ...endpointInfo };
|
||||
result.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
|
||||
|
||||
result.updateSourceAndTarget();
|
||||
|
||||
result.verifyButtonsState( {
|
||||
result.verifyButtonsState({
|
||||
compareButtonState: false,
|
||||
optionsButtonState: false,
|
||||
switchButtonState: true,
|
||||
@@ -252,14 +544,14 @@ describe('SchemaCompareMainWindow.updateSourceAndTarget', function (): void {
|
||||
selectTargetButtonState: true,
|
||||
generateScriptButtonState: false,
|
||||
applyButtonState: false
|
||||
} );
|
||||
});
|
||||
});
|
||||
|
||||
it('Should set buttons appropriately when source and target endpoints are populated', async function (): Promise<void> {
|
||||
let sc = new SchemaCompareTestService();
|
||||
let endpointInfo: mssql.SchemaCompareEndpointInfo;
|
||||
|
||||
let result = new SchemaCompareMainWindowTest(testContext.apiWrapper.object, sc, mockExtensionContext.object);
|
||||
let result = new SchemaCompareMainWindowTest(sc, mockExtensionContext.object);
|
||||
|
||||
await result.start(undefined);
|
||||
|
||||
@@ -270,7 +562,7 @@ describe('SchemaCompareMainWindow.updateSourceAndTarget', function (): void {
|
||||
|
||||
result.updateSourceAndTarget();
|
||||
|
||||
result.verifyButtonsState( {
|
||||
result.verifyButtonsState({
|
||||
compareButtonState: true,
|
||||
optionsButtonState: true,
|
||||
switchButtonState: true,
|
||||
@@ -281,7 +573,7 @@ describe('SchemaCompareMainWindow.updateSourceAndTarget', function (): void {
|
||||
selectTargetButtonState: true,
|
||||
generateScriptButtonState: false,
|
||||
applyButtonState: false
|
||||
} );
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -32,7 +32,7 @@ describe('SchemaCompareDialog.openDialog', function (): void {
|
||||
});
|
||||
|
||||
it('Should be correct when created.', async function (): Promise<void> {
|
||||
let schemaCompareResult = new SchemaCompareMainWindow(testContext.apiWrapper.object, undefined, mockExtensionContext.object);
|
||||
let schemaCompareResult = new SchemaCompareMainWindow(undefined, mockExtensionContext.object);
|
||||
let dialog = new SchemaCompareDialog(schemaCompareResult);
|
||||
await dialog.openDialog();
|
||||
|
||||
@@ -42,7 +42,7 @@ describe('SchemaCompareDialog.openDialog', function (): void {
|
||||
});
|
||||
|
||||
it('Simulate ok button- with both endpoints set to dacpac', async function (): Promise<void> {
|
||||
let schemaCompareResult = new SchemaCompareMainWindowTest(testContext.apiWrapper.object, undefined, mockExtensionContext.object);
|
||||
let schemaCompareResult = new SchemaCompareMainWindowTest(undefined, mockExtensionContext.object);
|
||||
await schemaCompareResult.start(undefined);
|
||||
schemaCompareResult.sourceEndpointInfo = setDacpacEndpointInfo(mocksource);
|
||||
schemaCompareResult.targetEndpointInfo = setDacpacEndpointInfo(mocktarget);
|
||||
@@ -53,7 +53,7 @@ describe('SchemaCompareDialog.openDialog', function (): void {
|
||||
await dialog.execute();
|
||||
|
||||
// Confirm that ok button got clicked
|
||||
schemaCompareResult.verifyButtonsState( {
|
||||
schemaCompareResult.verifyButtonsState({
|
||||
compareButtonState: true,
|
||||
optionsButtonState: true,
|
||||
switchButtonState: true,
|
||||
@@ -64,6 +64,6 @@ describe('SchemaCompareDialog.openDialog', function (): void {
|
||||
selectTargetButtonState: true,
|
||||
generateScriptButtonState: false,
|
||||
applyButtonState: false
|
||||
} );
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,11 +5,8 @@
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import { ApiWrapper } from '../common/apiWrapper';
|
||||
|
||||
export interface TestContext {
|
||||
apiWrapper: TypeMoq.IMock<ApiWrapper>;
|
||||
context: vscode.ExtensionContext;
|
||||
}
|
||||
|
||||
@@ -17,7 +14,6 @@ export function createContext(): TestContext {
|
||||
let extensionPath = path.join(__dirname, '..', '..');
|
||||
|
||||
return {
|
||||
apiWrapper: TypeMoq.Mock.ofType(ApiWrapper),
|
||||
context: {
|
||||
subscriptions: [],
|
||||
workspaceState: {
|
||||
|
||||
@@ -7,7 +7,6 @@ import * as vscode from 'vscode';
|
||||
import * as mssql from '../../../mssql';
|
||||
import * as should from 'should';
|
||||
import { SchemaCompareMainWindow } from '../schemaCompareMainWindow';
|
||||
import { ApiWrapper } from '../common/apiWrapper';
|
||||
|
||||
export interface ButtonState {
|
||||
compareButtonState: boolean;
|
||||
@@ -24,10 +23,9 @@ export interface ButtonState {
|
||||
export class SchemaCompareMainWindowTest extends SchemaCompareMainWindow {
|
||||
|
||||
constructor(
|
||||
apiWrapper: ApiWrapper,
|
||||
schemaCompareService: mssql.ISchemaCompareService,
|
||||
extensionContext: vscode.ExtensionContext) {
|
||||
super(apiWrapper, schemaCompareService, extensionContext);
|
||||
super(schemaCompareService, extensionContext);
|
||||
}
|
||||
|
||||
// only for test
|
||||
|
||||
@@ -47,7 +47,7 @@ export class SchemaCompareTestService implements mssql.ISchemaCompareService {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
schemaCompare(operationId: string, sourceEndpointInfo: mssql.SchemaCompareEndpointInfo, targetEndpointInfo: mssql.SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode): Thenable<mssql.SchemaCompareResult> {
|
||||
schemaCompare(operationId: string, sourceEndpointInfo: mssql.SchemaCompareEndpointInfo, targetEndpointInfo: mssql.SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode, deploymentOptions: mssql.DeploymentOptions): Thenable<mssql.SchemaCompareResult> {
|
||||
let result: mssql.SchemaCompareResult;
|
||||
if (this.testState === testStateScmp.FAILURE) {
|
||||
result = {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import * as should from 'should';
|
||||
import * as azdata from 'azdata';
|
||||
import * as vscode from 'vscode';
|
||||
import * as mssql from '../../../mssql';
|
||||
import * as loc from '../localizedConstants';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
@@ -15,10 +16,15 @@ import { promises as fs } from 'fs';
|
||||
import { getEndpointName, verifyConnectionAndGetOwnerUri, exists } from '../utils';
|
||||
import { mockDacpacEndpoint, mockDatabaseEndpoint, mockFilePath, mockConnectionInfo, shouldThrowSpecificError, mockConnectionResult, mockConnectionProfile } from './testUtils';
|
||||
import { createContext, TestContext } from './testContext';
|
||||
import * as sinon from 'sinon';
|
||||
|
||||
let testContext: TestContext;
|
||||
|
||||
describe('utils: Tests to verify getEndpointName', function (): void {
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it('Should generate correct endpoint information', () => {
|
||||
let endpointInfo: mssql.SchemaCompareEndpointInfo;
|
||||
|
||||
@@ -52,7 +58,7 @@ describe('utils: Basic tests to verify verifyConnectionAndGetOwnerUri', function
|
||||
|
||||
it('Should return undefined for endpoint as dacpac', async function (): Promise<void> {
|
||||
let ownerUri = undefined;
|
||||
ownerUri = await verifyConnectionAndGetOwnerUri(mockDacpacEndpoint, 'test', testContext.apiWrapper.object);
|
||||
ownerUri = await verifyConnectionAndGetOwnerUri(mockDacpacEndpoint, 'test');
|
||||
|
||||
should(ownerUri).equal(undefined);
|
||||
});
|
||||
@@ -62,7 +68,7 @@ describe('utils: Basic tests to verify verifyConnectionAndGetOwnerUri', function
|
||||
let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = { ...mockDatabaseEndpoint };
|
||||
testDatabaseEndpoint.connectionDetails = undefined;
|
||||
|
||||
ownerUri = await verifyConnectionAndGetOwnerUri(testDatabaseEndpoint, 'test', testContext.apiWrapper.object);
|
||||
ownerUri = await verifyConnectionAndGetOwnerUri(testDatabaseEndpoint, 'test');
|
||||
|
||||
should(ownerUri).equal(undefined);
|
||||
});
|
||||
@@ -73,6 +79,10 @@ describe('utils: In-depth tests to verify verifyConnectionAndGetOwnerUri', funct
|
||||
testContext = createContext();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it('Should throw an error asking to make a connection', async function (): Promise<void> {
|
||||
let getConnectionsResults: azdata.connection.ConnectionProfile[] = [];
|
||||
let connection = { ...mockConnectionResult };
|
||||
@@ -80,12 +90,14 @@ describe('utils: In-depth tests to verify verifyConnectionAndGetOwnerUri', funct
|
||||
testDatabaseEndpoint.connectionDetails = { ...mockConnectionInfo };
|
||||
const getConnectionString = loc.getConnectionString('test');
|
||||
|
||||
testContext.apiWrapper.setup(x => x.connect(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return Promise.resolve(connection); });
|
||||
testContext.apiWrapper.setup(x => x.getUriForConnection(TypeMoq.It.isAny())).returns(() => { return Promise.resolve(undefined); });
|
||||
testContext.apiWrapper.setup(x => x.getConnections(TypeMoq.It.isAny())).returns(() => { return Promise.resolve(getConnectionsResults); });
|
||||
testContext.apiWrapper.setup(x => x.showWarningMessage(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns((s) => { throw new Error(s); });
|
||||
sinon.stub(azdata.connection, 'connect').returns(<any>Promise.resolve(connection));
|
||||
sinon.stub(azdata.connection, 'getUriForConnection').returns(<any>Promise.resolve(undefined));
|
||||
sinon.stub(azdata.connection, 'getConnections').returns(<any>Promise.resolve(getConnectionsResults));
|
||||
sinon.stub(vscode.window, 'showWarningMessage').callsFake((message) => {
|
||||
throw new Error(message);
|
||||
});
|
||||
|
||||
await shouldThrowSpecificError(async () => await verifyConnectionAndGetOwnerUri(testDatabaseEndpoint, 'test', testContext.apiWrapper.object), getConnectionString);
|
||||
await shouldThrowSpecificError(async () => await verifyConnectionAndGetOwnerUri(testDatabaseEndpoint, 'test'), getConnectionString);
|
||||
});
|
||||
|
||||
it('Should throw an error for login failure', async function (): Promise<void> {
|
||||
@@ -94,12 +106,15 @@ describe('utils: In-depth tests to verify verifyConnectionAndGetOwnerUri', funct
|
||||
let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = { ...mockDatabaseEndpoint };
|
||||
testDatabaseEndpoint.connectionDetails = { ...mockConnectionInfo };
|
||||
|
||||
testContext.apiWrapper.setup(x => x.connect(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return Promise.resolve(connection); });
|
||||
testContext.apiWrapper.setup(x => x.getUriForConnection(TypeMoq.It.isAny())).returns(() => { return Promise.resolve(undefined); });
|
||||
testContext.apiWrapper.setup(x => x.getConnections(TypeMoq.It.isAny())).returns(() => { return Promise.resolve(getConnectionsResults); });
|
||||
testContext.apiWrapper.setup(x => x.showErrorMessage(TypeMoq.It.isAny())).returns((s) => { throw new Error(s); });
|
||||
sinon.stub(azdata.connection, 'connect').returns(<any>Promise.resolve(connection));
|
||||
sinon.stub(azdata.connection, 'getUriForConnection').returns(<any>Promise.resolve(undefined));
|
||||
sinon.stub(azdata.connection, 'getConnections').returns(<any>Promise.resolve(getConnectionsResults));
|
||||
sinon.stub(vscode.window, 'showWarningMessage').returns(<any>Promise.resolve(loc.YesButtonText));
|
||||
sinon.stub(vscode.window, 'showErrorMessage').callsFake((message) => {
|
||||
throw new Error(message);
|
||||
});
|
||||
|
||||
await shouldThrowSpecificError(async () => await verifyConnectionAndGetOwnerUri(testDatabaseEndpoint, 'test', testContext.apiWrapper.object), connection.errorMessage);
|
||||
await shouldThrowSpecificError(async () => await verifyConnectionAndGetOwnerUri(testDatabaseEndpoint, 'test'), connection.errorMessage);
|
||||
});
|
||||
|
||||
it('Should throw an error for login failure with openConnectionDialog but no ownerUri', async function (): Promise<void> {
|
||||
@@ -108,13 +123,18 @@ describe('utils: In-depth tests to verify verifyConnectionAndGetOwnerUri', funct
|
||||
let testDatabaseEndpoint: mssql.SchemaCompareEndpointInfo = { ...mockDatabaseEndpoint };
|
||||
testDatabaseEndpoint.connectionDetails = { ...mockConnectionInfo };
|
||||
|
||||
testContext.apiWrapper.setup(x => x.connect(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return Promise.resolve(connection); });
|
||||
testContext.apiWrapper.setup(x => x.getUriForConnection(TypeMoq.It.isAny())).returns(() => { return Promise.resolve(undefined); });
|
||||
testContext.apiWrapper.setup(x => x.getConnections(TypeMoq.It.isAny())).returns(() => { return Promise.resolve(getConnectionsResults); });
|
||||
testContext.apiWrapper.setup(x => x.showWarningMessage(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return Promise.resolve(loc.YesButtonText); });
|
||||
testContext.apiWrapper.setup(x => x.openConnectionDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return Promise.resolve(undefined); });
|
||||
sinon.stub(azdata.connection, 'connect').returns(<any>Promise.resolve(connection));
|
||||
sinon.stub(azdata.connection, 'getUriForConnection').returns(<any>Promise.resolve(undefined));
|
||||
sinon.stub(azdata.connection, 'openConnectionDialog').returns(<any>Promise.resolve({
|
||||
connectionId: 'id'
|
||||
}));
|
||||
sinon.stub(azdata.connection, 'getConnections').returns(<any>Promise.resolve(getConnectionsResults));
|
||||
sinon.stub(vscode.window, 'showWarningMessage').returns(<any>Promise.resolve(loc.YesButtonText));
|
||||
sinon.stub(vscode.window, 'showErrorMessage').callsFake((message) => {
|
||||
throw new Error(message);
|
||||
});
|
||||
|
||||
await shouldThrowSpecificError(async () => await verifyConnectionAndGetOwnerUri(testDatabaseEndpoint, 'test', testContext.apiWrapper.object), connection.errorMessage);
|
||||
await shouldThrowSpecificError(async () => await verifyConnectionAndGetOwnerUri(testDatabaseEndpoint, 'test'), connection.errorMessage);
|
||||
});
|
||||
|
||||
it('Should not throw an error and set ownerUri appropriately', async function (): Promise<void> {
|
||||
@@ -124,10 +144,10 @@ describe('utils: In-depth tests to verify verifyConnectionAndGetOwnerUri', funct
|
||||
let expectedOwnerUri: string = 'providerName:MSSQL|authenticationType:SqlLogin|database:My Database|server:My Server|user:My User|databaseDisplayName:My Database';
|
||||
testDatabaseEndpoint.connectionDetails = { ...mockConnectionInfo };
|
||||
|
||||
testContext.apiWrapper.setup(x => x.connect(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { return Promise.resolve(connection); });
|
||||
testContext.apiWrapper.setup(x => x.getUriForConnection(TypeMoq.It.isAny())).returns(() => { return Promise.resolve(expectedOwnerUri); });
|
||||
sinon.stub(azdata.connection, 'connect').returns(<any>Promise.resolve(connection));
|
||||
sinon.stub(azdata.connection, 'getUriForConnection').returns(<any>Promise.resolve(expectedOwnerUri));
|
||||
|
||||
ownerUri = await verifyConnectionAndGetOwnerUri(testDatabaseEndpoint, 'test', testContext.apiWrapper.object);
|
||||
ownerUri = await verifyConnectionAndGetOwnerUri(testDatabaseEndpoint, 'test');
|
||||
|
||||
should(ownerUri).equal(expectedOwnerUri);
|
||||
});
|
||||
|
||||
@@ -8,7 +8,6 @@ import * as vscode from 'vscode';
|
||||
import * as mssql from '../../mssql';
|
||||
import * as os from 'os';
|
||||
import * as loc from './localizedConstants';
|
||||
import { ApiWrapper } from './common/apiWrapper';
|
||||
import { promises as fs } from 'fs';
|
||||
|
||||
export interface IPackageInfo {
|
||||
@@ -32,7 +31,7 @@ export function getPackageInfo(packageJson: any): IPackageInfo {
|
||||
* @param msg The error message to map
|
||||
*/
|
||||
export function getTelemetryErrorType(msg: string): string {
|
||||
if (msg.indexOf('Object reference not set to an instance of an object') !== -1) {
|
||||
if (msg && msg.indexOf('Object reference not set to an instance of an object') !== -1) {
|
||||
return 'ObjectReferenceNotSet';
|
||||
}
|
||||
else {
|
||||
@@ -85,18 +84,18 @@ function connectionInfoToConnectionProfile(details: azdata.ConnectionInfo): azda
|
||||
};
|
||||
}
|
||||
|
||||
export async function verifyConnectionAndGetOwnerUri(endpoint: mssql.SchemaCompareEndpointInfo, caller: string, apiWrapper: ApiWrapper): Promise<string | undefined> {
|
||||
export async function verifyConnectionAndGetOwnerUri(endpoint: mssql.SchemaCompareEndpointInfo, caller: string): Promise<string | undefined> {
|
||||
let ownerUri = undefined;
|
||||
|
||||
if (endpoint.endpointType === mssql.SchemaCompareEndpointType.Database && endpoint.connectionDetails) {
|
||||
let connectionProfile = await connectionInfoToConnectionProfile(endpoint.connectionDetails);
|
||||
let connection = await apiWrapper.connect(connectionProfile, false, false);
|
||||
let connection = await azdata.connection.connect(connectionProfile, false, false);
|
||||
|
||||
if (connection) {
|
||||
ownerUri = await apiWrapper.getUriForConnection(connection.connectionId);
|
||||
ownerUri = await azdata.connection.getUriForConnection(connection.connectionId);
|
||||
|
||||
if (!ownerUri) {
|
||||
let connectionList = await apiWrapper.getConnections(true);
|
||||
let connectionList = await azdata.connection.getConnections(true);
|
||||
|
||||
let userConnection;
|
||||
userConnection = connectionList.find(connection =>
|
||||
@@ -109,18 +108,18 @@ export async function verifyConnectionAndGetOwnerUri(endpoint: mssql.SchemaCompa
|
||||
if (userConnection === undefined) {
|
||||
const getConnectionString = loc.getConnectionString(caller);
|
||||
// need only yes button - since the modal dialog has a default cancel
|
||||
let result = await apiWrapper.showWarningMessage(getConnectionString, { modal: true }, loc.YesButtonText);
|
||||
let result = await vscode.window.showWarningMessage(getConnectionString, { modal: true }, loc.YesButtonText);
|
||||
if (result === loc.YesButtonText) {
|
||||
userConnection = await apiWrapper.openConnectionDialog(undefined, connectionProfile);
|
||||
userConnection = await azdata.connection.openConnectionDialog(undefined, connectionProfile);
|
||||
}
|
||||
}
|
||||
|
||||
if (userConnection !== undefined) {
|
||||
ownerUri = await apiWrapper.getUriForConnection(userConnection.connectionId);
|
||||
ownerUri = await azdata.connection.getUriForConnection(userConnection.connectionId);
|
||||
}
|
||||
}
|
||||
if (!ownerUri && connection.errorMessage) {
|
||||
apiWrapper.showErrorMessage(connection.errorMessage);
|
||||
vscode.window.showErrorMessage(connection.errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +182,42 @@
|
||||
resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd"
|
||||
integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==
|
||||
|
||||
"@sinonjs/commons@^1", "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.1":
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217"
|
||||
integrity sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==
|
||||
dependencies:
|
||||
type-detect "4.0.8"
|
||||
|
||||
"@sinonjs/fake-timers@^6.0.0", "@sinonjs/fake-timers@^6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40"
|
||||
integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^1.7.0"
|
||||
|
||||
"@sinonjs/formatio@^5.0.1":
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-5.0.1.tgz#f13e713cb3313b1ab965901b01b0828ea6b77089"
|
||||
integrity sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^1"
|
||||
"@sinonjs/samsam" "^5.0.2"
|
||||
|
||||
"@sinonjs/samsam@^5.0.2", "@sinonjs/samsam@^5.2.0":
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-5.3.0.tgz#1d2f0743dc54bf13fe9d508baefacdffa25d4329"
|
||||
integrity sha512-hXpcfx3aq+ETVBwPlRFICld5EnrkexXuXDwqUNhDdr5L8VjvMeSRwyOa0qL7XFmR+jVWR4rUZtnxlG7RX72sBg==
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^1.6.0"
|
||||
lodash.get "^4.4.2"
|
||||
type-detect "^4.0.8"
|
||||
|
||||
"@sinonjs/text-encoding@^0.7.1":
|
||||
version "0.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5"
|
||||
integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==
|
||||
|
||||
"@types/mocha@^5.2.5":
|
||||
version "5.2.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.6.tgz#b8622d50557dd155e9f2f634b7d68fd38de5e94b"
|
||||
@@ -192,6 +228,18 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.7.tgz#01e4ea724d9e3bd50d90c11fd5980ba317d8fa11"
|
||||
integrity sha512-E6Zn0rffhgd130zbCbAr/JdXfXkoOUFAKNs/rF8qnafSJ8KYaA/j3oz7dcwal+lYjLA7xvdd5J4wdYpCTlP8+w==
|
||||
|
||||
"@types/sinon@^9.0.4":
|
||||
version "9.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.9.tgz#115843b491583f924080f684b6d0d7438344f73c"
|
||||
integrity sha512-z/y8maYOQyYLyqaOB+dYQ6i0pxKLOsfwCmHmn4T7jS/SDHicIslr37oE3Dg8SCqKrKeBy6Lemu7do2yy+unLrw==
|
||||
dependencies:
|
||||
"@types/sinonjs__fake-timers" "*"
|
||||
|
||||
"@types/sinonjs__fake-timers@*":
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.2.tgz#3a84cf5ec3249439015e14049bd3161419bf9eae"
|
||||
integrity sha512-dIPoZ3g5gcx9zZEszaxLSVTvMReD3xxyyDnQUjA6IYDG9Ba2AV0otMPs+77sG9ojB4Qr2N2Vk5RnKeuA0X/0bg==
|
||||
|
||||
ads-extension-telemetry@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ads-extension-telemetry/-/ads-extension-telemetry-1.0.0.tgz#840b363a6ad958447819b9bc59fdad3e49de31a9"
|
||||
@@ -395,6 +443,11 @@ diff@3.5.0:
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
|
||||
integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
|
||||
|
||||
diff@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
|
||||
|
||||
emitter-listener@^1.0.1, emitter-listener@^1.1.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8"
|
||||
@@ -501,6 +554,11 @@ is-buffer@~1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
||||
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
|
||||
|
||||
isarray@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
|
||||
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
|
||||
|
||||
istanbul-lib-coverage@^2.0.5:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49"
|
||||
@@ -576,6 +634,16 @@ json5@^2.1.2:
|
||||
dependencies:
|
||||
minimist "^1.2.5"
|
||||
|
||||
just-extend@^4.0.2:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.1.1.tgz#158f1fdb01f128c411dc8b286a7b4837b3545282"
|
||||
integrity sha512-aWgeGFW67BP3e5181Ep1Fv2v8z//iBJfrvyTnq8wG86vEESwmonn1zPBJ0VfmT9CJq2FIT0VsETtrNFm2a+SHA==
|
||||
|
||||
lodash.get@^4.4.2:
|
||||
version "4.4.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
|
||||
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
|
||||
|
||||
lodash@^4.16.4, lodash@^4.17.13, lodash@^4.17.4:
|
||||
version "4.17.19"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
|
||||
@@ -675,6 +743,17 @@ ms@^2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
nise@^4.0.4:
|
||||
version "4.0.4"
|
||||
resolved "https://registry.yarnpkg.com/nise/-/nise-4.0.4.tgz#d73dea3e5731e6561992b8f570be9e363c4512dd"
|
||||
integrity sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^1.7.0"
|
||||
"@sinonjs/fake-timers" "^6.0.0"
|
||||
"@sinonjs/text-encoding" "^0.7.1"
|
||||
just-extend "^4.0.2"
|
||||
path-to-regexp "^1.7.0"
|
||||
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
@@ -692,6 +771,13 @@ path-parse@^1.0.6:
|
||||
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
|
||||
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
|
||||
|
||||
path-to-regexp@^1.7.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
|
||||
integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
|
||||
dependencies:
|
||||
isarray "0.0.1"
|
||||
|
||||
pify@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
|
||||
@@ -785,6 +871,19 @@ should@^13.2.1:
|
||||
should-type-adaptors "^1.0.1"
|
||||
should-util "^1.0.0"
|
||||
|
||||
sinon@^9.0.2:
|
||||
version "9.2.1"
|
||||
resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.2.1.tgz#64cc88beac718557055bd8caa526b34a2231be6d"
|
||||
integrity sha512-naPfsamB5KEE1aiioaoqJ6MEhdUs/2vtI5w1hPAXX/UwvoPjXcwh1m5HiKx0HGgKR8lQSoFIgY5jM6KK8VrS9w==
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^1.8.1"
|
||||
"@sinonjs/fake-timers" "^6.0.1"
|
||||
"@sinonjs/formatio" "^5.0.1"
|
||||
"@sinonjs/samsam" "^5.2.0"
|
||||
diff "^4.0.2"
|
||||
nise "^4.0.4"
|
||||
supports-color "^7.1.0"
|
||||
|
||||
source-map@^0.5.0:
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||
@@ -838,6 +937,11 @@ to-fast-properties@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
|
||||
integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
|
||||
|
||||
type-detect@4.0.8, type-detect@^4.0.8:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
|
||||
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
|
||||
|
||||
typemoq@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/typemoq/-/typemoq-2.1.0.tgz#4452ce360d92cf2a1a180f0c29de2803f87af1e8"
|
||||
|
||||
Reference in New Issue
Block a user