mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-14 01:25:37 -05:00
SQL Project: Opening connection viewlet after deploying database (#19544)
This commit is contained in:
@@ -47,6 +47,7 @@ import { ILocalDbDeployProfile, ISqlDbDeployProfile } from '../models/deploy/dep
|
||||
import { EntryType, FileProjectEntry, IDatabaseReferenceProjectEntry, SqlProjectReferenceProjectEntry } from '../models/projectEntry';
|
||||
import { UpdateProjectAction, UpdateProjectDataModel } from '../models/api/updateProject';
|
||||
import { AzureSqlClient } from '../models/deploy/azureSqlClient';
|
||||
import { ConnectionService } from '../models/connections/connectionService';
|
||||
|
||||
const maxTableLength = 10;
|
||||
|
||||
@@ -74,6 +75,7 @@ export class ProjectsController {
|
||||
private buildInfo: DashboardData[] = [];
|
||||
private publishInfo: PublishData[] = [];
|
||||
private deployService: DeployService;
|
||||
private connectionService: ConnectionService;
|
||||
private azureSqlClient: AzureSqlClient;
|
||||
private autorestHelper: AutorestHelper;
|
||||
|
||||
@@ -84,6 +86,7 @@ export class ProjectsController {
|
||||
this.buildHelper = new BuildHelper();
|
||||
this.azureSqlClient = new AzureSqlClient();
|
||||
this.deployService = new DeployService(this.azureSqlClient, this._outputChannel);
|
||||
this.connectionService = new ConnectionService(this._outputChannel);
|
||||
this.autorestHelper = new AutorestHelper(this._outputChannel);
|
||||
}
|
||||
|
||||
@@ -293,7 +296,7 @@ export class ProjectsController {
|
||||
if (deployProfile.sqlDbSetting) {
|
||||
|
||||
// Connecting to the deployed db to add the profile to connection viewlet
|
||||
await this.deployService.getConnection(deployProfile.sqlDbSetting, true, deployProfile.sqlDbSetting.dbName);
|
||||
await this.connectionService.getConnection(deployProfile.sqlDbSetting, true, deployProfile.sqlDbSetting.dbName);
|
||||
}
|
||||
void vscode.window.showInformationMessage(constants.publishProjectSucceed);
|
||||
} else {
|
||||
@@ -335,7 +338,7 @@ export class ProjectsController {
|
||||
const publishResult = await this.publishOrScriptProject(project, deployProfile.deploySettings, true);
|
||||
if (publishResult && publishResult.success) {
|
||||
if (deployProfile.localDbSetting) {
|
||||
await this.deployService.getConnection(deployProfile.localDbSetting, true, deployProfile.localDbSetting.dbName);
|
||||
await this.connectionService.getConnection(deployProfile.localDbSetting, true, deployProfile.localDbSetting.dbName);
|
||||
}
|
||||
void vscode.window.showInformationMessage(constants.publishProjectSucceed);
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as constants from '../../common/constants';
|
||||
import * as utils from '../../common/utils';
|
||||
import * as vscode from 'vscode';
|
||||
import { ConnectionResult } from 'azdata';
|
||||
import { IFireWallRuleError } from 'vscode-mssql';
|
||||
|
||||
export interface ISqlConnectionProperties {
|
||||
tenantId?: string,
|
||||
accountId?: string
|
||||
serverName: string,
|
||||
userName: string,
|
||||
password: string,
|
||||
port: number,
|
||||
dbName: string,
|
||||
profileName?: string,
|
||||
connectionRetryTimeout?: number
|
||||
}
|
||||
|
||||
/**
|
||||
* Includes methods to open connections and interact with connection views
|
||||
*/
|
||||
export class ConnectionService {
|
||||
|
||||
constructor(private _outputChannel: vscode.OutputChannel) {
|
||||
}
|
||||
|
||||
private defaultSqlRetryTimeoutInSec: number = 10;
|
||||
private defaultSqlNumberOfRetries: number = 3;
|
||||
|
||||
/**
|
||||
* Connects to a database
|
||||
* @param profile connection profile
|
||||
* @param saveConnectionAndPassword if true, connection will be saved in the connection view
|
||||
* @param database database name
|
||||
* @returns
|
||||
*/
|
||||
private async connectToDatabase(profile: ISqlConnectionProperties, saveConnectionAndPassword: boolean, database: string): Promise<ConnectionResult | string | undefined> {
|
||||
const azdataApi = utils.getAzdataApi();
|
||||
const vscodeMssqlApi = azdataApi ? undefined : await utils.getVscodeMssqlApi();
|
||||
if (azdataApi) {
|
||||
const connectionProfile = {
|
||||
password: profile.password,
|
||||
serverName: `${profile.serverName},${profile.port}`,
|
||||
database: database,
|
||||
savePassword: saveConnectionAndPassword,
|
||||
userName: profile.userName,
|
||||
providerName: 'MSSQL',
|
||||
saveProfile: false,
|
||||
id: '',
|
||||
connectionName: profile.profileName,
|
||||
options: [],
|
||||
authenticationType: 'SqlLogin'
|
||||
};
|
||||
return await azdataApi.connection.connect(connectionProfile, saveConnectionAndPassword, false);
|
||||
} else if (vscodeMssqlApi) {
|
||||
const connectionProfile = {
|
||||
password: profile.password,
|
||||
server: `${profile.serverName}`,
|
||||
port: profile.port,
|
||||
database: database,
|
||||
savePassword: saveConnectionAndPassword,
|
||||
user: profile.userName,
|
||||
authenticationType: 'SqlLogin',
|
||||
encrypt: false,
|
||||
connectTimeout: 30,
|
||||
applicationName: 'SQL Database Project',
|
||||
accountId: profile.accountId,
|
||||
azureAccountToken: undefined,
|
||||
applicationIntent: undefined,
|
||||
attachDbFilename: undefined,
|
||||
connectRetryCount: undefined,
|
||||
connectRetryInterval: undefined,
|
||||
connectionString: undefined,
|
||||
currentLanguage: undefined,
|
||||
email: undefined,
|
||||
failoverPartner: undefined,
|
||||
loadBalanceTimeout: undefined,
|
||||
maxPoolSize: undefined,
|
||||
minPoolSize: undefined,
|
||||
multiSubnetFailover: undefined,
|
||||
multipleActiveResultSets: undefined,
|
||||
packetSize: undefined,
|
||||
persistSecurityInfo: undefined,
|
||||
pooling: undefined,
|
||||
replication: undefined,
|
||||
trustServerCertificate: undefined,
|
||||
typeSystemVersion: undefined,
|
||||
workstationId: undefined,
|
||||
profileName: profile.profileName,
|
||||
expiresOn: undefined,
|
||||
tenantId: profile.tenantId
|
||||
};
|
||||
let connectionUrl = '';
|
||||
try {
|
||||
connectionUrl = await vscodeMssqlApi.connect(connectionProfile, saveConnectionAndPassword);
|
||||
} catch (err) {
|
||||
const firewallRuleError = <IFireWallRuleError>err;
|
||||
if (firewallRuleError?.connectionUri) {
|
||||
await vscodeMssqlApi.promptForFirewallRule(err.connectionUri, connectionProfile);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
// If connected successfully and saved the connection in the view, open the connection view
|
||||
if (saveConnectionAndPassword && connectionUrl) {
|
||||
await vscode.commands.executeCommand('objectExplorer.focus');
|
||||
}
|
||||
return connectionUrl;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the connection result. If using azdata API, verifies connection was successful and connection id is returns
|
||||
* If using vscode API, verifies the connection url is returns
|
||||
* @param connection connection result or connection Id
|
||||
* @returns validation result
|
||||
*/
|
||||
private async validateConnection(connection: ConnectionResult | string | undefined): Promise<utils.ValidationResult> {
|
||||
const azdataApi = utils.getAzdataApi();
|
||||
if (!connection) {
|
||||
return { validated: false, errorMessage: constants.connectionFailedError('No result returned') };
|
||||
} else if (azdataApi) {
|
||||
const connectionResult = <ConnectionResult>connection;
|
||||
if (connectionResult) {
|
||||
const connected = connectionResult !== undefined && connectionResult.connected && connectionResult.connectionId !== undefined;
|
||||
return { validated: connected, errorMessage: connected ? '' : constants.connectionFailedError(connectionResult?.errorMessage!) };
|
||||
} else {
|
||||
return { validated: false, errorMessage: constants.connectionFailedError('') };
|
||||
}
|
||||
} else {
|
||||
return { validated: connection !== undefined, errorMessage: constants.connectionFailedError('') };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats connection result to string to be able to add to log
|
||||
* @param connection connection result or connection Id
|
||||
* @returns formatted connection result
|
||||
*/
|
||||
private async formatConnectionResult(connection: ConnectionResult | string | undefined): Promise<string> {
|
||||
const azdataApi = utils.getAzdataApi();
|
||||
const connectionResult = connection !== undefined && azdataApi ? <ConnectionResult>connection : undefined;
|
||||
return connectionResult?.connected ? connectionResult.connectionId! : <string>connection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a connections and returns the connection id
|
||||
* @param profile connection profile
|
||||
* @param saveConnectionAndPassword is set to true the connection will be saved in the connection view
|
||||
* @param database database name
|
||||
* @returns connection id
|
||||
*/
|
||||
public async getConnection(profile: ISqlConnectionProperties, saveConnectionAndPassword: boolean, database: string): Promise<string | undefined> {
|
||||
const azdataApi = utils.getAzdataApi();
|
||||
let connection = await utils.retry(
|
||||
constants.connectingToSqlServerMessage,
|
||||
async () => {
|
||||
return await this.connectToDatabase(profile, saveConnectionAndPassword, database);
|
||||
},
|
||||
this.validateConnection,
|
||||
this.formatConnectionResult,
|
||||
this._outputChannel,
|
||||
this.defaultSqlNumberOfRetries, profile.connectionRetryTimeout || this.defaultSqlRetryTimeoutInSec);
|
||||
|
||||
if (connection) {
|
||||
const connectionResult = <ConnectionResult>connection;
|
||||
if (azdataApi) {
|
||||
utils.throwIfNotConnected(connectionResult);
|
||||
return azdataApi.connection.getUriForConnection(connectionResult.connectionId!);
|
||||
} else {
|
||||
return <string>connection;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
import { IDeploySettings } from '../IDeploySettings';
|
||||
import type * as azdataType from 'azdata';
|
||||
import { IAzureAccountSession } from 'vscode-mssql';
|
||||
import { ISqlConnectionProperties } from '../connections/connectionService';
|
||||
|
||||
export enum AppSettingType {
|
||||
None,
|
||||
@@ -38,17 +39,7 @@ export interface ILocalDbSetting extends ISqlConnectionProperties {
|
||||
dockerBaseImageEula: string,
|
||||
}
|
||||
|
||||
export interface ISqlConnectionProperties {
|
||||
tenantId?: string,
|
||||
accountId?: string
|
||||
serverName: string,
|
||||
userName: string,
|
||||
password: string,
|
||||
port: number,
|
||||
dbName: string,
|
||||
profileName?: string,
|
||||
connectionRetryTimeout?: number
|
||||
}
|
||||
|
||||
|
||||
export interface DockerImageInfo {
|
||||
name: string,
|
||||
|
||||
@@ -3,18 +3,15 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { AppSettingType, IDeployAppIntegrationProfile, ILocalDbDeployProfile, ILocalDbSetting, ISqlConnectionProperties, ISqlDbDeployProfile } from './deployProfile';
|
||||
import { ILocalDbDeployProfile, ILocalDbSetting, ISqlDbDeployProfile } from './deployProfile';
|
||||
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
|
||||
import { Project } from '../project';
|
||||
import * as constants from '../../common/constants';
|
||||
import * as utils from '../../common/utils';
|
||||
import * as fse from 'fs-extra';
|
||||
import * as vscode from 'vscode';
|
||||
import { ConnectionResult } from 'azdata';
|
||||
import * as templates from '../../templates/templates';
|
||||
import { ShellExecutionHelper } from '../../tools/shellExecutionHelper';
|
||||
import { AzureSqlClient } from './azureSqlClient';
|
||||
import { IFireWallRuleError } from 'vscode-mssql';
|
||||
import { ConnectionService } from '../connections/connectionService';
|
||||
|
||||
interface DockerImageSpec {
|
||||
label: string;
|
||||
@@ -25,73 +22,11 @@ export class DeployService {
|
||||
|
||||
constructor(private _azureSqlClient = new AzureSqlClient(), private _outputChannel: vscode.OutputChannel, shellExecutionHelper: ShellExecutionHelper | undefined = undefined) {
|
||||
this._shellExecutionHelper = shellExecutionHelper ?? new ShellExecutionHelper(this._outputChannel);
|
||||
this._connectionService = new ConnectionService(this._outputChannel);
|
||||
}
|
||||
|
||||
private _shellExecutionHelper: ShellExecutionHelper;
|
||||
private DefaultSqlRetryTimeoutInSec: number = 10;
|
||||
private DefaultSqlNumberOfRetries: number = 3;
|
||||
|
||||
private createConnectionStringTemplate(runtime: string | undefined): string {
|
||||
switch (runtime?.toLocaleLowerCase()) {
|
||||
case 'dotnet':
|
||||
return constants.defaultConnectionStringTemplate;
|
||||
break;
|
||||
// TODO: add connection strings for other languages
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
private findAppRuntime(profile: IDeployAppIntegrationProfile, appSettingContent: any): string | undefined {
|
||||
switch (profile.appSettingType) {
|
||||
case AppSettingType.AzureFunction:
|
||||
return <string>appSettingContent?.Values['FUNCTIONS_WORKER_RUNTIME'];
|
||||
default:
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public async updateAppSettings(profile: IDeployAppIntegrationProfile, deployProfile: ILocalDbDeployProfile | undefined): Promise<void> {
|
||||
// Update app settings
|
||||
//
|
||||
if (!profile.appSettingFile) {
|
||||
return;
|
||||
}
|
||||
this.logToOutput(constants.deployAppSettingUpdating(profile.appSettingFile));
|
||||
|
||||
// TODO: handle parsing errors
|
||||
let content = JSON.parse(fse.readFileSync(profile.appSettingFile, 'utf8'));
|
||||
if (content && content.Values) {
|
||||
let connectionString: string | undefined = '';
|
||||
if (deployProfile && deployProfile.localDbSetting) {
|
||||
// Find the runtime and generate the connection string for the runtime
|
||||
//
|
||||
const runtime = this.findAppRuntime(profile, content);
|
||||
let connectionStringTemplate = this.createConnectionStringTemplate(runtime);
|
||||
const macroDict: Record<string, string> = {
|
||||
'SERVER': deployProfile?.localDbSetting?.serverName || '',
|
||||
'PORT': deployProfile?.localDbSetting?.port?.toString() || '',
|
||||
'USER': deployProfile?.localDbSetting?.userName || '',
|
||||
'SA_PASSWORD': deployProfile?.localDbSetting?.password || '',
|
||||
'DATABASE': deployProfile?.localDbSetting?.dbName || '',
|
||||
};
|
||||
|
||||
connectionString = templates.macroExpansion(connectionStringTemplate, macroDict);
|
||||
} else if (deployProfile?.deploySettings?.connectionUri) {
|
||||
connectionString = await this.getConnectionString(deployProfile?.deploySettings?.connectionUri);
|
||||
}
|
||||
|
||||
if (connectionString && profile.envVariableName) {
|
||||
content.Values[profile.envVariableName] = connectionString;
|
||||
fse.writeFileSync(profile.appSettingFile, JSON.stringify(content, undefined, 4));
|
||||
this.logToOutput(`app setting '${profile.appSettingFile}' has been updated. env variable name: ${profile.envVariableName} connection String: ${connectionString}`);
|
||||
|
||||
} else {
|
||||
this.logToOutput(constants.deployAppSettingUpdateFailed(profile.appSettingFile));
|
||||
}
|
||||
}
|
||||
}
|
||||
private _connectionService: ConnectionService;
|
||||
|
||||
private async verifyDocker(): Promise<void> {
|
||||
try {
|
||||
@@ -149,7 +84,7 @@ export class DeployService {
|
||||
this.logToOutput(constants.azureSqlServerCreated(profile?.sqlDbSetting?.serverName));
|
||||
|
||||
// Connect to the server
|
||||
return await this.getConnection(profile.sqlDbSetting, false, constants.master);
|
||||
return await this._connectionService.getConnection(profile.sqlDbSetting, false, constants.master);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
@@ -209,7 +144,7 @@ export class DeployService {
|
||||
|
||||
if (runningDockerId) {
|
||||
this.logToOutput(constants.dockerContainerCreatedMessage(runningDockerId));
|
||||
return await this.getConnection(profile.localDbSetting, false, 'master');
|
||||
return await this._connectionService.getConnection(profile.localDbSetting, false, 'master');
|
||||
|
||||
} else {
|
||||
this.logToOutput(constants.dockerContainerFailedToRunErrorMessage);
|
||||
@@ -235,145 +170,6 @@ export class DeployService {
|
||||
return await this.executeCommand(`docker ps -q -a --filter label=${dockerImageSpec.label} -q`);
|
||||
}
|
||||
|
||||
private async getConnectionString(connectionUri: string): Promise<string | undefined> {
|
||||
const azdataApi = utils.getAzdataApi();
|
||||
if (azdataApi) {
|
||||
const connection = await azdataApi.connection.getConnection(connectionUri);
|
||||
if (connection) {
|
||||
return await azdataApi.connection.getConnectionString(connection.connectionId, true);
|
||||
}
|
||||
}
|
||||
// TODO: vscode connections string
|
||||
|
||||
return undefined;
|
||||
|
||||
}
|
||||
|
||||
// Connects to a database
|
||||
private async connectToDatabase(profile: ISqlConnectionProperties, saveConnectionAndPassword: boolean, database: string): Promise<ConnectionResult | string | undefined> {
|
||||
const azdataApi = utils.getAzdataApi();
|
||||
const vscodeMssqlApi = azdataApi ? undefined : await utils.getVscodeMssqlApi();
|
||||
if (azdataApi) {
|
||||
const connectionProfile = {
|
||||
password: profile.password,
|
||||
serverName: `${profile.serverName},${profile.port}`,
|
||||
database: database,
|
||||
savePassword: saveConnectionAndPassword,
|
||||
userName: profile.userName,
|
||||
providerName: 'MSSQL',
|
||||
saveProfile: false,
|
||||
id: '',
|
||||
connectionName: profile.profileName,
|
||||
options: [],
|
||||
authenticationType: 'SqlLogin'
|
||||
};
|
||||
return await azdataApi.connection.connect(connectionProfile, saveConnectionAndPassword, false);
|
||||
} else if (vscodeMssqlApi) {
|
||||
const connectionProfile = {
|
||||
password: profile.password,
|
||||
server: `${profile.serverName}`,
|
||||
port: profile.port,
|
||||
database: database,
|
||||
savePassword: saveConnectionAndPassword,
|
||||
user: profile.userName,
|
||||
authenticationType: 'SqlLogin',
|
||||
encrypt: false,
|
||||
connectTimeout: 30,
|
||||
applicationName: 'SQL Database Project',
|
||||
accountId: profile.accountId,
|
||||
azureAccountToken: undefined,
|
||||
applicationIntent: undefined,
|
||||
attachDbFilename: undefined,
|
||||
connectRetryCount: undefined,
|
||||
connectRetryInterval: undefined,
|
||||
connectionString: undefined,
|
||||
currentLanguage: undefined,
|
||||
email: undefined,
|
||||
failoverPartner: undefined,
|
||||
loadBalanceTimeout: undefined,
|
||||
maxPoolSize: undefined,
|
||||
minPoolSize: undefined,
|
||||
multiSubnetFailover: undefined,
|
||||
multipleActiveResultSets: undefined,
|
||||
packetSize: undefined,
|
||||
persistSecurityInfo: undefined,
|
||||
pooling: undefined,
|
||||
replication: undefined,
|
||||
trustServerCertificate: undefined,
|
||||
typeSystemVersion: undefined,
|
||||
workstationId: undefined,
|
||||
profileName: profile.profileName,
|
||||
expiresOn: undefined,
|
||||
tenantId: profile.tenantId
|
||||
};
|
||||
let connectionUrl = '';
|
||||
try {
|
||||
connectionUrl = await vscodeMssqlApi.connect(connectionProfile, saveConnectionAndPassword);
|
||||
} catch (err) {
|
||||
const firewallRuleError = <IFireWallRuleError>err;
|
||||
if (firewallRuleError?.connectionUri) {
|
||||
await vscodeMssqlApi.promptForFirewallRule(err.connectionUri, connectionProfile);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
return connectionUrl;
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// Validates the connection result. If using azdata API, verifies connection was successful and connection id is returns
|
||||
// If using vscode API, verifies the connection url is returns
|
||||
private async validateConnection(connection: ConnectionResult | string | undefined): Promise<utils.ValidationResult> {
|
||||
const azdataApi = utils.getAzdataApi();
|
||||
if (!connection) {
|
||||
return { validated: false, errorMessage: constants.connectionFailedError('No result returned') };
|
||||
} else if (azdataApi) {
|
||||
const connectionResult = <ConnectionResult>connection;
|
||||
if (connectionResult) {
|
||||
const connected = connectionResult !== undefined && connectionResult.connected && connectionResult.connectionId !== undefined;
|
||||
return { validated: connected, errorMessage: connected ? '' : constants.connectionFailedError(connectionResult?.errorMessage!) };
|
||||
} else {
|
||||
return { validated: false, errorMessage: constants.connectionFailedError('') };
|
||||
}
|
||||
} else {
|
||||
return { validated: connection !== undefined, errorMessage: constants.connectionFailedError('') };
|
||||
}
|
||||
}
|
||||
|
||||
// Formats connection result to string to be able to add to log
|
||||
private async formatConnectionResult(connection: ConnectionResult | string | undefined): Promise<string> {
|
||||
const azdataApi = utils.getAzdataApi();
|
||||
const connectionResult = connection !== undefined && azdataApi ? <ConnectionResult>connection : undefined;
|
||||
return connectionResult?.connected ? connectionResult.connectionId! : <string>connection;
|
||||
}
|
||||
|
||||
public async getConnection(profile: ISqlConnectionProperties, saveConnectionAndPassword: boolean, database: string): Promise<string | undefined> {
|
||||
const azdataApi = utils.getAzdataApi();
|
||||
let connection = await utils.retry(
|
||||
constants.connectingToSqlServerMessage,
|
||||
async () => {
|
||||
return await this.connectToDatabase(profile, saveConnectionAndPassword, database);
|
||||
},
|
||||
this.validateConnection,
|
||||
this.formatConnectionResult,
|
||||
this._outputChannel,
|
||||
this.DefaultSqlNumberOfRetries, profile.connectionRetryTimeout || this.DefaultSqlRetryTimeoutInSec);
|
||||
|
||||
if (connection) {
|
||||
const connectionResult = <ConnectionResult>connection;
|
||||
if (azdataApi) {
|
||||
utils.throwIfNotConnected(connectionResult);
|
||||
return azdataApi.connection.getUriForConnection(connectionResult.connectionId!);
|
||||
} else {
|
||||
return <string>connection;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async executeTask<T>(taskName: string, task: () => Promise<T>): Promise<T> {
|
||||
const azdataApi = utils.getAzdataApi();
|
||||
if (azdataApi) {
|
||||
|
||||
@@ -11,14 +11,13 @@ import { DeployService } from '../../models/deploy/deployService';
|
||||
import { Project } from '../../models/project';
|
||||
import * as vscode from 'vscode';
|
||||
import * as azdata from 'azdata';
|
||||
import { AppSettingType, ILocalDbDeployProfile, ISqlDbDeployProfile } from '../../models/deploy/deployProfile';
|
||||
import { ILocalDbDeployProfile, ISqlDbDeployProfile } from '../../models/deploy/deployProfile';
|
||||
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
|
||||
import * as fse from 'fs-extra';
|
||||
import * as path from 'path';
|
||||
import * as constants from '../../common/constants';
|
||||
import { ShellExecutionHelper } from '../../tools/shellExecutionHelper';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import { AzureSqlClient } from '../../models/deploy/azureSqlClient';
|
||||
import { ConnectionService } from '../../models/connections/connectionService';
|
||||
|
||||
export interface TestContext {
|
||||
outputChannel: vscode.OutputChannel;
|
||||
@@ -140,125 +139,17 @@ describe('deploy service', function (): void {
|
||||
const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper);
|
||||
shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(),
|
||||
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id'));
|
||||
const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object);
|
||||
const connectionService = new ConnectionService(testContext.outputChannel);
|
||||
let connectionStub = sandbox.stub(azdata.connection, 'connect');
|
||||
connectionStub.onFirstCall().returns(Promise.resolve(mockFailedConnectionResult));
|
||||
connectionStub.onSecondCall().returns(Promise.resolve(mockConnectionResult));
|
||||
sandbox.stub(azdata.connection, 'getUriForConnection').returns(Promise.resolve('connection'));
|
||||
sandbox.stub(azdata.tasks, 'startBackgroundOperation').callThrough();
|
||||
|
||||
let connection = await deployService.getConnection(localDbSettings, false, 'master');
|
||||
let connection = await connectionService.getConnection(localDbSettings, false, 'master');
|
||||
should(connection).equals('connection');
|
||||
});
|
||||
|
||||
it('Should update app settings successfully', async function (): Promise<void> {
|
||||
const testContext = createContext();
|
||||
const projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
||||
const project1 = await Project.openProject(vscode.Uri.file(projFilePath).fsPath);
|
||||
const jsondData =
|
||||
{
|
||||
IsEncrypted: false,
|
||||
Values: {
|
||||
AzureWebJobsStorage: 'UseDevelopmentStorage=true',
|
||||
FUNCTIONS_WORKER_RUNTIME: 'dotnet'
|
||||
}
|
||||
};
|
||||
let settingContent = JSON.stringify(jsondData, undefined, 4);
|
||||
const expected =
|
||||
{
|
||||
IsEncrypted: false,
|
||||
Values: {
|
||||
AzureWebJobsStorage: 'UseDevelopmentStorage=true',
|
||||
FUNCTIONS_WORKER_RUNTIME: 'dotnet',
|
||||
SQLConnectionString: 'Data Source=localhost,1433;Initial Catalog=test;User id=sa;Password=PLACEHOLDER;'
|
||||
}
|
||||
};
|
||||
const filePath = path.join(project1.projectFolderPath, 'local.settings.json');
|
||||
await fse.writeFile(filePath, settingContent);
|
||||
|
||||
const deployProfile: ILocalDbDeployProfile = {
|
||||
localDbSetting: {
|
||||
dbName: 'test',
|
||||
password: 'PLACEHOLDER',
|
||||
port: 1433,
|
||||
serverName: 'localhost',
|
||||
userName: 'sa',
|
||||
dockerBaseImage: 'image',
|
||||
dockerBaseImageEula: ''
|
||||
}
|
||||
};
|
||||
|
||||
const appInteg = {
|
||||
appSettingType: AppSettingType.AzureFunction,
|
||||
appSettingFile: filePath,
|
||||
deploySettings: undefined,
|
||||
envVariableName: 'SQLConnectionString'
|
||||
};
|
||||
|
||||
const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper);
|
||||
shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(),
|
||||
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id'));
|
||||
const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object);
|
||||
|
||||
await deployService.updateAppSettings(appInteg, deployProfile);
|
||||
let newContent = JSON.parse(fse.readFileSync(filePath, 'utf8'));
|
||||
should(newContent).deepEqual(expected);
|
||||
|
||||
});
|
||||
|
||||
it('Should update app settings using connection uri if there are no local settings', async function (): Promise<void> {
|
||||
const testContext = createContext();
|
||||
const projFilePath = await testUtils.createTestSqlProjFile(baselines.newProjectFileBaseline);
|
||||
const project1 = await Project.openProject(vscode.Uri.file(projFilePath).fsPath);
|
||||
const jsondData =
|
||||
{
|
||||
IsEncrypted: false,
|
||||
Values: {
|
||||
AzureWebJobsStorage: 'UseDevelopmentStorage=true',
|
||||
FUNCTIONS_WORKER_RUNTIME: 'dotnet'
|
||||
}
|
||||
};
|
||||
let settingContent = JSON.stringify(jsondData, undefined, 4);
|
||||
const expected =
|
||||
{
|
||||
IsEncrypted: false,
|
||||
Values: {
|
||||
AzureWebJobsStorage: 'UseDevelopmentStorage=true',
|
||||
FUNCTIONS_WORKER_RUNTIME: 'dotnet',
|
||||
SQLConnectionString: 'connectionString'
|
||||
}
|
||||
};
|
||||
const filePath = path.join(project1.projectFolderPath, 'local.settings.json');
|
||||
await fse.writeFile(filePath, settingContent);
|
||||
|
||||
const deployProfile: ILocalDbDeployProfile = {
|
||||
|
||||
deploySettings: {
|
||||
connectionUri: 'connection',
|
||||
databaseName: 'test',
|
||||
serverName: 'test'
|
||||
},
|
||||
localDbSetting: undefined
|
||||
};
|
||||
|
||||
const appInteg = {
|
||||
appSettingType: AppSettingType.AzureFunction,
|
||||
appSettingFile: filePath,
|
||||
envVariableName: 'SQLConnectionString',
|
||||
};
|
||||
const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper);
|
||||
shellExecutionHelper.setup(x => x.runStreamedCommand(TypeMoq.It.isAny(),
|
||||
undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve('id'));
|
||||
const deployService = new DeployService(testContext.azureSqlClient.object, testContext.outputChannel, shellExecutionHelper.object);
|
||||
let connection = new azdata.connection.ConnectionProfile();
|
||||
sandbox.stub(azdata.connection, 'getConnection').returns(Promise.resolve(connection));
|
||||
|
||||
sandbox.stub(azdata.connection, 'getConnectionString').returns(Promise.resolve('connectionString'));
|
||||
await deployService.updateAppSettings(appInteg, deployProfile);
|
||||
let newContent = JSON.parse(fse.readFileSync(filePath, 'utf8'));
|
||||
should(newContent).deepEqual(expected);
|
||||
});
|
||||
|
||||
it('Should clean a list of docker images successfully', async function (): Promise<void> {
|
||||
const testContext = createContext();
|
||||
const shellExecutionHelper = TypeMoq.Mock.ofType(ShellExecutionHelper);
|
||||
|
||||
Reference in New Issue
Block a user