diff --git a/extensions/dacpac/src/test/testDacFxService.ts b/extensions/dacpac/src/test/testDacFxService.ts index 2241c985bb..62ff028f42 100644 --- a/extensions/dacpac/src/test/testDacFxService.ts +++ b/extensions/dacpac/src/test/testDacFxService.ts @@ -56,4 +56,92 @@ export class DacFxTestService implements mssql.IDacFxService { }; return Promise.resolve(deployPlan); } + getOptionsFromProfile(profilePath: string): Thenable { + const optionsResult: mssql.DacFxOptionsResult = { + success: true, + errorMessage: '', + deploymentOptions: { + ignoreTableOptions: false, + ignoreSemicolonBetweenStatements: false, + ignoreRouteLifetime: false, + ignoreRoleMembership: false, + ignoreQuotedIdentifiers: false, + ignorePermissions: false, + ignorePartitionSchemes: false, + ignoreObjectPlacementOnPartitionScheme: false, + ignoreNotForReplication: false, + ignoreLoginSids: false, + ignoreLockHintsOnIndexes: false, + ignoreKeywordCasing: false, + ignoreIndexPadding: false, + ignoreIndexOptions: false, + ignoreIncrement: false, + ignoreIdentitySeed: false, + ignoreUserSettingsObjects: false, + ignoreFullTextCatalogFilePath: false, + ignoreWhitespace: false, + ignoreWithNocheckOnForeignKeys: false, + verifyCollationCompatibility: false, + unmodifiableObjectWarnings: false, + treatVerificationErrorsAsWarnings: false, + scriptRefreshModule: false, + scriptNewConstraintValidation: false, + scriptFileSize: false, + scriptDeployStateChecks: false, + scriptDatabaseOptions: false, + scriptDatabaseCompatibility: false, + scriptDatabaseCollation: false, + runDeploymentPlanExecutors: false, + registerDataTierApplication: false, + populateFilesOnFileGroups: false, + noAlterStatementsToChangeClrTypes: false, + includeTransactionalScripts: false, + includeCompositeObjects: false, + allowUnsafeRowLevelSecurityDataMovement: false, + ignoreWithNocheckOnCheckConstraints: false, + ignoreFillFactor: false, + ignoreFileSize: false, + ignoreFilegroupPlacement: false, + doNotAlterReplicatedObjects: false, + doNotAlterChangeDataCaptureObjects: false, + disableAndReenableDdlTriggers: false, + deployDatabaseInSingleUserMode: false, + createNewDatabase: false, + compareUsingTargetCollation: false, + commentOutSetVarDeclarations: false, + blockWhenDriftDetected: false, + blockOnPossibleDataLoss: false, + backupDatabaseBeforeChanges: false, + allowIncompatiblePlatform: false, + allowDropBlockingAssemblies: false, + dropConstraintsNotInSource: false, + dropDmlTriggersNotInSource: false, + dropExtendedPropertiesNotInSource: false, + dropIndexesNotInSource: false, + ignoreFileAndLogFilePath: false, + ignoreExtendedProperties: false, + ignoreDmlTriggerState: false, + ignoreDmlTriggerOrder: false, + ignoreDefaultSchema: false, + ignoreDdlTriggerState: false, + ignoreDdlTriggerOrder: false, + ignoreCryptographicProviderFilePath: false, + verifyDeployment: false, + ignoreComments: false, + ignoreColumnCollation: false, + ignoreAuthorizer: false, + ignoreAnsiNulls: false, + generateSmartDefaults: false, + dropStatisticsNotInSource: false, + dropRoleMembersNotInSource: false, + dropPermissionsNotInSource: false, + dropObjectsNotInSource: false, + ignoreColumnOrder: false, + doNotDropObjectTypes: [], + excludeObjectTypes: [] + } + }; + + return Promise.resolve(optionsResult); + } } diff --git a/extensions/mssql/config.json b/extensions/mssql/config.json index 4d4ef5eaef..ced60839a1 100644 --- a/extensions/mssql/config.json +++ b/extensions/mssql/config.json @@ -1,6 +1,6 @@ { "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", - "version": "3.0.0-release.4", + "version": "3.0.0-release.8", "downloadFileNames": { "Windows_86": "win-x86-netcoreapp3.1.zip", "Windows_64": "win-x64-netcoreapp3.1.zip", diff --git a/extensions/mssql/src/contracts.ts b/extensions/mssql/src/contracts.ts index 798a7a05e1..268925bbfa 100644 --- a/extensions/mssql/src/contracts.ts +++ b/extensions/mssql/src/contracts.ts @@ -452,6 +452,7 @@ export interface DeployParams { databaseName: string; upgradeExisting: boolean; sqlCommandVariableValues?: Record; + deploymentOptions?: mssql.DeploymentOptions; ownerUri: string; taskExecutionMode: TaskExecutionMode; } @@ -460,6 +461,7 @@ export interface GenerateDeployScriptParams { packageFilePath: string; databaseName: string; sqlCommandVariableValues?: Record; + deploymentOptions?: mssql.DeploymentOptions ownerUri: string; taskExecutionMode: TaskExecutionMode; } @@ -471,6 +473,9 @@ export interface GenerateDeployPlanParams { taskExecutionMode: TaskExecutionMode; } +export interface GetOptionsFromProfileParams { + profilePath: string; +} export namespace ExportRequest { export const type = new RequestType('dacfx/export'); } @@ -494,6 +499,10 @@ export namespace GenerateDeployScriptRequest { export namespace GenerateDeployPlanRequest { export const type = new RequestType('dacfx/generateDeployPlan'); } + +export namespace GetOptionsFromProfileRequest { + export const type = new RequestType('dacfx/getOptionsFromProfile'); +} // ------------------------------- < DacFx > ------------------------------------ // ------------------------------- ---------------------------------------- diff --git a/extensions/mssql/src/dacfx/dacFxService.ts b/extensions/mssql/src/dacfx/dacFxService.ts index 2b7344f914..90ac6c8bf7 100644 --- a/extensions/mssql/src/dacfx/dacFxService.ts +++ b/extensions/mssql/src/dacfx/dacFxService.ts @@ -76,8 +76,8 @@ export class DacFxService implements mssql.IDacFxService { ); } - public deployDacpac(packageFilePath: string, targetDatabaseName: string, upgradeExisting: boolean, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode, sqlCommandVariableValues?: Record): Thenable { - const params: contracts.DeployParams = { packageFilePath: packageFilePath, databaseName: targetDatabaseName, upgradeExisting: upgradeExisting, sqlCommandVariableValues: sqlCommandVariableValues, ownerUri: ownerUri, taskExecutionMode: taskExecutionMode }; + public deployDacpac(packageFilePath: string, targetDatabaseName: string, upgradeExisting: boolean, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode, sqlCommandVariableValues?: Record, deploymentOptions?: mssql.DeploymentOptions): Thenable { + const params: contracts.DeployParams = { packageFilePath: packageFilePath, databaseName: targetDatabaseName, upgradeExisting: upgradeExisting, sqlCommandVariableValues: sqlCommandVariableValues, deploymentOptions: deploymentOptions, ownerUri: ownerUri, taskExecutionMode: taskExecutionMode }; return this.client.sendRequest(contracts.DeployRequest.type, params).then( undefined, e => { @@ -87,8 +87,8 @@ export class DacFxService implements mssql.IDacFxService { ); } - public generateDeployScript(packageFilePath: string, targetDatabaseName: string, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode, sqlCommandVariableValues?: Record): Thenable { - const params: contracts.GenerateDeployScriptParams = { packageFilePath: packageFilePath, databaseName: targetDatabaseName, sqlCommandVariableValues: sqlCommandVariableValues, ownerUri: ownerUri, taskExecutionMode: taskExecutionMode }; + public generateDeployScript(packageFilePath: string, targetDatabaseName: string, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode, sqlCommandVariableValues?: Record, deploymentOptions?: mssql.DeploymentOptions): Thenable { + const params: contracts.GenerateDeployScriptParams = { packageFilePath: packageFilePath, databaseName: targetDatabaseName, sqlCommandVariableValues: sqlCommandVariableValues, deploymentOptions: deploymentOptions, ownerUri: ownerUri, taskExecutionMode: taskExecutionMode }; return this.client.sendRequest(contracts.GenerateDeployScriptRequest.type, params).then( undefined, e => { @@ -108,4 +108,15 @@ export class DacFxService implements mssql.IDacFxService { } ); } + + public getOptionsFromProfile(profilePath: string): Thenable { + const params: contracts.GetOptionsFromProfileParams = { profilePath: profilePath }; + return this.client.sendRequest(contracts.GetOptionsFromProfileRequest.type, params).then( + undefined, + e => { + this.client.logFailedRequest(contracts.GetOptionsFromProfileRequest.type, e); + return Promise.resolve(undefined); + } + ); + } } diff --git a/extensions/mssql/src/mssql.d.ts b/extensions/mssql/src/mssql.d.ts index 7767b2b2ad..e9a3e19ebe 100644 --- a/extensions/mssql/src/mssql.d.ts +++ b/extensions/mssql/src/mssql.d.ts @@ -333,9 +333,10 @@ export interface IDacFxService { importBacpac(packageFilePath: string, databaseName: string, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable; extractDacpac(databaseName: string, packageFilePath: string, applicationName: string, applicationVersion: string, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable; importDatabaseProject(databaseName: string, targetFilePath: string, applicationName: string, applicationVersion: string, ownerUri: string, extractTarget: ExtractTarget, taskExecutionMode: azdata.TaskExecutionMode): Thenable; - deployDacpac(packageFilePath: string, databaseName: string, upgradeExisting: boolean, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode, sqlCommandVariableValues?: Record): Thenable; - generateDeployScript(packageFilePath: string, databaseName: string, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode, sqlCommandVariableValues?: Record): Thenable; + deployDacpac(packageFilePath: string, databaseName: string, upgradeExisting: boolean, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode, sqlCommandVariableValues?: Record, deploymentOptions?: DeploymentOptions): Thenable; + generateDeployScript(packageFilePath: string, databaseName: string, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode, sqlCommandVariableValues?: Record, deploymentOptions?: DeploymentOptions): Thenable; generateDeployPlan(packageFilePath: string, databaseName: string, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable; + getOptionsFromProfile(profilePath: string): Thenable; } export interface DacFxResult extends azdata.ResultStatus { @@ -346,6 +347,10 @@ export interface GenerateDeployPlanResult extends DacFxResult { report: string; } +export interface DacFxOptionsResult extends azdata.ResultStatus { + deploymentOptions: DeploymentOptions; +} + export interface ExportParams { databaseName: string; packageFilePath: string; diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts index 1d4ae46072..df0a9dd3f4 100644 --- a/extensions/sql-database-projects/src/common/constants.ts +++ b/extensions/sql-database-projects/src/common/constants.ts @@ -77,7 +77,7 @@ export const selectConnectionRadioButtonsTitle = localize('selectconnectionRadio export const dataSourceDropdownTitle = localize('dataSourceDropdownTitle', "Data source"); export const noDataSourcesText = localize('noDataSourcesText', "No data sources in this project"); export const loadProfileButtonText = localize('loadProfileButtonText', "Load Profile..."); -export const profileWarningText = localize('profileWarningText', "⚠ Warning: Only SQL Login and Integrated Authentication connection strings, database name, and SQLCMD variables are able to be loaded from a profile at this time"); +export const profileWarningText = localize('profileWarningText', "⚠ Warning: Connection strings using AAD Authentication are not supported at this time"); export const sqlCmdTableLabel = localize('sqlCmdTableLabel', "SQLCMD Variables"); export const sqlCmdVariableColumn = localize('sqlCmdVariableColumn', "Variable"); export const sqlCmdValueColumn = localize('sqlCmdValueColumn', "Value"); diff --git a/extensions/sql-database-projects/src/controllers/projectController.ts b/extensions/sql-database-projects/src/controllers/projectController.ts index d41aeb8281..302aaa908c 100644 --- a/extensions/sql-database-projects/src/controllers/projectController.ts +++ b/extensions/sql-database-projects/src/controllers/projectController.ts @@ -220,15 +220,16 @@ export class ProjectsController { const dacFxService = await this.getDaxFxService(); if ((settings).upgradeExisting) { - return await dacFxService.deployDacpac(tempPath, settings.databaseName, (settings).upgradeExisting, settings.connectionUri, azdata.TaskExecutionMode.execute, settings.sqlCmdVariables); + return await dacFxService.deployDacpac(tempPath, settings.databaseName, (settings).upgradeExisting, settings.connectionUri, azdata.TaskExecutionMode.execute, settings.sqlCmdVariables, settings.deploymentOptions); } else { - return await dacFxService.generateDeployScript(tempPath, settings.databaseName, settings.connectionUri, azdata.TaskExecutionMode.script, settings.sqlCmdVariables); + return await dacFxService.generateDeployScript(tempPath, settings.databaseName, settings.connectionUri, azdata.TaskExecutionMode.script, settings.sqlCmdVariables, settings.deploymentOptions); } } public async readPublishProfileCallback(profileUri: vscode.Uri): Promise { - const profile = await load(profileUri); + const dacFxService = await this.getDaxFxService(); + const profile = await load(profileUri, dacFxService); return profile; } diff --git a/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts b/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts index e04dd3c106..e5aa826846 100644 --- a/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts +++ b/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts @@ -11,6 +11,7 @@ import * as utils from '../common/utils'; import { Project } from '../models/project'; import { SqlConnectionDataSource } from '../models/dataSources/sqlConnectionStringSource'; import { IPublishSettings, IGenerateScriptSettings } from '../models/IPublishSettings'; +import { DeploymentOptions } from '../../../mssql/src/mssql'; interface DataSourceDropdownValue extends azdata.CategoryValue { dataSource: SqlConnectionDataSource; @@ -35,6 +36,7 @@ export class PublishDatabaseDialog { private connectionId: string | undefined; private connectionIsDataSource: boolean | undefined; private profileSqlCmdVars: Record | undefined; + private deploymentOptions: DeploymentOptions | undefined; private toDispose: vscode.Disposable[] = []; @@ -191,7 +193,8 @@ export class PublishDatabaseDialog { databaseName: this.getTargetDatabaseName(), upgradeExisting: true, connectionUri: await this.getConnectionUri(), - sqlCmdVariables: sqlCmdVars + sqlCmdVariables: sqlCmdVars, + deploymentOptions: this.deploymentOptions }; azdata.window.closeDialog(this.dialog); @@ -205,7 +208,8 @@ export class PublishDatabaseDialog { const settings: IGenerateScriptSettings = { databaseName: this.getTargetDatabaseName(), connectionUri: await this.getConnectionUri(), - sqlCmdVariables: sqlCmdVars + sqlCmdVariables: sqlCmdVars, + deploymentOptions: this.deploymentOptions }; azdata.window.closeDialog(this.dialog); @@ -399,7 +403,7 @@ export class PublishDatabaseDialog { canSelectFiles: true, canSelectFolders: false, canSelectMany: false, - defaultUri: vscode.Uri.parse(this.project.projectFolderPath), + defaultUri: vscode.workspace.workspaceFolders ? (vscode.workspace.workspaceFolders as vscode.WorkspaceFolder[])[0].uri : undefined, filters: { [constants.publishSettingsFiles]: ['publish.xml'] } @@ -417,6 +421,7 @@ export class PublishDatabaseDialog { this.connectionId = result.connectionId; (this.targetConnectionTextBox).value = result.connectionString; + this.deploymentOptions = result.options; this.profileSqlCmdVars = result.sqlCmdVariables; const data = this.convertSqlCmdVarsToTableFormat(this.getSqlCmdVariablesForPublish()); diff --git a/extensions/sql-database-projects/src/models/IPublishSettings.ts b/extensions/sql-database-projects/src/models/IPublishSettings.ts index a5b90f0e4b..865620a55f 100644 --- a/extensions/sql-database-projects/src/models/IPublishSettings.ts +++ b/extensions/sql-database-projects/src/models/IPublishSettings.ts @@ -3,15 +3,19 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { DeploymentOptions } from '../../../mssql/src/mssql'; + export interface IPublishSettings { databaseName: string; connectionUri: string; upgradeExisting: boolean; sqlCmdVariables?: Record; + deploymentOptions?: DeploymentOptions; } export interface IGenerateScriptSettings { databaseName: string; connectionUri: string; sqlCmdVariables?: Record; + deploymentOptions?: DeploymentOptions; } diff --git a/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts b/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts index 3120af8f1b..5ea17ab4b9 100644 --- a/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts +++ b/extensions/sql-database-projects/src/models/publishProfile/publishProfile.ts @@ -7,6 +7,7 @@ import * as azdata from 'azdata'; import * as xmldom from 'xmldom'; import * as constants from '../../common/constants'; import * as utils from '../../common/utils'; +import * as mssql from '../../../../mssql'; import { promises as fs } from 'fs'; import { Uri } from 'vscode'; @@ -18,12 +19,13 @@ export interface PublishProfile { connectionId: string; connectionString: string; sqlCmdVariables: Record; + options?: mssql.DeploymentOptions; } /** * parses the specified file to load publish settings */ -export async function load(profileUri: Uri): Promise { +export async function load(profileUri: Uri, dacfxService: mssql.IDacFxService): Promise { const profileText = await fs.readFile(profileUri.fsPath); const profileXmlDoc = new xmldom.DOMParser().parseFromString(profileText.toString()); @@ -36,6 +38,7 @@ export async function load(profileUri: Uri): Promise { } const connectionInfo = await readConnectionString(profileXmlDoc); + const optionsResult = await dacfxService.getOptionsFromProfile(profileUri.fsPath); // get all SQLCMD variables to include from the profile const sqlCmdVariables = readSqlCmdVariables(profileXmlDoc); @@ -44,7 +47,8 @@ export async function load(profileUri: Uri): Promise { databaseName: targetDbName, connectionId: connectionInfo.connectionId, connectionString: connectionInfo.connectionString, - sqlCmdVariables: sqlCmdVariables + sqlCmdVariables: sqlCmdVariables, + options: optionsResult.deploymentOptions }; } @@ -54,7 +58,7 @@ export async function load(profileUri: Uri): Promise { */ export function readSqlCmdVariables(xmlDoc: any): Record { let sqlCmdVariables: Record = {}; - for (let i = 0; i < xmlDoc.documentElement.getElementsByTagName(constants.SqlCmdVariable).length; i++) { + for (let i = 0; i < xmlDoc.documentElement.getElementsByTagName(constants.SqlCmdVariable)?.length; i++) { const sqlCmdVar = xmlDoc.documentElement.getElementsByTagName(constants.SqlCmdVariable)[i]; const varName = sqlCmdVar.getAttribute(constants.Include); diff --git a/extensions/sql-database-projects/src/test/projectController.test.ts b/extensions/sql-database-projects/src/test/projectController.test.ts index c9cbe48e3c..4d5fc58e42 100644 --- a/extensions/sql-database-projects/src/test/projectController.test.ts +++ b/extensions/sql-database-projects/src/test/projectController.test.ts @@ -289,7 +289,7 @@ describe('ProjectsController', function (): void { let builtDacpacPath = ''; let publishedDacpacPath = ''; - testContext.dacFxService.setup(x => x.generateDeployScript(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(async (p) => { + testContext.dacFxService.setup(x => x.generateDeployScript(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(async (p) => { publishedDacpacPath = p; postCopyContents = (await fs.readFile(publishedDacpacPath)).toString(); return Promise.resolve(mockDacFxResult); diff --git a/extensions/sql-database-projects/src/test/publishProfile.test.ts b/extensions/sql-database-projects/src/test/publishProfile.test.ts index c189940b42..adcfbc6a9a 100644 --- a/extensions/sql-database-projects/src/test/publishProfile.test.ts +++ b/extensions/sql-database-projects/src/test/publishProfile.test.ts @@ -7,18 +7,26 @@ import * as should from 'should'; import * as azdata from 'azdata'; import * as vscode from 'vscode'; import * as sinon from 'sinon'; +import * as TypeMoq from 'typemoq'; import * as baselines from './baselines/baselines'; import * as testUtils from './testUtils'; import * as constants from '../common/constants'; import { ProjectsController } from '../controllers/projectController'; import { SqlDatabaseProjectTreeViewProvider } from '../controllers/databaseProjectTreeViewProvider'; +import { TestContext, createContext, mockDacFxOptionsResult } from './testContext'; +import { load } from '../models/publishProfile/publishProfile'; +let testContext: TestContext; describe('Publish profile tests', function (): void { before(async function (): Promise { await baselines.loadBaselines(); }); + beforeEach(function (): void { + testContext = createContext(); + }); + afterEach(function (): void { sinon.restore(); }); @@ -26,44 +34,50 @@ describe('Publish profile tests', function (): void { it('Should read database name, integrated security connection string, and SQLCMD variables from publish profile', async function (): Promise { await baselines.loadBaselines(); let profilePath = await testUtils.createTestFile(baselines.publishProfileIntegratedSecurityBaseline, 'publishProfile.publish.xml'); - const projController = new ProjectsController(new SqlDatabaseProjectTreeViewProvider()); const connectionResult = { connected: true, connectionId: 'connId', errorMessage: '', errorCode: 0 }; + testContext.dacFxService.setup(x => x.getOptionsFromProfile(TypeMoq.It.isAny())).returns(async () => { + return Promise.resolve(mockDacFxOptionsResult); + }); const connectionString = 'Data Source=testserver;Integrated Security=true;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Connect Timeout=60;Encrypt=False;TrustServerCertificate=True'; sinon.stub(azdata.connection, 'connect').resolves(connectionResult); sinon.stub(azdata.connection, 'getConnectionString').resolves(connectionString); - let result = await projController.readPublishProfileCallback(vscode.Uri.file(profilePath)); + let result = await load(vscode.Uri.file(profilePath), testContext.dacFxService.object); should(result.databaseName).equal('targetDb'); should(Object.keys(result.sqlCmdVariables).length).equal(1); should(result.sqlCmdVariables['ProdDatabaseName']).equal('MyProdDatabase'); should(result.connectionId).equal('connId'); should(result.connectionString).equal('Data Source=testserver;Integrated Security=true;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Connect Timeout=60;Encrypt=False;TrustServerCertificate=True'); + should(result.options).equal(mockDacFxOptionsResult.deploymentOptions); }); it('Should read database name, SQL login connection string, and SQLCMD variables from publish profile', async function (): Promise { await baselines.loadBaselines(); let profilePath = await testUtils.createTestFile(baselines.publishProfileSqlLoginBaseline, 'publishProfile.publish.xml'); - const projController = new ProjectsController(new SqlDatabaseProjectTreeViewProvider()); const connectionResult = { providerName: 'MSSQL', connectionId: 'connId', options: {} }; + testContext.dacFxService.setup(x => x.getOptionsFromProfile(TypeMoq.It.isAny())).returns(async () => { + return Promise.resolve(mockDacFxOptionsResult); + }); const connectionString = 'Data Source=testserver;User Id=testUser;Password=******;Integrated Security=false;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Connect Timeout=60;Encrypt=False;TrustServerCertificate=True'; sinon.stub(azdata.connection, 'openConnectionDialog').resolves(connectionResult); sinon.stub(azdata.connection, 'getConnectionString').resolves(connectionString); - let result = await projController.readPublishProfileCallback(vscode.Uri.file(profilePath)); + let result = await load(vscode.Uri.file(profilePath), testContext.dacFxService.object); should(result.databaseName).equal('targetDb'); should(Object.keys(result.sqlCmdVariables).length).equal(1); should(result.sqlCmdVariables['ProdDatabaseName']).equal('MyProdDatabase'); should(result.connectionId).equal('connId'); should(result.connectionString).equal('Data Source=testserver;User Id=testUser;Password=******;Integrated Security=false;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Connect Timeout=60;Encrypt=False;TrustServerCertificate=True'); + should(result.options).equal(mockDacFxOptionsResult.deploymentOptions); }); it('Should throw error when connecting does not work', async function (): Promise { diff --git a/extensions/sql-database-projects/src/test/testContext.ts b/extensions/sql-database-projects/src/test/testContext.ts index bd5275882b..bdfa07703c 100644 --- a/extensions/sql-database-projects/src/test/testContext.ts +++ b/extensions/sql-database-projects/src/test/testContext.ts @@ -21,6 +21,91 @@ export const mockDacFxResult = { report: '' }; +export const mockDacFxOptionsResult: mssql.DacFxOptionsResult = { + success: true, + errorMessage: '', + deploymentOptions: { + ignoreTableOptions: false, + ignoreSemicolonBetweenStatements: false, + ignoreRouteLifetime: false, + ignoreRoleMembership: false, + ignoreQuotedIdentifiers: false, + ignorePermissions: false, + ignorePartitionSchemes: false, + ignoreObjectPlacementOnPartitionScheme: false, + ignoreNotForReplication: false, + ignoreLoginSids: false, + ignoreLockHintsOnIndexes: false, + ignoreKeywordCasing: false, + ignoreIndexPadding: false, + ignoreIndexOptions: false, + ignoreIncrement: false, + ignoreIdentitySeed: false, + ignoreUserSettingsObjects: false, + ignoreFullTextCatalogFilePath: false, + ignoreWhitespace: false, + ignoreWithNocheckOnForeignKeys: false, + verifyCollationCompatibility: false, + unmodifiableObjectWarnings: false, + treatVerificationErrorsAsWarnings: false, + scriptRefreshModule: false, + scriptNewConstraintValidation: false, + scriptFileSize: false, + scriptDeployStateChecks: false, + scriptDatabaseOptions: false, + scriptDatabaseCompatibility: false, + scriptDatabaseCollation: false, + runDeploymentPlanExecutors: false, + registerDataTierApplication: false, + populateFilesOnFileGroups: false, + noAlterStatementsToChangeClrTypes: false, + includeTransactionalScripts: false, + includeCompositeObjects: false, + allowUnsafeRowLevelSecurityDataMovement: false, + ignoreWithNocheckOnCheckConstraints: false, + ignoreFillFactor: false, + ignoreFileSize: false, + ignoreFilegroupPlacement: false, + doNotAlterReplicatedObjects: false, + doNotAlterChangeDataCaptureObjects: false, + disableAndReenableDdlTriggers: false, + deployDatabaseInSingleUserMode: false, + createNewDatabase: false, + compareUsingTargetCollation: false, + commentOutSetVarDeclarations: false, + blockWhenDriftDetected: false, + blockOnPossibleDataLoss: false, + backupDatabaseBeforeChanges: false, + allowIncompatiblePlatform: false, + allowDropBlockingAssemblies: false, + dropConstraintsNotInSource: false, + dropDmlTriggersNotInSource: false, + dropExtendedPropertiesNotInSource: false, + dropIndexesNotInSource: false, + ignoreFileAndLogFilePath: false, + ignoreExtendedProperties: false, + ignoreDmlTriggerState: false, + ignoreDmlTriggerOrder: false, + ignoreDefaultSchema: false, + ignoreDdlTriggerState: false, + ignoreDdlTriggerOrder: false, + ignoreCryptographicProviderFilePath: false, + verifyDeployment: false, + ignoreComments: false, + ignoreColumnCollation: false, + ignoreAuthorizer: false, + ignoreAnsiNulls: false, + generateSmartDefaults: false, + dropStatisticsNotInSource: false, + dropRoleMembersNotInSource: false, + dropPermissionsNotInSource: false, + dropObjectsNotInSource: false, + ignoreColumnOrder: false, + doNotDropObjectTypes: [], + excludeObjectTypes: [] + } +}; + export class MockDacFxService implements mssql.IDacFxService { public exportBacpac(_: string, __: string, ___: string, ____: azdata.TaskExecutionMode): Thenable { return Promise.resolve(mockDacFxResult); } public importBacpac(_: string, __: string, ___: string, ____: azdata.TaskExecutionMode): Thenable { return Promise.resolve(mockDacFxResult); } @@ -29,6 +114,7 @@ export class MockDacFxService implements mssql.IDacFxService { public deployDacpac(_: string, __: string, ___: boolean, ____: string, _____: azdata.TaskExecutionMode, ______?: Record): Thenable { return Promise.resolve(mockDacFxResult); } public generateDeployScript(_: string, __: string, ___: string, ____: azdata.TaskExecutionMode, ______?: Record): Thenable { return Promise.resolve(mockDacFxResult); } public generateDeployPlan(_: string, __: string, ___: string, ____: azdata.TaskExecutionMode): Thenable { return Promise.resolve(mockDacFxResult); } + public getOptionsFromProfile(_: string): Thenable { return Promise.resolve(mockDacFxOptionsResult); } } export function createContext(): TestContext {