mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-14 01:25:37 -05:00
@@ -97,10 +97,24 @@ export class TestCapabilitiesService implements ICapabilitiesService {
|
||||
valueType: ServiceOptionType.string
|
||||
}
|
||||
];
|
||||
let mssqlAdvancedOptions: azdata.ConnectionOption[] = [
|
||||
{
|
||||
name: 'trustServerCertificate',
|
||||
displayName: undefined!,
|
||||
description: undefined!,
|
||||
groupName: undefined!,
|
||||
categoryValues: undefined!,
|
||||
defaultValue: 'false',
|
||||
isIdentity: false,
|
||||
isRequired: false,
|
||||
specialValueType: undefined!,
|
||||
valueType: ServiceOptionType.boolean
|
||||
}
|
||||
];
|
||||
let msSQLCapabilities = {
|
||||
providerId: mssqlProviderName,
|
||||
displayName: 'MSSQL',
|
||||
connectionOptions: connectionProvider,
|
||||
connectionOptions: connectionProvider.concat(mssqlAdvancedOptions),
|
||||
};
|
||||
let pgSQLCapabilities = {
|
||||
providerId: this.pgsqlProviderName,
|
||||
|
||||
@@ -202,6 +202,27 @@ export class ProviderConnectionInfo implements azdata.ConnectionInfo {
|
||||
* Example: "providerName:MSSQL|authenticationType:|databaseName:database|serverName:server3|userName:user|group:testid"
|
||||
*/
|
||||
public getOptionsKey(): string {
|
||||
let idNames = this.getOptionKeyIdNames();
|
||||
idNames = idNames.filter(x => x !== undefined);
|
||||
|
||||
//Sort to make sure using names in the same order every time otherwise the ids would be different
|
||||
idNames.sort();
|
||||
|
||||
let idValues: string[] = [];
|
||||
for (let index = 0; index < idNames.length; index++) {
|
||||
let value = this.options[idNames[index]!];
|
||||
value = value ? value : '';
|
||||
idValues.push(`${idNames[index]}${ProviderConnectionInfo.nameValueSeparator}${value}`);
|
||||
}
|
||||
|
||||
return ProviderConnectionInfo.ProviderPropertyName + ProviderConnectionInfo.nameValueSeparator +
|
||||
this.providerName + ProviderConnectionInfo.idSeparator + idValues.join(ProviderConnectionInfo.idSeparator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns Array of option key names
|
||||
*/
|
||||
public getOptionKeyIdNames(): string[] {
|
||||
let idNames = [];
|
||||
if (this.serverCapabilities) {
|
||||
idNames = this.serverCapabilities.connectionOptions.map(o => {
|
||||
@@ -217,21 +238,7 @@ export class ProviderConnectionInfo implements azdata.ConnectionInfo {
|
||||
// This should never happen but just incase the serverCapabilities was not ready at this time
|
||||
idNames = ['authenticationType', 'database', 'server', 'user'];
|
||||
}
|
||||
|
||||
idNames = idNames.filter(x => x !== undefined);
|
||||
|
||||
//Sort to make sure using names in the same order every time otherwise the ids would be different
|
||||
idNames.sort();
|
||||
|
||||
let idValues: string[] = [];
|
||||
for (let index = 0; index < idNames.length; index++) {
|
||||
let value = this.options[idNames[index]!];
|
||||
value = value ? value : '';
|
||||
idValues.push(`${idNames[index]}${ProviderConnectionInfo.nameValueSeparator}${value}`);
|
||||
}
|
||||
|
||||
return ProviderConnectionInfo.ProviderPropertyName + ProviderConnectionInfo.nameValueSeparator +
|
||||
this.providerName + ProviderConnectionInfo.idSeparator + idValues.join(ProviderConnectionInfo.idSeparator);
|
||||
return idNames;
|
||||
}
|
||||
|
||||
public static getProviderFromOptionsKey(optionsKey: string) {
|
||||
|
||||
@@ -31,17 +31,61 @@ import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/envi
|
||||
import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
|
||||
|
||||
export interface SqlArgs {
|
||||
/**
|
||||
* Used to determine file paths to be opened with SQL Editor.
|
||||
* If provided, we connect the given profile to to it.
|
||||
* More than one files can be passed to connect to provided profile.
|
||||
*/
|
||||
_?: string[];
|
||||
/**
|
||||
* Provide authenticationType to be used.
|
||||
* accepted values: AzureMFA, SqlLogin, Integrated, etc.
|
||||
*/
|
||||
authenticationType?: string
|
||||
/**
|
||||
* Name of database
|
||||
*/
|
||||
database?: string;
|
||||
/**
|
||||
* Name of server
|
||||
*/
|
||||
server?: string;
|
||||
/**
|
||||
* User name/email address
|
||||
*/
|
||||
user?: string;
|
||||
/**
|
||||
* Operation to perform:
|
||||
* accepted values: connect, openConnectionDialog
|
||||
*/
|
||||
command?: string;
|
||||
/**
|
||||
* Name of connection provider,
|
||||
* accepted values: mssql (by default), pgsql, etc.
|
||||
*/
|
||||
provider?: string;
|
||||
aad?: boolean; // deprecated - used by SSMS - authenticationType should be used instead
|
||||
integrated?: boolean; // deprecated - used by SSMS - authenticationType should be used instead.
|
||||
/**
|
||||
* Deprecated - used by SSMS - authenticationType should be used instead
|
||||
*/
|
||||
aad?: boolean;
|
||||
/**
|
||||
* Deprecated - used by SSMS - authenticationType should be used instead.
|
||||
*/
|
||||
integrated?: boolean;
|
||||
/**
|
||||
* Whether or not to show dashboard
|
||||
* accepted values: true, false (by default).
|
||||
*/
|
||||
showDashboard?: boolean;
|
||||
/**
|
||||
* Supports providing applicationName that will be used for connection profile app name.
|
||||
*/
|
||||
applicationName?: string;
|
||||
/**
|
||||
* Supports providing advanced connection properties that providers support.
|
||||
* Value must be a json object containing key-value pairs in format: '{"key1":"value1","key2":"value2",...}'
|
||||
*/
|
||||
connectionProperties?: string;
|
||||
}
|
||||
|
||||
//#region decorators
|
||||
@@ -324,9 +368,33 @@ export class CommandLineWorkbenchContribution implements IWorkbenchContribution,
|
||||
profile.setOptionValue('applicationName', applicationName);
|
||||
profile.setOptionValue('databaseDisplayName', profile.databaseName);
|
||||
profile.setOptionValue('groupId', profile.groupId);
|
||||
// Set all advanced options
|
||||
let advancedOptions = this.getAdvancedOptions(args.connectionProperties, profile.getOptionKeyIdNames());
|
||||
advancedOptions.forEach((v, k) => {
|
||||
profile.setOptionValue(k, v);
|
||||
});
|
||||
return this._connectionManagementService ? this.tryMatchSavedProfile(profile) : profile;
|
||||
}
|
||||
|
||||
private getAdvancedOptions(options: string, idNames: string[]): Map<string, string> {
|
||||
const ignoredProperties = idNames.concat(['password', 'azureAccountToken']);
|
||||
let advancedOptionsMap = new Map<string, string>();
|
||||
if (options) {
|
||||
try {
|
||||
// Decode options if they contain any encoded URL characters
|
||||
options = decodeURI(options);
|
||||
JSON.parse(options, (k, v) => {
|
||||
if (!(k in ignoredProperties)) {
|
||||
advancedOptionsMap.set(k, v);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
throw new Error(localize('commandline.propertiesFormatError', 'Advanced connection properties could not be parsed as JSON, error occurred: {0} Received properties value: {1}', e, options));
|
||||
}
|
||||
}
|
||||
return advancedOptionsMap;
|
||||
}
|
||||
|
||||
private tryMatchSavedProfile(profile: ConnectionProfile) {
|
||||
let match: ConnectionProfile = undefined;
|
||||
// If we can find a saved mssql provider connection that matches the args, use it
|
||||
|
||||
@@ -96,6 +96,7 @@ class TestParsedArgs implements NativeParsedArgs, SqlArgs {
|
||||
waitMarkerFilePath?: string;
|
||||
authenticationType?: string;
|
||||
applicationName?: string;
|
||||
connectionProperties?: string;
|
||||
}
|
||||
suite('commandLineService tests', () => {
|
||||
|
||||
@@ -219,6 +220,42 @@ suite('commandLineService tests', () => {
|
||||
connectionManagementService.verifyAll();
|
||||
});
|
||||
|
||||
test('processCommandLine loads advanced options in args', async () => {
|
||||
const connectionManagementService: TypeMoq.Mock<IConnectionManagementService>
|
||||
= TypeMoq.Mock.ofType<IConnectionManagementService>(TestConnectionManagementService, TypeMoq.MockBehavior.Strict);
|
||||
|
||||
const args: TestParsedArgs = new TestParsedArgs();
|
||||
args.server = 'myserver';
|
||||
args.database = 'mydatabase';
|
||||
args.user = 'myuser';
|
||||
args.authenticationType = Constants.AuthenticationType.SqlLogin;
|
||||
args.applicationName = 'myapplication';
|
||||
// Pass advanced connection properties
|
||||
args.connectionProperties = `{"trustServerCertificate":"true"}`;
|
||||
|
||||
connectionManagementService.setup((c) => c.showConnectionDialog()).verifiable(TypeMoq.Times.never());
|
||||
connectionManagementService.setup(c => c.hasRegisteredServers()).returns(() => true).verifiable(TypeMoq.Times.atMostOnce());
|
||||
connectionManagementService.setup(c => c.getConnectionGroups(TypeMoq.It.isAny())).returns(() => []);
|
||||
let originalProfile: IConnectionProfile = undefined;
|
||||
connectionManagementService.setup(c => c.connectIfNotConnected(TypeMoq.It.is<ConnectionProfile>(
|
||||
p => p.serverName === 'myserver'
|
||||
&& p.authenticationType === Constants.AuthenticationType.SqlLogin
|
||||
&& p.options['applicationName'] === 'myapplication-azdata'), 'connection', true))
|
||||
.returns((conn) => {
|
||||
originalProfile = conn;
|
||||
return Promise.resolve('unused');
|
||||
})
|
||||
.verifiable(TypeMoq.Times.once());
|
||||
connectionManagementService.setup(c => c.getConnectionProfileById(TypeMoq.It.isAnyString())).returns(() => originalProfile);
|
||||
const configurationService = getConfigurationServiceMock(true);
|
||||
const logService = new NullLogService();
|
||||
let contribution = getCommandLineContribution(connectionManagementService.object, configurationService.object, capabilitiesService, undefined, undefined, logService);
|
||||
await contribution.processCommandLine(args);
|
||||
assert.equal(originalProfile.options['applicationName'], 'myapplication-azdata', 'Application Name not received as expected.');
|
||||
assert.equal(originalProfile.options['trustServerCertificate'], 'true', 'Advanced option not received as expected.');
|
||||
connectionManagementService.verifyAll();
|
||||
});
|
||||
|
||||
test('processCommandLine invokes a command without a profile parameter when no server is passed', async () => {
|
||||
const connectionManagementService: TypeMoq.Mock<IConnectionManagementService>
|
||||
= TypeMoq.Mock.ofType<IConnectionManagementService>(TestConnectionManagementService, TypeMoq.MockBehavior.Loose);
|
||||
@@ -568,7 +605,5 @@ suite('commandLineService tests', () => {
|
||||
notificationService.verifyAll();
|
||||
connectionManagementService.verifyAll();
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user