diff --git a/extensions/azurecore/src/azureResource/azure-resource.d.ts b/extensions/azurecore/src/azureResource/azure-resource.d.ts index 2c551a786d..056e5e1f50 100644 --- a/extensions/azurecore/src/azureResource/azure-resource.d.ts +++ b/extensions/azurecore/src/azureResource/azure-resource.d.ts @@ -4,8 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { TreeDataProvider } from 'vscode'; -import { DataProvider, Account } from 'azdata'; -import { TreeItem } from 'azdata'; +import { DataProvider, Account, TreeItem } from 'azdata'; export namespace azureResource { export interface IAzureResourceProvider extends DataProvider { @@ -26,4 +25,4 @@ export namespace azureResource { id: string; name: string; } -} \ No newline at end of file +} diff --git a/extensions/big-data-cluster/src/wizards/create-cluster/createClusterModel.ts b/extensions/big-data-cluster/src/wizards/create-cluster/createClusterModel.ts index bdbf7220d6..e572bbe55b 100644 --- a/extensions/big-data-cluster/src/wizards/create-cluster/createClusterModel.ts +++ b/extensions/big-data-cluster/src/wizards/create-cluster/createClusterModel.ts @@ -24,7 +24,7 @@ export class CreateClusterModel implements Scriptable { } public async changeKubernetesContext(targetContext: string): Promise { - await setContext(this._kubectl, targetContext) + await setContext(this._kubectl, targetContext); } public getDefaultPorts(): Thenable { diff --git a/extensions/big-data-cluster/tsconfig.json b/extensions/big-data-cluster/tsconfig.json index e6baa6d40d..d9fbb41ead 100644 --- a/extensions/big-data-cluster/tsconfig.json +++ b/extensions/big-data-cluster/tsconfig.json @@ -1,19 +1,15 @@ { - "compileOnSave": true, - "compilerOptions": { - "module": "commonjs", - "target": "es6", + "extends": "../shared.tsconfig.json", + "compilerOptions": { "outDir": "./out", - "lib": [ - "es6", "es2015.promise" - ], - "sourceMap": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "moduleResolution": "node", - "declaration": true - }, - "exclude": [ - "node_modules" - ] + "strict": false, + "alwaysStrict": false, + "noImplicitAny": false, + "noImplicitReturns": false, + "noUnusedLocals": false, + "noUnusedParameters": false + }, + "include": [ + "src/**/*" + ] } diff --git a/extensions/configuration-editing/tsconfig.json b/extensions/configuration-editing/tsconfig.json index 296ddb38fc..a50348dc22 100644 --- a/extensions/configuration-editing/tsconfig.json +++ b/extensions/configuration-editing/tsconfig.json @@ -6,4 +6,4 @@ "include": [ "src/**/*" ] -} \ No newline at end of file +} diff --git a/extensions/dacpac/tsconfig.json b/extensions/dacpac/tsconfig.json index e6baa6d40d..d9fbb41ead 100644 --- a/extensions/dacpac/tsconfig.json +++ b/extensions/dacpac/tsconfig.json @@ -1,19 +1,15 @@ { - "compileOnSave": true, - "compilerOptions": { - "module": "commonjs", - "target": "es6", + "extends": "../shared.tsconfig.json", + "compilerOptions": { "outDir": "./out", - "lib": [ - "es6", "es2015.promise" - ], - "sourceMap": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "moduleResolution": "node", - "declaration": true - }, - "exclude": [ - "node_modules" - ] + "strict": false, + "alwaysStrict": false, + "noImplicitAny": false, + "noImplicitReturns": false, + "noUnusedLocals": false, + "noUnusedParameters": false + }, + "include": [ + "src/**/*" + ] } diff --git a/extensions/mssql/src/sparkFeature/dialog/sparkJobSubmission/sparkJobSubmissionService.ts b/extensions/mssql/src/sparkFeature/dialog/sparkJobSubmission/sparkJobSubmissionService.ts index 6e3bfeb3ee..83c46a4dab 100644 --- a/extensions/mssql/src/sparkFeature/dialog/sparkJobSubmission/sparkJobSubmissionService.ts +++ b/extensions/mssql/src/sparkFeature/dialog/sparkJobSubmission/sparkJobSubmissionService.ts @@ -42,7 +42,7 @@ export class SparkJobSubmissionService { }, // authentication headers headers: { - 'Authorization': 'Basic ' + new Buffer(submissionArgs.user + ':' + submissionArgs.password).toString('base64') + 'Authorization': 'Basic ' + Buffer.from(submissionArgs.user + ':' + submissionArgs.password).toString('base64') } }; @@ -100,7 +100,7 @@ export class SparkJobSubmissionService { rejectUnauthorized: false, // authentication headers headers: { - 'Authorization': 'Basic ' + new Buffer(submissionArgs.user + ':' + submissionArgs.password).toString('base64') + 'Authorization': 'Basic ' + Buffer.from(submissionArgs.user + ':' + submissionArgs.password).toString('base64') } }; diff --git a/extensions/mssql/tsconfig.json b/extensions/mssql/tsconfig.json index a696aa1763..d9fbb41ead 100644 --- a/extensions/mssql/tsconfig.json +++ b/extensions/mssql/tsconfig.json @@ -1,19 +1,15 @@ { - "compileOnSave": true, - "compilerOptions": { - "module": "commonjs", - "target": "es6", + "extends": "../shared.tsconfig.json", + "compilerOptions": { "outDir": "./out", - "lib": [ - "es6", "es2015.promise" - ], - "sourceMap": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "moduleResolution": "node", - "declaration": false - }, - "exclude": [ - "node_modules" - ] + "strict": false, + "alwaysStrict": false, + "noImplicitAny": false, + "noImplicitReturns": false, + "noUnusedLocals": false, + "noUnusedParameters": false + }, + "include": [ + "src/**/*" + ] } diff --git a/extensions/notebook/src/jupyter/jupyterNotebookProvider.ts b/extensions/notebook/src/jupyter/jupyterNotebookProvider.ts index 9dcb951d42..6571f3821b 100644 --- a/extensions/notebook/src/jupyter/jupyterNotebookProvider.ts +++ b/extensions/notebook/src/jupyter/jupyterNotebookProvider.ts @@ -58,4 +58,3 @@ export class JupyterNotebookProvider implements nb.NotebookProvider { return []; } } - diff --git a/extensions/notebook/tsconfig.json b/extensions/notebook/tsconfig.json index c308915334..1d437e3614 100644 --- a/extensions/notebook/tsconfig.json +++ b/extensions/notebook/tsconfig.json @@ -1,22 +1,18 @@ { - "compileOnSave": true, + "extends": "../shared.tsconfig.json", "compilerOptions": { - "module": "commonjs", - "target": "es6", - "outDir": "./out", "lib": [ - "dom", "es6", "es2015.promise" + "dom" ], - "typeRoots": [ - "./node_modules/@types" - ], - "sourceMap": true, - "emitDecoratorMetadata": true, - "experimentalDecorators": true, - "moduleResolution": "node", - "declaration": true + "outDir": "./out", + "strict": false, + "alwaysStrict": false, + "noImplicitAny": false, + "noImplicitReturns": false, + "noUnusedLocals": false, + "noUnusedParameters": false }, - "exclude": [ - "node_modules" + "include": [ + "src/**/*" ] } diff --git a/src/sql/parts/connection/common/connection.contribution.ts b/src/sql/parts/connection/common/connection.contribution.ts index fac71e16b6..dc207fdd54 100644 --- a/src/sql/parts/connection/common/connection.contribution.ts +++ b/src/sql/parts/connection/common/connection.contribution.ts @@ -3,18 +3,15 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IExtensionGalleryService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { EditorDescriptor, IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; import { IConfigurationRegistry, Extensions as ConfigExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Registry } from 'vs/platform/registry/common/platform'; import { DashboardEditor } from 'sql/parts/dashboard/dashboardEditor'; import { DashboardInput } from 'sql/parts/dashboard/dashboardInput'; import { AddServerGroupAction, AddServerAction } from 'sql/parts/objectExplorer/viewlet/connectionTreeAction'; import { ClearRecentConnectionsAction, GetCurrentConnectionStringAction } from 'sql/parts/connection/common/connectionActions'; -import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { localize } from 'vs/nls'; @@ -22,11 +19,6 @@ import { IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/com import { ExtensionTipsService } from 'vs/workbench/contrib/extensions/electron-browser/extensionTipsService'; import { ExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/node/extensionsWorkbenchService'; -// Singletons -registerSingleton(IExtensionGalleryService, ExtensionGalleryService); -registerSingleton(IExtensionTipsService, ExtensionTipsService); -registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService); - // Connection Dashboard registration const dashboardEditorDescriptor = new EditorDescriptor( DashboardEditor, diff --git a/src/sql/platform/connection/common/connectionConfig.ts b/src/sql/platform/connection/common/connectionConfig.ts index 44db17dd38..83022d304a 100644 --- a/src/sql/platform/connection/common/connectionConfig.ts +++ b/src/sql/platform/connection/common/connectionConfig.ts @@ -4,19 +4,16 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import * as Constants from './constants'; -import * as Utils from './utils'; -import { IConnectionProfile, IConnectionProfileStore } from './interfaces'; -import { IConnectionConfig } from './iconnectionConfig'; -import { ConnectionProfileGroup, IConnectionProfileGroup } from './connectionProfileGroup'; -import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ConnectionProfile } from './connectionProfile'; import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; -import * as azdata from 'azdata'; -import * as nls from 'vs/nls'; - +import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; +import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; +import * as Constants from 'sql/platform/connection/common/constants'; +import { IConnectionConfig } from 'sql/platform/connection/common/iconnectionConfig'; +import { IConnectionProfile, IConnectionProfileStore } from 'sql/platform/connection/common/interfaces'; +import * as Utils from 'sql/platform/connection/common/utils'; import { generateUuid } from 'vs/base/common/uuid'; -import { ConfigurationEditingService, IConfigurationValue } from 'vs/workbench/services/configuration/common/configurationEditingService'; +import * as nls from 'vs/nls'; +import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration'; export interface ISaveGroupResult { groups: IConnectionProfileGroup[]; @@ -28,12 +25,8 @@ export interface ISaveGroupResult { */ export class ConnectionConfig implements IConnectionConfig { - /** - * Constructor. - */ public constructor( - private _configurationEditService: ConfigurationEditingService, - private _workspaceConfigurationService: IConfigurationService, + private configurationService: IConfigurationService, private _capabilitiesService: ICapabilitiesService ) { } @@ -43,15 +36,14 @@ export class ConnectionConfig implements IConnectionConfig { public getAllGroups(): IConnectionProfileGroup[] { let allGroups: IConnectionProfileGroup[] = []; - let userGroups = this.getConfiguration(Constants.connectionGroupsArrayName).user as IConnectionProfileGroup[]; - let workspaceGroups = this.getConfiguration(Constants.connectionGroupsArrayName).workspace as IConnectionProfileGroup[]; + let { user, workspace } = this.configurationService.inspect(Constants.connectionGroupsArrayName); - if (userGroups) { - if (workspaceGroups) { - userGroups = userGroups.filter(x => workspaceGroups.find(f => this.isSameGroupName(f, x)) === undefined); - allGroups = allGroups.concat(workspaceGroups); + if (user) { + if (workspace) { + user = user.filter(x => workspace.find(f => this.isSameGroupName(f, x)) === undefined); + allGroups = allGroups.concat(workspace); } - allGroups = allGroups.concat(userGroups); + allGroups = allGroups.concat(user); } allGroups = allGroups.map(g => { if (g.parentId === '' || !g.parentId) { @@ -66,39 +58,35 @@ export class ConnectionConfig implements IConnectionConfig { * Add a new connection to the connection config. */ public addConnection(profile: IConnectionProfile): Promise { - return new Promise((resolve, reject) => { - if (profile.saveProfile) { - this.addGroupFromProfile(profile).then(groupId => { - let profiles = this._workspaceConfigurationService.inspect(Constants.connectionsArrayName).user; - if (!profiles) { - profiles = []; - } + if (profile.saveProfile) { + return this.addGroupFromProfile(profile).then(groupId => { + let profiles = this.configurationService.inspect(Constants.connectionsArrayName).user; + if (!profiles) { + profiles = []; + } - let connectionProfile = this.getConnectionProfileInstance(profile, groupId); - let newProfile = ConnectionProfile.convertToProfileStore(this._capabilitiesService, connectionProfile); + let connectionProfile = this.getConnectionProfileInstance(profile, groupId); + let newProfile = ConnectionProfile.convertToProfileStore(this._capabilitiesService, connectionProfile); - // Remove the profile if already set - var sameProfileInList = profiles.find(value => { - let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, this._capabilitiesService); - return providerConnectionProfile.matches(connectionProfile); - }); - if (sameProfileInList) { - let profileIndex = profiles.findIndex(value => value === sameProfileInList); - newProfile.id = sameProfileInList.id; - connectionProfile.id = sameProfileInList.id; - profiles[profileIndex] = newProfile; - } else { - profiles.push(newProfile); - } - - this.writeConfiguration(Constants.connectionsArrayName, profiles).then(() => { - resolve(connectionProfile); - }).catch(err => { - reject(err); - }); + // Remove the profile if already set + var sameProfileInList = profiles.find(value => { + let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, this._capabilitiesService); + return providerConnectionProfile.matches(connectionProfile); }); - } - }); + if (sameProfileInList) { + let profileIndex = profiles.findIndex(value => value === sameProfileInList); + newProfile.id = sameProfileInList.id; + connectionProfile.id = sameProfileInList.id; + profiles[profileIndex] = newProfile; + } else { + profiles.push(newProfile); + } + + return this.configurationService.updateValue(Constants.connectionsArrayName, profiles, ConfigurationTarget.USER).then(() => connectionProfile); + }); + } else { + return Promise.resolve(profile); + } } private getConnectionProfileInstance(profile: IConnectionProfile, groupId: string): ConnectionProfile { @@ -115,21 +103,15 @@ export class ConnectionConfig implements IConnectionConfig { * @param groupName */ public addGroupFromProfile(profile: IConnectionProfile): Promise { - return new Promise((resolve, reject) => { - if (profile.groupId && profile.groupId !== Utils.defaultGroupId) { - resolve(profile.groupId); - } else { - let groups = this._workspaceConfigurationService.inspect(Constants.connectionGroupsArrayName).user; - let result = this.saveGroup(groups, profile.groupFullName, undefined, undefined); - groups = result.groups; + if (profile.groupId && profile.groupId !== Utils.defaultGroupId) { + return Promise.resolve(profile.groupId); + } else { + let groups = this.configurationService.inspect(Constants.connectionGroupsArrayName).user; + let result = this.saveGroup(groups, profile.groupFullName, undefined, undefined); + groups = result.groups; - this.writeConfiguration(Constants.connectionGroupsArrayName, groups).then(() => { - resolve(result.newGroupId); - }).catch(err => { - reject(err); - }); - } - }); + return this.configurationService.updateValue(Constants.connectionGroupsArrayName, groups, ConfigurationTarget.USER).then(() => result.newGroupId); + } } /** @@ -137,41 +119,35 @@ export class ConnectionConfig implements IConnectionConfig { * @param groupName */ public addGroup(profileGroup: IConnectionProfileGroup): Promise { - return new Promise((resolve, reject) => { - if (profileGroup.id) { - resolve(profileGroup.id); + if (profileGroup.id) { + return Promise.resolve(profileGroup.id); + } else { + let groups = this.configurationService.inspect(Constants.connectionGroupsArrayName).user; + let sameNameGroup = groups ? groups.find(group => group.name === profileGroup.name) : undefined; + if (sameNameGroup) { + let errMessage: string = nls.localize('invalidServerName', "A server group with the same name already exists."); + return Promise.reject(errMessage); } else { - let groups = this._workspaceConfigurationService.inspect(Constants.connectionGroupsArrayName).user; - let sameNameGroup = groups ? groups.find(group => group.name === profileGroup.name) : undefined; - if (sameNameGroup) { - let errMessage: string = nls.localize('invalidServerName', "A server group with the same name already exists."); - reject(errMessage); - } else { - let result = this.saveGroup(groups, profileGroup.name, profileGroup.color, profileGroup.description); - groups = result.groups; + let result = this.saveGroup(groups, profileGroup.name, profileGroup.color, profileGroup.description); + groups = result.groups; - this.writeConfiguration(Constants.connectionGroupsArrayName, groups).then(() => { - resolve(result.newGroupId); - }).catch(err => { - reject(err); - }); - } + return this.configurationService.updateValue(Constants.connectionGroupsArrayName, groups, ConfigurationTarget.USER).then(() => result.newGroupId); } - }); + } } private getConnectionProfilesForTarget(configTarget: ConfigurationTarget): IConnectionProfileStore[] { - let configs = this.getConfiguration(Constants.connectionsArrayName); + let configs = this.configurationService.inspect(Constants.connectionsArrayName); let profiles: IConnectionProfileStore[]; if (configs) { if (configTarget === ConfigurationTarget.USER) { - profiles = configs.user; + profiles = configs.user; } else if (configTarget === ConfigurationTarget.WORKSPACE) { - profiles = configs.workspace; + profiles = configs.workspace; } if (profiles) { if (this.fixConnectionIds(profiles)) { - this.writeConfiguration(Constants.connectionsArrayName, profiles, configTarget); + this.configurationService.updateValue(Constants.connectionsArrayName, profiles, configTarget); } } else { profiles = []; @@ -185,7 +161,7 @@ export class ConnectionConfig implements IConnectionConfig { * Replace duplicate ids with new ones. Sets id for the profiles without id * @param profiles */ - public fixConnectionIds(profiles: IConnectionProfileStore[]): boolean { + private fixConnectionIds(profiles: IConnectionProfileStore[]): boolean { let idsCache: { [label: string]: boolean } = {}; let changed: boolean = false; for (var index = 0; index < profiles.length; index++) { @@ -239,7 +215,7 @@ export class ConnectionConfig implements IConnectionConfig { */ public deleteConnection(profile: ConnectionProfile): Promise { // Get all connections in the settings - let profiles = this._workspaceConfigurationService.inspect(Constants.connectionsArrayName).user; + let profiles = this.configurationService.inspect(Constants.connectionsArrayName).user; // Remove the profile from the connections profiles = profiles.filter(value => { let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, this._capabilitiesService); @@ -247,7 +223,7 @@ export class ConnectionConfig implements IConnectionConfig { }); // Write connections back to settings - return this.writeConfiguration(Constants.connectionsArrayName, profiles); + return this.configurationService.updateValue(Constants.connectionsArrayName, profiles, ConfigurationTarget.USER); } /** @@ -260,7 +236,7 @@ export class ConnectionConfig implements IConnectionConfig { // Add selected group to subgroups list subgroups.push(group); // Get all connections in the settings - let profiles = this._workspaceConfigurationService.inspect(Constants.connectionsArrayName).user; + let profiles = this.configurationService.inspect(Constants.connectionsArrayName).user; // Remove the profiles from the connections profiles = profiles.filter(value => { let providerConnectionProfile = ConnectionProfile.createFromStoredProfile(value, this._capabilitiesService); @@ -268,32 +244,29 @@ export class ConnectionConfig implements IConnectionConfig { }); // Get all groups in the settings - let groups = this._workspaceConfigurationService.inspect(Constants.connectionGroupsArrayName).user; + let groups = this.configurationService.inspect(Constants.connectionGroupsArrayName).user; // Remove subgroups in the settings groups = groups.filter((grp) => { return !subgroups.some((item) => item.id === grp.id); }); - return new Promise((resolve, reject) => { - this.writeConfiguration(Constants.connectionsArrayName, profiles).then(() => { - this.writeConfiguration(Constants.connectionGroupsArrayName, groups).then(() => { - resolve(); - }).catch(() => reject()); - }).catch(() => reject()); - }); + return Promise.all([ + this.configurationService.updateValue(Constants.connectionsArrayName, profiles, ConfigurationTarget.USER), + this.configurationService.updateValue(Constants.connectionGroupsArrayName, groups, ConfigurationTarget.USER) + ]).then(() => Promise.resolve()); } /** * Moves the source group under the target group. */ public changeGroupIdForConnectionGroup(source: ConnectionProfileGroup, target: ConnectionProfileGroup): Promise { - let groups = this._workspaceConfigurationService.inspect(Constants.connectionGroupsArrayName).user; + let groups = this.configurationService.inspect(Constants.connectionGroupsArrayName).user; groups = groups.map(g => { if (g.id === source.id) { g.parentId = target.id; } return g; }); - return this.writeConfiguration(Constants.connectionGroupsArrayName, groups); + return this.configurationService.updateValue(Constants.connectionGroupsArrayName, groups, ConfigurationTarget.USER); } /** @@ -310,53 +283,40 @@ export class ConnectionConfig implements IConnectionConfig { * Moves the connection under the target group with the new ID. */ private changeGroupIdForConnectionInSettings(profile: ConnectionProfile, newGroupID: string, target: ConfigurationTarget = ConfigurationTarget.USER): Promise { - return new Promise((resolve, reject) => { - let profiles = target === ConfigurationTarget.USER ? this._workspaceConfigurationService.inspect(Constants.connectionsArrayName).user : - this._workspaceConfigurationService.inspect(Constants.connectionsArrayName).workspace; - if (profiles) { - if (profile.parent && profile.parent.id === Constants.unsavedGroupId) { - profile.groupId = newGroupID; - profiles.push(ConnectionProfile.convertToProfileStore(this._capabilitiesService, profile)); - } else { - profiles.forEach((value) => { - let configProf = ConnectionProfile.createFromStoredProfile(value, this._capabilitiesService); - if (configProf.getOptionsKey() === profile.getOptionsKey()) { - value.groupId = newGroupID; - } - }); - } - - this.writeConfiguration(Constants.connectionsArrayName, profiles, target).then(result => { - resolve(); - }).catch(error => { - reject(error); - }); + let profiles = target === ConfigurationTarget.USER ? this.configurationService.inspect(Constants.connectionsArrayName).user : + this.configurationService.inspect(Constants.connectionsArrayName).workspace; + if (profiles) { + if (profile.parent && profile.parent.id === Constants.unsavedGroupId) { + profile.groupId = newGroupID; + profiles.push(ConnectionProfile.convertToProfileStore(this._capabilitiesService, profile)); } else { - resolve(); + profiles.forEach((value) => { + let configProf = ConnectionProfile.createFromStoredProfile(value, this._capabilitiesService); + if (configProf.getOptionsKey() === profile.getOptionsKey()) { + value.groupId = newGroupID; + } + }); } - }); + + return this.configurationService.updateValue(Constants.connectionsArrayName, profiles, target); + } else { + return Promise.resolve(); + } } /** * Moves the connection under the target group with the new ID. */ public changeGroupIdForConnection(profile: ConnectionProfile, newGroupID: string): Promise { - return new Promise((resolve, reject) => { - if (!this.canChangeConnectionConfig(profile, newGroupID)) { - // Same connection already exists in this group - reject('Same connection already exists in the group'); - } else { - this.changeGroupIdForConnectionInSettings(profile, newGroupID, ConfigurationTarget.USER).then(result1 => { - this.changeGroupIdForConnectionInSettings(profile, newGroupID, ConfigurationTarget.WORKSPACE).then(result2 => { - resolve(); - }).catch(error2 => { - reject(error2); - }); - }).catch(error1 => { - reject(error1); - }); - } - }); + if (!this.canChangeConnectionConfig(profile, newGroupID)) { + // Same connection already exists in this group + return Promise.reject('Same connection already exists in the group'); + } else { + return Promise.all([ + this.changeGroupIdForConnectionInSettings(profile, newGroupID, ConfigurationTarget.USER), + this.changeGroupIdForConnectionInSettings(profile, newGroupID, ConfigurationTarget.WORKSPACE) + ]).then(() => Promise.resolve()); + } } public saveGroup(groups: IConnectionProfileGroup[], groupFullName: string, color: string, description: string): ISaveGroupResult { @@ -367,7 +327,7 @@ export class ConnectionConfig implements IConnectionConfig { } public editGroup(source: ConnectionProfileGroup): Promise { - let groups = this._workspaceConfigurationService.inspect(Constants.connectionGroupsArrayName).user; + let groups = this.configurationService.inspect(Constants.connectionGroupsArrayName).user; let sameNameGroup = groups ? groups.find(group => group.name === source.name && group.id !== source.id) : undefined; if (sameNameGroup) { let errMessage: string = nls.localize('invalidServerName', "A server group with the same name already exists."); @@ -382,7 +342,7 @@ export class ConnectionConfig implements IConnectionConfig { } return g; }); - return this.writeConfiguration(Constants.connectionGroupsArrayName, groups); + return this.configurationService.updateValue(Constants.connectionGroupsArrayName, groups, ConfigurationTarget.USER); } private isSameGroupName(group1: IConnectionProfileGroup, group2: IConnectionProfileGroup): boolean { @@ -441,40 +401,4 @@ export class ConnectionConfig implements IConnectionConfig { }; return groupResult; } - - /** - * Get all profiles from the parsed settings file. - * This is public for testing only. - * @param parsedSettingsFile an object representing the parsed contents of the settings file. - * @returns the set of connection profiles found in the parsed settings file. - */ - private getConfiguration(key: string): any { - let configs: any; - configs = this._workspaceConfigurationService.inspect(key); - return configs; - } - - /** - * Replace existing profiles in the settings file with a new set of profiles. - * @param parsedSettingsFile an object representing the parsed contents of the settings file. - * @param profiles the set of profiles to insert into the settings file. - */ - private writeConfiguration( - key: string, - profiles: IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[], - target: ConfigurationTarget = ConfigurationTarget.USER): Promise { - return new Promise((resolve, reject) => { - let configValue: IConfigurationValue = { - key: key, - value: profiles - }; - this._configurationEditService.writeConfiguration(target, configValue).then(result => { - this._workspaceConfigurationService.reloadConfiguration().then(() => { - resolve(); - }); - }, (error => { - reject(error); - })); - }); - } } diff --git a/src/sql/platform/connection/common/connectionInfo.ts b/src/sql/platform/connection/common/connectionInfo.ts index c826be69f5..cb21a58da9 100644 --- a/src/sql/platform/connection/common/connectionInfo.ts +++ b/src/sql/platform/connection/common/connectionInfo.ts @@ -5,17 +5,17 @@ 'use strict'; -import Interfaces = require('./interfaces'); +import * as interfaces from 'sql/platform/connection/common/interfaces'; /** * Sets sensible defaults for key connection properties, especially * if connection to Azure * * @export connectionInfo/fixupConnectionCredentials - * @param {Interfaces.IConnectionCredentials} connCreds connection to be fixed up - * @returns {Interfaces.IConnectionCredentials} the updated connection + * @param {interfaces.IConnectionCredentials} connCreds connection to be fixed up + * @returns {interfaces.IConnectionCredentials} the updated connection */ -export function fixupConnectionCredentials(connCreds: Interfaces.IConnectionProfile): Interfaces.IConnectionProfile { +export function fixupConnectionCredentials(connCreds: interfaces.IConnectionProfile): interfaces.IConnectionProfile { if (!connCreds.serverName) { connCreds.serverName = ''; } @@ -33,4 +33,3 @@ export function fixupConnectionCredentials(connCreds: Interfaces.IConnectionProf } return connCreds; } - diff --git a/src/sql/platform/connection/common/connectionManagement.ts b/src/sql/platform/connection/common/connectionManagement.ts index 38e43617fa..3632cbb31c 100644 --- a/src/sql/platform/connection/common/connectionManagement.ts +++ b/src/sql/platform/connection/common/connectionManagement.ts @@ -11,7 +11,7 @@ import * as azdata from 'azdata'; import { IConnectionProfileGroup, ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; -import { ConnectionManagementInfo } from './connectionManagementInfo'; +import { ConnectionManagementInfo } from 'sql/platform/connection/common/connectionManagementInfo'; import { IServerGroupDialogCallbacks } from 'sql/platform/serverGroup/common/serverGroupController'; export const VIEWLET_ID = 'workbench.view.connections'; @@ -331,4 +331,4 @@ export enum TaskStatus { export interface IConnectionParams { connectionUri: string; connectionProfile: IConnectionProfile; -} \ No newline at end of file +} diff --git a/src/sql/platform/connection/common/connectionManagementInfo.ts b/src/sql/platform/connection/common/connectionManagementInfo.ts index 911c76ce34..131d0c51d3 100644 --- a/src/sql/platform/connection/common/connectionManagementInfo.ts +++ b/src/sql/platform/connection/common/connectionManagementInfo.ts @@ -70,4 +70,4 @@ export class ConnectionManagementInfo { * Owner uri assigned to the connection */ public ownerUri: string; -} \ No newline at end of file +} diff --git a/src/sql/platform/connection/common/connectionManagementService.ts b/src/sql/platform/connection/common/connectionManagementService.ts index 4bc9457431..07f3d11ec6 100644 --- a/src/sql/platform/connection/common/connectionManagementService.ts +++ b/src/sql/platform/connection/common/connectionManagementService.ts @@ -56,7 +56,6 @@ import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { IConnectionDialogService } from 'sql/workbench/services/connection/common/connectionDialogService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditingService'; export class ConnectionManagementService extends Disposable implements IConnectionManagementService { @@ -77,8 +76,6 @@ export class ConnectionManagementService extends Disposable implements IConnecti private _onLanguageFlavorChanged = new Emitter(); private _connectionGlobalStatus = new ConnectionGlobalStatus(this._statusBarService); - private _configurationEditService: ConfigurationEditingService; - constructor( private _connectionMemento: Memento, private _connectionStore: ConnectionStore, @@ -99,17 +96,14 @@ export class ConnectionManagementService extends Disposable implements IConnecti @IAccountManagementService private _accountManagementService: IAccountManagementService ) { super(); - if (this._instantiationService) { - this._configurationEditService = this._instantiationService.createInstance(ConfigurationEditingService); - } // _connectionMemento and _connectionStore are in constructor to enable this class to be more testable if (!this._connectionMemento) { this._connectionMemento = new Memento('ConnectionManagement', _storageService); } if (!this._connectionStore) { - this._connectionStore = new ConnectionStore(_storageService, this._connectionMemento, - this._configurationEditService, this._configurationService, this._credentialsService, this._capabilitiesService); + this._connectionStore = new ConnectionStore(this._connectionMemento, + this._configurationService, this._credentialsService, this._capabilitiesService); } // Register Statusbar item diff --git a/src/sql/platform/connection/common/connectionProfile.ts b/src/sql/platform/connection/common/connectionProfile.ts index f9b6bfa277..86b8845807 100644 --- a/src/sql/platform/connection/common/connectionProfile.ts +++ b/src/sql/platform/connection/common/connectionProfile.ts @@ -5,7 +5,7 @@ 'use strict'; -import { ConnectionProfileGroup } from './connectionProfileGroup'; +import { ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; import * as azdata from 'azdata'; import { ProviderConnectionInfo } from 'sql/platform/connection/common/providerConnectionInfo'; import * as interfaces from 'sql/platform/connection/common/interfaces'; diff --git a/src/sql/platform/connection/common/connectionProfileGroup.ts b/src/sql/platform/connection/common/connectionProfileGroup.ts index a7266ca1df..6f14ebaa3e 100644 --- a/src/sql/platform/connection/common/connectionProfileGroup.ts +++ b/src/sql/platform/connection/common/connectionProfileGroup.ts @@ -5,7 +5,7 @@ 'use strict'; -import { ConnectionProfile } from './connectionProfile'; +import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; export interface IConnectionProfileGroup { id: string; @@ -216,4 +216,4 @@ export class ConnectionProfileGroup implements IConnectionProfileGroup { } return subgroups; } -} \ No newline at end of file +} diff --git a/src/sql/platform/connection/common/connectionStatusManager.ts b/src/sql/platform/connection/common/connectionStatusManager.ts index 7adafdef91..7e51e0e349 100644 --- a/src/sql/platform/connection/common/connectionStatusManager.ts +++ b/src/sql/platform/connection/common/connectionStatusManager.ts @@ -4,22 +4,20 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; -import { ConnectionManagementInfo } from './connectionManagementInfo'; +import { ConnectionManagementInfo } from 'sql/platform/connection/common/connectionManagementInfo'; import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; -import { IConnectionProfile } from './interfaces'; -import * as Utils from './utils'; +import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; +import * as Utils from 'sql/platform/connection/common/utils'; import * as azdata from 'azdata'; import { StopWatch } from 'vs/base/common/stopwatch'; export class ConnectionStatusManager { private _connections: { [id: string]: ConnectionManagementInfo }; - private _providerCapabilitiesMap: { [providerName: string]: azdata.DataProtocolServerCapabilities }; constructor( @ICapabilitiesService private _capabilitiesService: ICapabilitiesService) { this._connections = {}; - this._providerCapabilitiesMap = {}; } public findConnection(uri: string): ConnectionManagementInfo { @@ -207,4 +205,4 @@ export class ConnectionStatusManager { } return profiles; } -} \ No newline at end of file +} diff --git a/src/sql/platform/connection/common/connectionStore.ts b/src/sql/platform/connection/common/connectionStore.ts index 7bf8d9bb4e..f1e627daec 100644 --- a/src/sql/platform/connection/common/connectionStore.ts +++ b/src/sql/platform/connection/common/connectionStore.ts @@ -5,19 +5,18 @@ 'use strict'; -import * as Constants from './constants'; -import * as ConnInfo from './connectionInfo'; -import { ConnectionProfile } from '../common/connectionProfile'; +import * as Constants from 'sql/platform/connection/common/constants'; +import * as ConnInfo from 'sql/platform/connection/common/connectionInfo'; +import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; import { ICredentialsService } from 'sql/platform/credentials/common/credentialsService'; -import { IConnectionConfig } from './iconnectionConfig'; -import { ConnectionConfig } from './connectionConfig'; +import { IConnectionConfig } from 'sql/platform/connection/common/iconnectionConfig'; +import { ConnectionConfig } from 'sql/platform/connection/common/connectionConfig'; import { Memento } from 'vs/workbench/common/memento'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { StorageScope } from 'vs/platform/storage/common/storage'; import { ConnectionProfileGroup, IConnectionProfileGroup } from './connectionProfileGroup'; import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ConfigurationEditingService } from 'vs/workbench/services/configuration/common/configurationEditingService'; const MAX_CONNECTIONS_DEFAULT = 25; @@ -33,9 +32,7 @@ export class ConnectionStore { private _groupFullNameToIdMap: { [groupId: string]: string }; constructor( - private _storageService: IStorageService, private _context: Memento, - private _configurationEditService: ConfigurationEditingService, private _configurationService: IConfigurationService, private _credentialService: ICredentialsService, private _capabilitiesService: ICapabilitiesService, @@ -47,8 +44,7 @@ export class ConnectionStore { this._groupIdToFullNameMap = {}; this._groupFullNameToIdMap = {}; if (!this._connectionConfig) { - this._connectionConfig = new ConnectionConfig(this._configurationEditService, - this._configurationService, this._capabilitiesService); + this._connectionConfig = new ConnectionConfig(this._configurationService, this._capabilitiesService); } } diff --git a/src/sql/platform/connection/common/constants.ts b/src/sql/platform/connection/common/constants.ts index c30519237e..f09f28b867 100644 --- a/src/sql/platform/connection/common/constants.ts +++ b/src/sql/platform/connection/common/constants.ts @@ -34,4 +34,3 @@ export const passwordChars = '***************'; export const sqlLogin = 'SqlLogin'; export const integrated = 'Integrated'; export const azureMFA = 'AzureMFA'; - diff --git a/src/sql/platform/connection/common/iconnectionConfig.ts b/src/sql/platform/connection/common/iconnectionConfig.ts index bcf0f12a60..7e14127817 100644 --- a/src/sql/platform/connection/common/iconnectionConfig.ts +++ b/src/sql/platform/connection/common/iconnectionConfig.ts @@ -5,10 +5,9 @@ 'use strict'; -import { IConnectionProfile } from './interfaces'; -import { IConnectionProfileGroup, ConnectionProfileGroup } from './connectionProfileGroup'; -import { ConnectionProfile } from './connectionProfile'; -import * as azdata from 'azdata'; +import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; +import { IConnectionProfileGroup, ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; +import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; /** * Interface for a configuration file that stores connection profiles. diff --git a/src/sql/platform/connection/common/utils.ts b/src/sql/platform/connection/common/utils.ts index 8de53e3fba..b257f30005 100644 --- a/src/sql/platform/connection/common/utils.ts +++ b/src/sql/platform/connection/common/utils.ts @@ -5,9 +5,9 @@ 'use strict'; -import { IConnectionProfile } from './interfaces'; -import { ConnectionProfile } from './connectionProfile'; -import { ConnectionProfileGroup } from './connectionProfileGroup'; +import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; +import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; +import { ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; // CONSTANTS ////////////////////////////////////////////////////////////////////////////////////// const msInH = 3.6e6; diff --git a/src/sql/platform/connection/test/common/connectionConfig.test.ts b/src/sql/platform/connection/test/common/connectionConfig.test.ts new file mode 100644 index 0000000000..3471caa7be --- /dev/null +++ b/src/sql/platform/connection/test/common/connectionConfig.test.ts @@ -0,0 +1,737 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as TypeMoq from 'typemoq'; +import { ConnectionConfig, ISaveGroupResult } from 'sql/platform/connection/common/connectionConfig'; +import { IConnectionProfile, IConnectionProfileStore } from 'sql/platform/connection/common/interfaces'; +import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; +import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +import * as Constants from 'sql/platform/connection/common/constants'; +import { IConnectionProfileGroup, ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; +import * as assert from 'assert'; +import { ProviderFeatures, ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; +import * as azdata from 'azdata'; +import { Emitter } from 'vs/base/common/event'; +import { ConnectionOptionSpecialType, ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes'; +import { CapabilitiesTestService } from 'sqltest/stubs/capabilitiesTestService'; +import { TestConfigurationService } from 'sql/platform/connection/test/common/testConfigurationService'; +import { deepFreeze, deepClone } from 'vs/base/common/objects'; +import { isUndefinedOrNull } from 'vs/base/common/types'; +import { ConnectionManagementInfo } from 'sql/platform/connection/common/connectionManagementInfo'; + +suite('ConnectionConfig', () => { + let capabilitiesService: TypeMoq.Mock; + let msSQLCapabilities: ProviderFeatures; + let capabilities: ProviderFeatures[]; + let onCapabilitiesRegistered = new Emitter(); + + const testGroups = deepFreeze([ + { + name: 'g1', + id: 'g1', + parentId: 'ROOT', + color: 'pink', + description: 'g1' + }, + { + name: 'g1-1', + id: 'g1-1', + parentId: 'g1', + color: 'blue', + description: 'g1-1' + }, + { + name: 'ROOT', + id: 'ROOT', + parentId: '', + color: 'white', + description: 'ROOT' + }, + { + name: 'g2', + id: 'g2', + parentId: 'ROOT', + color: 'green', + description: 'g2' + }, + { + name: 'g2-1', + id: 'g2-1', + parentId: 'g2', + color: 'yellow', + description: 'g2' + }, + { + name: 'g3', + id: 'g3', + parentId: '', + color: 'orange', + description: 'g3' + }, + { + name: 'g3-1', + id: 'g3-1', + parentId: 'g3', + color: 'purple', + description: 'g3-1' + } + ]); + + const testConnections: IConnectionProfileStore[] = deepFreeze([ + { + options: { + serverName: 'server1', + databaseName: 'database', + userName: 'user', + password: 'password', + authenticationType: '' + }, + providerName: 'MSSQL', + groupId: 'test', + savePassword: true, + id: 'server1' + }, + { + options: { + serverName: 'server2', + databaseName: 'database', + userName: 'user', + password: 'password', + authenticationType: '' + }, + providerName: 'MSSQL', + groupId: 'test', + savePassword: true, + id: 'server2' + }, + { + options: { + serverName: 'server3', + databaseName: 'database', + userName: 'user', + password: 'password', + authenticationType: '' + }, + providerName: 'MSSQL', + groupId: 'g3', + savePassword: true, + id: 'server3' + } + ]); + + setup(() => { + capabilitiesService = TypeMoq.Mock.ofType(CapabilitiesTestService); + capabilities = []; + let connectionProvider: azdata.ConnectionProviderOptions = { + options: [ + { + name: 'serverName', + displayName: undefined, + description: undefined, + groupName: undefined, + categoryValues: undefined, + defaultValue: undefined, + isIdentity: true, + isRequired: true, + specialValueType: ConnectionOptionSpecialType.serverName, + valueType: ServiceOptionType.string + }, + { + name: 'databaseName', + displayName: undefined, + description: undefined, + groupName: undefined, + categoryValues: undefined, + defaultValue: undefined, + isIdentity: true, + isRequired: true, + specialValueType: ConnectionOptionSpecialType.databaseName, + valueType: ServiceOptionType.string + }, + { + name: 'userName', + displayName: undefined, + description: undefined, + groupName: undefined, + categoryValues: undefined, + defaultValue: undefined, + isIdentity: true, + isRequired: true, + specialValueType: ConnectionOptionSpecialType.userName, + valueType: ServiceOptionType.string + }, + { + name: 'authenticationType', + displayName: undefined, + description: undefined, + groupName: undefined, + categoryValues: undefined, + defaultValue: undefined, + isIdentity: true, + isRequired: true, + specialValueType: ConnectionOptionSpecialType.authType, + valueType: ServiceOptionType.string + }, + { + name: 'password', + displayName: undefined, + description: undefined, + groupName: undefined, + categoryValues: undefined, + defaultValue: undefined, + isIdentity: true, + isRequired: true, + specialValueType: ConnectionOptionSpecialType.password, + valueType: ServiceOptionType.string + } + ] + }; + msSQLCapabilities = { + connection: { + providerId: 'MSSQL', + displayName: 'MSSQL', + connectionOptions: connectionProvider.options + } + }; + capabilities.push(msSQLCapabilities); + + capabilitiesService.setup(x => x.getCapabilities('MSSQL')).returns(() => msSQLCapabilities); + (capabilitiesService.object as any).onCapabilitiesRegistered = onCapabilitiesRegistered.event; + }); + + function groupsAreEqual(groups1: IConnectionProfileGroup[], groups2: IConnectionProfileGroup[]): boolean { + if (!groups1 && !groups2) { + return true; + } else if ((!groups1 && groups2 && groups2.length === 0) || (!groups2 && groups1 && groups1.length === 0)) { + return true; + } + + if (groups1.length !== groups2.length) { + return false; + } + + for (let group of groups1) { + let g2 = groups2.find(g => g.name === group.name); + // if we couldn't find the group it means they must not be equal + if (!g2) { + return false; + } + + // weird way to verify that each group appears the same number of times in each array + let result = groupsAreEqual(groups1.filter(a => a.parentId === group.id), groups2.filter(b => b.parentId === g2.id)); + if (!result) { + return false; + } + + } + + return true; + } + + test('getAllGroups should merge user and workspace settings correctly', () => { + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionGroupsArrayName, deepClone(testGroups).slice(0, 3), ConfigurationTarget.USER); + // we intentionally overlap these values with the expectation that the function to should return each group once + configurationService.updateValue(Constants.connectionGroupsArrayName, deepClone(testGroups).slice(2, testGroups.length), ConfigurationTarget.WORKSPACE); + + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + let allGroups = config.getAllGroups(); + + assert.equal(allGroups.length, testGroups.length, 'did not meet the expected length'); + assert.ok(groupsAreEqual(allGroups, testGroups), 'the groups returned did not match expectation'); + }); + + test('addConnection should add the new profile to user settings if does not exist', async () => { + let newProfile: IConnectionProfile = { + serverName: 'new server', + databaseName: 'database', + userName: 'user', + password: 'password', + authenticationType: '', + savePassword: true, + groupFullName: undefined, + groupId: undefined, + getOptionsKey: undefined, + matches: undefined, + providerName: 'MSSQL', + options: {}, + saveProfile: true, + id: undefined, + connectionName: undefined + }; + + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionGroupsArrayName, deepClone(testGroups), ConfigurationTarget.USER); + configurationService.updateValue(Constants.connectionsArrayName, deepClone(testConnections), ConfigurationTarget.USER); + let connectionProfile = new ConnectionProfile(capabilitiesService.object, newProfile); + connectionProfile.options['databaseDisplayName'] = 'database'; + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + let savedConnectionProfile = await config.addConnection(connectionProfile); + + assert.ok(!isUndefinedOrNull(savedConnectionProfile.id)); + assert.equal(configurationService.inspect(Constants.connectionsArrayName).user.length, testConnections.length + 1); + }); + + test('addConnection should not add the new profile to user settings if already exists', async () => { + let existingConnection = testConnections[0]; + let newProfile: IConnectionProfile = { + serverName: existingConnection.options['serverName'], + databaseName: existingConnection.options['databaseName'], + userName: existingConnection.options['userName'], + password: existingConnection.options['password'], + authenticationType: existingConnection.options['authenticationType'], + groupId: existingConnection.groupId, + savePassword: true, + groupFullName: undefined, + getOptionsKey: undefined, + matches: undefined, + providerName: 'MSSQL', + options: {}, + saveProfile: true, + id: undefined, + connectionName: undefined + }; + + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionGroupsArrayName, deepClone(testGroups), ConfigurationTarget.USER); + configurationService.updateValue(Constants.connectionsArrayName, deepClone(testConnections), ConfigurationTarget.USER); + + let connectionProfile = new ConnectionProfile(capabilitiesService.object, newProfile); + connectionProfile.options['databaseDisplayName'] = existingConnection.options['databaseName']; + + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + let savedConnectionProfile = await config.addConnection(connectionProfile); + + assert.equal(savedConnectionProfile.id, existingConnection.id); + assert.equal(configurationService.inspect(Constants.connectionsArrayName).user.length, testConnections.length); + }); + + test('addConnection should add the new group to user settings if does not exist', async () => { + let newProfile: IConnectionProfile = { + serverName: 'new server', + databaseName: 'database', + userName: 'user', + password: 'password', + authenticationType: '', + savePassword: true, + groupFullName: 'g2/g2-2', + groupId: undefined, + getOptionsKey: undefined, + matches: undefined, + providerName: 'MSSQL', + options: {}, + saveProfile: true, + id: undefined, + connectionName: undefined + }; + + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionGroupsArrayName, deepClone(testGroups), ConfigurationTarget.USER); + configurationService.updateValue(Constants.connectionsArrayName, deepClone(testConnections), ConfigurationTarget.USER); + + let connectionProfile = new ConnectionProfile(capabilitiesService.object, newProfile); + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + await config.addConnection(connectionProfile); + + assert.equal(configurationService.inspect(Constants.connectionsArrayName).user.length, testConnections.length + 1); + assert.equal(configurationService.inspect(Constants.connectionGroupsArrayName).user.length, testGroups.length + 1); + }); + + test('getConnections should return connections from user and workspace settings given getWorkspaceConnections set to true', () => { + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionsArrayName, deepClone(testConnections).slice(0, 1), ConfigurationTarget.USER); + configurationService.updateValue(Constants.connectionsArrayName, deepClone(testConnections).slice(1, testConnections.length), ConfigurationTarget.WORKSPACE); + + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + let allConnections = config.getConnections(true); + assert.equal(allConnections.length, testConnections.length); + }); + + test('getConnections should return connections from user settings given getWorkspaceConnections set to false', () => { + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionsArrayName, deepClone(testConnections).slice(0, 2), ConfigurationTarget.USER); + configurationService.updateValue(Constants.connectionsArrayName, deepClone(testConnections).slice(2, testConnections.length), ConfigurationTarget.WORKSPACE); + + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + let allConnections = config.getConnections(false); + assert.equal(allConnections.length, 2); + }); + + test('getConnections should return connections with a valid id', () => { + let workspaceConnections = deepClone(testConnections).map(c => { + c.id = c.options['serverName']; + return c; + }); + let userConnections = deepClone(testConnections).map(c => { + c.id = undefined; + return c; + }); + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionsArrayName, userConnections, ConfigurationTarget.USER); + configurationService.updateValue(Constants.connectionsArrayName, workspaceConnections, ConfigurationTarget.WORKSPACE); + + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + let allConnections = config.getConnections(false); + assert.equal(allConnections.length, testConnections.length); + allConnections.forEach(connection => { + let userConnection = testConnections.find(u => u.options['serverName'] === connection.serverName); + if (userConnection !== undefined) { + assert.notEqual(connection.id, connection.getOptionsKey()); + assert.ok(!isUndefinedOrNull(connection.id)); + } else { + let workspaceConnection = workspaceConnections.find(u => u.options['serverName'] === connection.serverName); + assert.notEqual(connection.id, connection.getOptionsKey()); + assert.equal(workspaceConnection.id, connection.id); + } + }); + }); + + test('saveGroup should save the new groups to tree and return the id of the last group name', () => { + let config = new ConnectionConfig(undefined, undefined); + let groups: IConnectionProfileGroup[] = deepClone(testGroups); + let newGroups: string = 'ROOT/g1/g1-1/new-group/new-group2'; + let color: string = 'red'; + + let result: ISaveGroupResult = config.saveGroup(groups, newGroups, color, newGroups); + assert.ok(!isUndefinedOrNull(result)); + assert.equal(result.groups.length, testGroups.length + 2, 'The result groups length is invalid'); + let newGroup = result.groups.find(g => g.name === 'new-group2'); + assert.equal(result.newGroupId, newGroup.id, 'The groups id is invalid'); + }); + + test('saveGroup should only add the groups that are not in the tree', () => { + let config = new ConnectionConfig(undefined, undefined); + let groups: IConnectionProfileGroup[] = deepClone(testGroups); + let newGroups: string = 'ROOT/g2/g2-5'; + let color: string = 'red'; + + let result: ISaveGroupResult = config.saveGroup(groups, newGroups, color, newGroups); + assert.ok(!isUndefinedOrNull(result)); + assert.equal(result.groups.length, testGroups.length + 1, 'The result groups length is invalid'); + let newGroup = result.groups.find(g => g.name === 'g2-5'); + assert.equal(result.newGroupId, newGroup.id, 'The groups id is invalid'); + }); + + test('saveGroup should not add any new group if tree already has all the groups in the full path', () => { + let config = new ConnectionConfig(undefined, undefined); + let groups: IConnectionProfileGroup[] = deepClone(testGroups); + let newGroups: string = 'ROOT/g2/g2-1'; + let color: string = 'red'; + + let result: ISaveGroupResult = config.saveGroup(groups, newGroups, color, newGroups); + assert.ok(!isUndefinedOrNull(result)); + assert.equal(result.groups.length, testGroups.length, 'The result groups length is invalid'); + let newGroup = result.groups.find(g => g.name === 'g2-1'); + assert.equal(result.newGroupId, newGroup.id, 'The groups id is invalid'); + }); + + test('deleteConnection should remove the connection from config', async () => { + let newProfile: IConnectionProfile = { + serverName: 'server3', + databaseName: 'database', + userName: 'user', + password: 'password', + authenticationType: '', + savePassword: true, + groupFullName: 'g3', + groupId: 'g3', + getOptionsKey: undefined, + matches: undefined, + providerName: 'MSSQL', + options: {}, + saveProfile: true, + id: undefined, + connectionName: undefined + }; + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionsArrayName, deepClone(testConnections), ConfigurationTarget.USER); + + let connectionProfile = new ConnectionProfile(capabilitiesService.object, newProfile); + connectionProfile.options['databaseDisplayName'] = 'database'; + + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + await config.deleteConnection(connectionProfile); + + assert.equal(configurationService.inspect(Constants.connectionsArrayName).user.length, testConnections.length - 1); + }); + + test('deleteConnectionGroup should remove the children connections and subgroups from config', async () => { + let newProfile: IConnectionProfile = { + serverName: 'server3', + databaseName: 'database', + userName: 'user', + password: 'password', + authenticationType: '', + savePassword: true, + groupFullName: 'g3', + groupId: 'g3', + getOptionsKey: undefined, + matches: undefined, + providerName: 'MSSQL', + options: {}, + saveProfile: true, + id: undefined, + connectionName: undefined + }; + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionsArrayName, deepClone(testConnections), ConfigurationTarget.USER); + configurationService.updateValue(Constants.connectionGroupsArrayName, deepClone(testGroups), ConfigurationTarget.USER); + + let connectionProfile = new ConnectionProfile(capabilitiesService.object, newProfile); + connectionProfile.options['databaseDisplayName'] = 'database'; + + let connectionProfileGroup = new ConnectionProfileGroup('g3', undefined, 'g3', undefined, undefined); + let childGroup = new ConnectionProfileGroup('g3-1', connectionProfileGroup, 'g3-1', undefined, undefined); + connectionProfileGroup.addGroups([childGroup]); + connectionProfileGroup.addConnections([connectionProfile]); + + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + await config.deleteGroup(connectionProfileGroup); + + assert.equal(configurationService.inspect(Constants.connectionsArrayName).user.length, testConnections.length - 1); + assert.equal(configurationService.inspect(Constants.connectionGroupsArrayName).user.length, testGroups.length - 2); + }); + + test('deleteConnection should not throw error for connection not in config', async () => { + let newProfile: IConnectionProfile = { + serverName: 'connectionNotThere', + databaseName: 'database', + userName: 'user', + password: 'password', + authenticationType: '', + savePassword: true, + groupFullName: 'g3', + groupId: 'newid', + getOptionsKey: undefined, + matches: undefined, + providerName: 'MSSQL', + options: {}, + saveProfile: true, + id: undefined, + connectionName: undefined + }; + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionsArrayName, deepClone(testConnections), ConfigurationTarget.USER); + + let connectionProfile = new ConnectionProfile(capabilitiesService.object, newProfile); + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + await config.deleteConnection(connectionProfile); + + assert.equal(configurationService.inspect(Constants.connectionsArrayName).user.length, testConnections.length); + }); + + test('renameGroup should change group name', async () => { + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionGroupsArrayName, deepClone(testGroups), ConfigurationTarget.USER); + + let connectionProfileGroup = new ConnectionProfileGroup('g-renamed', undefined, 'g2', undefined, undefined); + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + await config.editGroup(connectionProfileGroup); + + let editedGroups = configurationService.inspect(Constants.connectionGroupsArrayName).user; + + assert.equal(editedGroups.length, testGroups.length); + let editedGroup = editedGroups.find(group => group.id === 'g2'); + assert.ok(!isUndefinedOrNull(editedGroup)); + assert.equal(editedGroup.name, 'g-renamed'); + }); + + test('edit group should throw if there is a confliction', async () => { + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionGroupsArrayName, deepClone(testGroups), ConfigurationTarget.USER); + + let sameNameGroup = new ConnectionProfileGroup('g3', undefined, 'g2', undefined, undefined); + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + + try { + await config.editGroup(sameNameGroup); + assert.fail(); + } catch (e) { + let groups = configurationService.inspect(Constants.connectionGroupsArrayName).user; + let originalGroup = groups.find(g => g.id === 'g2'); + assert.ok(!isUndefinedOrNull(originalGroup)); + assert.equal(originalGroup.name, 'g2'); + } + }); + + test('change group(parent) for connection group', async () => { + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionGroupsArrayName, deepClone(testGroups), ConfigurationTarget.USER); + + let sourceProfileGroup = new ConnectionProfileGroup('g2', undefined, 'g2', undefined, undefined); + let targetProfileGroup = new ConnectionProfileGroup('g3', undefined, 'g3', undefined, undefined); + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + await config.changeGroupIdForConnectionGroup(sourceProfileGroup, targetProfileGroup); + + let editedGroups = configurationService.inspect(Constants.connectionGroupsArrayName).user; + + assert.equal(editedGroups.length, testGroups.length); + let editedGroup = editedGroups.find(group => group.id === 'g2'); + assert.ok(!isUndefinedOrNull(editedGroup)); + assert.equal(editedGroup.parentId, 'g3'); + }); + + + test('change group for connection with conflict should throw', async () => { + let changingProfile: IConnectionProfile = { + serverName: 'server3', + databaseName: 'database', + userName: 'user', + password: 'password', + authenticationType: '', + savePassword: true, + groupFullName: 'g3', + groupId: 'g3', + getOptionsKey: () => { return 'connectionId'; }, + matches: undefined, + providerName: 'MSSQL', + options: {}, + saveProfile: true, + id: 'server3-2', + connectionName: undefined + }; + let existingProfile = ConnectionProfile.convertToProfileStore(capabilitiesService.object, { + serverName: 'server3', + databaseName: 'database', + userName: 'user', + password: 'password', + authenticationType: '', + savePassword: true, + groupFullName: 'test', + groupId: 'test', + getOptionsKey: () => { return 'connectionId'; }, + matches: undefined, + providerName: 'MSSQL', + options: {}, + saveProfile: true, + id: 'server3', + connectionName: undefined + }); + + let _testConnections = deepClone(testConnections).concat([existingProfile, changingProfile]); + + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionsArrayName, _testConnections, ConfigurationTarget.USER); + + let connectionProfile = new ConnectionProfile(capabilitiesService.object, changingProfile); + + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + try { + await config.changeGroupIdForConnection(connectionProfile, 'test'); + assert.fail(); + } catch (e) { + let editedConnections = configurationService.inspect(Constants.connectionsArrayName).user; + // two + assert.equal(editedConnections.length, _testConnections.length); + let editedConnection = editedConnections.find(con => con.id === 'server3-2'); + assert.ok(!isUndefinedOrNull(editedConnection)); + assert.equal(editedConnection.groupId, 'g3'); + } + }); + + test('change group(parent) for connection', async () => { + let newProfile: IConnectionProfile = { + serverName: 'server3', + databaseName: 'database', + userName: 'user', + password: 'password', + authenticationType: '', + savePassword: true, + groupFullName: 'g3', + groupId: 'g3', + getOptionsKey: () => { return 'connectionId'; }, + matches: undefined, + providerName: 'MSSQL', + options: {}, + saveProfile: true, + id: 'server3', + connectionName: undefined + }; + + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionsArrayName, deepClone(testConnections), ConfigurationTarget.USER); + + let connectionProfile = new ConnectionProfile(capabilitiesService.object, newProfile); + let newId = 'newid'; + + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + await config.changeGroupIdForConnection(connectionProfile, newId); + + let editedConnections = configurationService.inspect(Constants.connectionsArrayName).user; + assert.equal(editedConnections.length, testConnections.length); + let editedConnection = editedConnections.find(con => con.id === 'server3'); + assert.ok(!isUndefinedOrNull(editedConnection)); + assert.equal(editedConnection.groupId, 'newid'); + }); + + test('addConnection should not move the connection when editing', async () => { + // Set up the connection config + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionsArrayName, deepClone(testConnections), ConfigurationTarget.USER); + configurationService.updateValue(Constants.connectionGroupsArrayName, deepClone(testGroups), ConfigurationTarget.USER); + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + + // Clone a connection and modify an option + const connectionIndex = 1; + const optionKey = 'testOption'; + const optionValue = 'testValue'; + let allConnections = config.getConnections(false); + let oldLength = allConnections.length; + let connectionToEdit = allConnections[connectionIndex].clone(); + connectionToEdit.options[optionKey] = optionValue; + await config.addConnection(connectionToEdit); + + // Get the connection and verify that it is in the same place and has been updated + let newConnections = config.getConnections(false); + assert.equal(newConnections.length, oldLength); + let editedConnection = newConnections[connectionIndex]; + assert.equal(editedConnection.getOptionsKey(), connectionToEdit.getOptionsKey()); + assert.equal(editedConnection.options[optionKey], optionValue); + }); + + test('addgroup works', async () => { + let newGroup: IConnectionProfileGroup = { + id: undefined, + parentId: undefined, + name: 'new group', + color: 'red', + description: 'new group' + }; + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionGroupsArrayName, deepClone(testGroups), ConfigurationTarget.USER); + + let config = new ConnectionConfig(configurationService, capabilitiesService.object); + + await config.addGroup(newGroup); + + let editGroups = configurationService.inspect(Constants.connectionGroupsArrayName).user; + + assert.equal(editGroups.length, testGroups.length + 1); + }); + + test('addGroup rejects if group name already exists', async () => { + let existingGroupName: IConnectionProfileGroup = { + id: undefined, + parentId: undefined, + name: 'g2', + color: 'red', + description: 'new group' + }; + let configurationService = new TestConfigurationService(); + configurationService.updateValue(Constants.connectionGroupsArrayName, deepClone(testGroups), ConfigurationTarget.USER); + + const config = new ConnectionConfig(configurationService, capabilitiesService.object); + try { + await config.addGroup(existingGroupName); + assert.fail(); + } catch (e) { + let editGroups = configurationService.inspect(Constants.connectionGroupsArrayName).user; + + assert.equal(editGroups.length, testGroups.length); + } + }); +}); diff --git a/src/sql/platform/connection/test/common/testConfigurationService.ts b/src/sql/platform/connection/test/common/testConfigurationService.ts new file mode 100644 index 0000000000..232fa6eb6e --- /dev/null +++ b/src/sql/platform/connection/test/common/testConfigurationService.ts @@ -0,0 +1,79 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { getConfigurationKeys, IConfigurationOverrides, IConfigurationService, getConfigurationValue, isConfigurationOverrides, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; + +export class TestConfigurationService implements IConfigurationService { + public _serviceBrand: any; + + private configuration = { + user: {}, + workspace: {} + }; + + public reloadConfiguration(): Promise { + return Promise.resolve(this.getValue()); + } + + public getValue(arg1?: any, arg2?: any): any { + let configuration; + configuration = configuration ? configuration : this.configuration; + if (arg1 && typeof arg1 === 'string') { + return getConfigurationValue(configuration, arg1); + } + return configuration; + } + + public updateValue(key: string, value: any, target?: any): Promise { + let _target = (target as ConfigurationTarget) === ConfigurationTarget.USER ? 'user' : 'workspace'; + let keyArray = key.split('.'); + let targetObject = this.configuration[_target]; + for (let i = 0; i < keyArray.length; i++) { + if (i === keyArray.length - 1) { + targetObject[keyArray[i]] = value; + } else { + if (!targetObject[keyArray[i]]) { + targetObject[keyArray[i]] = {}; + } + targetObject = targetObject[keyArray[i]]; + } + } + return Promise.resolve(void 0); + } + + public onDidChangeConfiguration() { + return { dispose() { } }; + } + + public inspect(key: string, overrides?: IConfigurationOverrides): { + default: T, + user: T, + workspace?: T, + workspaceFolder?: T + value: T, + } { + + return { + value: getConfigurationValue(this.configuration.user, key), + default: undefined, + user: getConfigurationValue(this.configuration.user, key), + workspace: getConfigurationValue(this.configuration.workspace, key), + workspaceFolder: undefined + }; + } + + public keys() { + return { + default: getConfigurationKeys(), + user: Object.keys(this.configuration), + workspace: [], + workspaceFolder: [] + }; + } + + public getConfigurationData() { + return null; + } +} diff --git a/src/sqltest/parts/connection/connectionConfig.test.ts b/src/sqltest/parts/connection/connectionConfig.test.ts deleted file mode 100644 index eea6f93b5c..0000000000 --- a/src/sqltest/parts/connection/connectionConfig.test.ts +++ /dev/null @@ -1,954 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - - -import * as TypeMoq from 'typemoq'; -import { ConnectionConfig, ISaveGroupResult } from 'sql/platform/connection/common/connectionConfig'; -import { IConnectionProfile, IConnectionProfileStore } from 'sql/platform/connection/common/interfaces'; -import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; -import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; -import { WorkspaceConfigurationTestService } from 'sqltest/stubs/workspaceConfigurationTestService'; -import * as Constants from 'sql/platform/connection/common/constants'; -import { IConnectionProfileGroup, ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; -import * as assert from 'assert'; -import { ProviderFeatures, ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; -import * as azdata from 'azdata'; -import { Emitter } from 'vs/base/common/event'; -import { ConnectionOptionSpecialType, ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes'; -import { CapabilitiesTestService } from 'sqltest/stubs/capabilitiesTestService'; -import { ConfigurationEditingService, IConfigurationValue } from 'vs/workbench/services/configuration/common/configurationEditingService'; - -suite('SQL ConnectionConfig tests', () => { - let capabilitiesService: TypeMoq.Mock; - let workspaceConfigurationServiceMock: TypeMoq.Mock; - let configEditingServiceMock: TypeMoq.Mock; - let msSQLCapabilities: ProviderFeatures; - let capabilities: ProviderFeatures[]; - let onCapabilitiesRegistered = new Emitter(); - - let configValueToConcat = { - workspace: [{ - name: 'g1', - id: 'g1', - parentId: 'ROOT', - color: 'pink', - description: 'g1' - }, - { - name: 'g1-1', - id: 'g1-1', - parentId: 'g1', - color: 'blue', - description: 'g1-1' - } - ], - user: [{ - name: 'ROOT', - id: 'ROOT', - parentId: '', - color: 'white', - description: 'ROOT' - }, { - name: 'g2', - id: 'g2', - parentId: 'ROOT', - color: 'green', - description: 'g2' - }, - { - name: 'g2-1', - id: 'g2-1', - parentId: 'g2', - color: 'yellow', - description: 'g2' - }, - { - name: 'g3', - id: 'g3', - parentId: '', - color: 'orange', - description: 'g3' - }, - { - name: 'g3-1', - id: 'g3-1', - parentId: 'g3', - color: 'purple', - description: 'g3-1' - } - ], - value: [], - default: [], - workspaceFolder: [] - }; - - let configValueToMerge = { - workspace: [ - { - name: 'g1', - id: 'g1', - parentId: '', - color: 'pink', - description: 'g1' - }, - { - name: 'g1-1', - id: 'g1-1', - parentId: 'g1', - color: 'blue', - description: 'g1-1' - } - ], - user: [ - { - name: 'g2', - id: 'g2', - parentId: '', - color: 'green', - description: 'g2' - }, - { - name: 'g2-1', - id: 'g2-1', - parentId: 'g2', - color: 'yellow', - description: 'g2' - }, - { - name: 'g1', - id: 'g1', - parentId: '', - color: 'pink', - description: 'g1' - }, - { - name: 'g1-2', - id: 'g1-2', - parentId: 'g1', - color: 'silver', - description: 'g1-2' - }], - value: [], - default: [], - workspaceFolder: [] - }; - - let connections = { - workspace: [{ - options: { - serverName: 'server1', - databaseName: 'database', - userName: 'user', - password: 'password', - authenticationType: '' - }, - providerName: 'MSSQL', - groupId: 'test', - savePassword: true, - id: 'server1' - } - - - ], - user: [{ - options: { - serverName: 'server2', - databaseName: 'database', - userName: 'user', - password: 'password', - authenticationType: '' - }, - providerName: 'MSSQL', - groupId: 'test', - savePassword: true, - id: 'server2' - }, { - options: { - serverName: 'server3', - databaseName: 'database', - userName: 'user', - password: 'password', - authenticationType: '' - }, - providerName: 'MSSQL', - groupId: 'g3', - savePassword: true, - id: 'server3' - } - ], - value: [], - default: [], - workspaceFolder: [] - }; - setup(() => { - capabilitiesService = TypeMoq.Mock.ofType(CapabilitiesTestService); - capabilities = []; - let connectionProvider: azdata.ConnectionProviderOptions = { - options: [ - { - name: 'serverName', - displayName: undefined, - description: undefined, - groupName: undefined, - categoryValues: undefined, - defaultValue: undefined, - isIdentity: true, - isRequired: true, - specialValueType: ConnectionOptionSpecialType.serverName, - valueType: ServiceOptionType.string - }, - { - name: 'databaseName', - displayName: undefined, - description: undefined, - groupName: undefined, - categoryValues: undefined, - defaultValue: undefined, - isIdentity: true, - isRequired: true, - specialValueType: ConnectionOptionSpecialType.databaseName, - valueType: ServiceOptionType.string - }, - { - name: 'userName', - displayName: undefined, - description: undefined, - groupName: undefined, - categoryValues: undefined, - defaultValue: undefined, - isIdentity: true, - isRequired: true, - specialValueType: ConnectionOptionSpecialType.userName, - valueType: ServiceOptionType.string - }, - { - name: 'authenticationType', - displayName: undefined, - description: undefined, - groupName: undefined, - categoryValues: undefined, - defaultValue: undefined, - isIdentity: true, - isRequired: true, - specialValueType: ConnectionOptionSpecialType.authType, - valueType: ServiceOptionType.string - }, - { - name: 'password', - displayName: undefined, - description: undefined, - groupName: undefined, - categoryValues: undefined, - defaultValue: undefined, - isIdentity: true, - isRequired: true, - specialValueType: ConnectionOptionSpecialType.password, - valueType: ServiceOptionType.string - } - ] - }; - msSQLCapabilities = { - connection: { - providerId: 'MSSQL', - displayName: 'MSSQL', - connectionOptions: connectionProvider.options - } - }; - capabilities.push(msSQLCapabilities); - - capabilitiesService.setup(x => x.getCapabilities('MSSQL')).returns(() => msSQLCapabilities); - (capabilitiesService.object as any).onCapabilitiesRegistered = onCapabilitiesRegistered.event; - - workspaceConfigurationServiceMock = TypeMoq.Mock.ofType(WorkspaceConfigurationTestService); - workspaceConfigurationServiceMock.setup(x => x.reloadConfiguration()) - .returns(() => Promise.resolve(undefined)); - - configEditingServiceMock = TypeMoq.Mock.ofType(ConfigurationEditingService); - configEditingServiceMock.setup(x => x.writeConfiguration(ConfigurationTarget.USER, TypeMoq.It.isAny())).returns(() => Promise.resolve(undefined)); - configEditingServiceMock.setup(x => x.writeConfiguration(ConfigurationTarget.WORKSPACE, TypeMoq.It.isAny())).returns(() => Promise.resolve(undefined)); - }); - - function groupsAreEqual(groups1: IConnectionProfileGroup[], groups2: IConnectionProfileGroup[]): Boolean { - if (!groups1 && !groups2) { - return true; - } else if ((!groups1 && groups2 && groups2.length === 0) || (!groups2 && groups1 && groups1.length === 0)) { - return true; - } - - if (groups1.length !== groups2.length) { - return false; - } - - let areEqual = true; - - groups1.map(g1 => { - if (areEqual) { - let g2 = groups2.find(g => g.name === g1.name); - if (!g2) { - areEqual = false; - } else { - let result = groupsAreEqual(groups1.filter(a => a.parentId === g1.id), groups2.filter(b => b.parentId === g2.id)); - if (result === false) { - areEqual = false; - } - } - } - }); - - return areEqual; - } - - test('allGroups should return groups from user and workspace settings', () => { - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionGroupsArrayName)) - .returns(() => configValueToConcat); - - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - let allGroups = config.getAllGroups(); - - - assert.notEqual(allGroups, undefined); - assert.equal(allGroups.length, configValueToConcat.workspace.length + configValueToConcat.user.length); - }); - - test('allGroups should merge groups from user and workspace settings', () => { - let expectedAllGroups: IConnectionProfileGroup[] = [ - { - name: 'g1', - id: 'g1', - parentId: '', - color: 'pink', - description: 'g1' - }, - { - name: 'g1-1', - id: 'g1-1', - parentId: 'g1', - color: 'blue', - description: 'g1-1' - }, - { - name: 'g2', - id: 'g2', - parentId: '', - color: 'yellow', - description: 'g2' - }, - { - name: 'g2-1', - id: 'g2-1', - parentId: 'g2', - color: 'red', - description: 'g2' - }, - { - name: 'g1-2', - id: 'g1-2', - parentId: 'g1', - color: 'green', - description: 'g1-2' - }]; - - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionGroupsArrayName)) - .returns(() => configValueToMerge); - - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - let allGroups = config.getAllGroups(); - - - assert.notEqual(allGroups, undefined); - assert.equal(groupsAreEqual(allGroups, expectedAllGroups), true); - }); - - test('addConnection should add the new profile to user settings if does not exist', done => { - let newProfile: IConnectionProfile = { - serverName: 'new server', - databaseName: 'database', - userName: 'user', - password: 'password', - authenticationType: '', - savePassword: true, - groupFullName: undefined, - groupId: undefined, - getOptionsKey: undefined, - matches: undefined, - providerName: 'MSSQL', - options: {}, - saveProfile: true, - id: undefined, - connectionName: undefined - }; - - let expectedNumberOfConnections = connections.user.length + 1; - - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionsArrayName)) - .returns(() => connections); - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionGroupsArrayName)) - .returns(() => configValueToConcat); - - let connectionProfile = new ConnectionProfile(capabilitiesService.object, newProfile); - connectionProfile.options['databaseDisplayName'] = 'database'; - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - config.addConnection(connectionProfile).then(savedConnectionProfile => { - configEditingServiceMock.verify(y => y.writeConfiguration(ConfigurationTarget.USER, - TypeMoq.It.is(c => (c.value as IConnectionProfileStore[]).length === expectedNumberOfConnections)), TypeMoq.Times.once()); - assert.notEqual(savedConnectionProfile.id, undefined); - done(); - }).catch(error => { - done(error); - }); - }); - - test('addConnection should not add the new profile to user settings if already exists', done => { - let profileFromConfig = connections.user[0]; - let newProfile: IConnectionProfile = { - serverName: profileFromConfig.options['serverName'], - databaseName: profileFromConfig.options['databaseName'], - userName: profileFromConfig.options['userName'], - password: profileFromConfig.options['password'], - authenticationType: profileFromConfig.options['authenticationType'], - groupId: profileFromConfig.groupId, - savePassword: true, - groupFullName: undefined, - getOptionsKey: undefined, - matches: undefined, - providerName: 'MSSQL', - options: {}, - saveProfile: true, - id: undefined, - connectionName: undefined - }; - - let expectedNumberOfConnections = connections.user.length; - - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionsArrayName)) - .returns(() => connections); - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionGroupsArrayName)) - .returns(() => configValueToConcat); - - let connectionProfile = new ConnectionProfile(capabilitiesService.object, newProfile); - connectionProfile.options['databaseDisplayName'] = profileFromConfig.options['databaseName']; - - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - config.addConnection(connectionProfile).then(savedConnectionProfile => { - configEditingServiceMock.verify(y => y.writeConfiguration(ConfigurationTarget.USER, - TypeMoq.It.is(c => (c.value as IConnectionProfileStore[]).length === expectedNumberOfConnections)), TypeMoq.Times.once()); - assert.equal(savedConnectionProfile.id, profileFromConfig.id); - done(); - }).catch(error => { - done(error); - }); - }); - - test('addConnection should add the new group to user settings if does not exist', done => { - let newProfile: IConnectionProfile = { - serverName: 'new server', - databaseName: 'database', - userName: 'user', - password: 'password', - authenticationType: '', - savePassword: true, - groupFullName: 'g2/g2-2', - groupId: undefined, - getOptionsKey: undefined, - matches: undefined, - providerName: 'MSSQL', - options: {}, - saveProfile: true, - id: undefined, - connectionName: undefined - }; - - let expectedNumberOfConnections = connections.user.length + 1; - let expectedNumberOfGroups = configValueToConcat.user.length + 1; - - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionsArrayName)) - .returns(() => connections); - - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionGroupsArrayName)) - .returns(() => configValueToConcat); - - let connectionProfile = new ConnectionProfile(capabilitiesService.object, newProfile); - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - config.addConnection(connectionProfile).then(success => { - configEditingServiceMock.verify(y => y.writeConfiguration(ConfigurationTarget.USER, - TypeMoq.It.is(c => (c.value as IConnectionProfileStore[]).length === expectedNumberOfConnections)), TypeMoq.Times.once()); - configEditingServiceMock.verify(y => y.writeConfiguration(ConfigurationTarget.USER, - TypeMoq.It.is(c => (c.value as IConnectionProfileGroup[]).length === expectedNumberOfGroups)), TypeMoq.Times.once()); - done(); - }).catch(error => { - done(error); - }); - }); - - test('getConnections should return connections from user and workspace settings given getWorkspaceConnections set to true', () => { - let getWorkspaceConnections: boolean = true; - - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionsArrayName)) - .returns(() => connections); - - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - let allConnections = config.getConnections(getWorkspaceConnections); - assert.equal(allConnections.length, connections.user.length + connections.workspace.length); - }); - - test('getConnections should return connections from user settings given getWorkspaceConnections set to false', () => { - let getWorkspaceConnections: boolean = false; - - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionsArrayName)) - .returns(() => connections); - - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - let allConnections = config.getConnections(getWorkspaceConnections); - assert.equal(allConnections.length, connections.user.length); - }); - - test('getConnections should return connections with a valid id', () => { - let getWorkspaceConnections: boolean = false; - let connectionsWithNoId = { - user: connections.user.map(c => { - c.id = undefined; - return c; - }), - default: connections.default, - workspace: connections.workspace.map(c => { - c.id = c.options['serverName']; - return c; - }), - value: connections.value, - workspaceFolder: [] - }; - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionsArrayName)) - .returns(() => connectionsWithNoId); - - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - let allConnections = config.getConnections(getWorkspaceConnections); - assert.equal(allConnections.length, connections.user.length); - allConnections.forEach(connection => { - let userConnection = connectionsWithNoId.user.find(u => u.options['serverName'] === connection.serverName); - if (userConnection !== undefined) { - assert.notEqual(connection.id, connection.getOptionsKey()); - assert.notEqual(connection.id, undefined); - } else { - let workspaceConnection = connectionsWithNoId.workspace.find(u => u.options['serverName'] === connection.serverName); - assert.notEqual(connection.id, connection.getOptionsKey()); - assert.equal(workspaceConnection.id, connection.id); - } - }); - }); - - test('getConnections update the capabilities in each profile when the provider capabilities is registered', () => { - let oldOptionName: string = 'oldOptionName'; - let optionsMetadataFromConfig = capabilities[0].connection.connectionOptions.concat({ - name: oldOptionName, - displayName: undefined, - description: undefined, - groupName: undefined, - categoryValues: undefined, - defaultValue: undefined, - isIdentity: true, - isRequired: true, - specialValueType: undefined, - valueType: ServiceOptionType.string - }); - - let capabilitiesFromConfig: ProviderFeatures[] = []; - let msSQLCapabilities2: ProviderFeatures = { - connection: { - providerId: 'MSSQL', - displayName: 'MSSQL', - connectionOptions: optionsMetadataFromConfig - } - }; - capabilitiesFromConfig.push(msSQLCapabilities2); - let connectionUsingOldMetadata = connections.user.map(c => { - c.options[oldOptionName] = 'oldOptionValue'; - return c; - }); - let configValue = Object.assign({}, connections, { user: connectionUsingOldMetadata }); - let capabilitiesService2: TypeMoq.Mock = TypeMoq.Mock.ofType(CapabilitiesTestService); - capabilitiesService2.setup(x => x.getCapabilities('MSSQL')).returns(() => msSQLCapabilities2); - (capabilitiesService2.object as any).onCapabilitiesRegistered = onCapabilitiesRegistered.event; - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionsArrayName)) - .returns(() => configValue); - - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService2.object); - let allConnections = config.getConnections(false); - allConnections.forEach(element => { - assert.notEqual(element.serverName, undefined); - assert.notEqual(element.getOptionsKey().indexOf('oldOptionValue|'), -1); - }); - - onCapabilitiesRegistered.fire(msSQLCapabilities); - allConnections.forEach(element => { - assert.notEqual(element.serverName, undefined); - assert.equal(element.getOptionsKey().indexOf('oldOptionValue|'), -1); - }); - }); - - test('saveGroup should save the new groups to tree and return the id of the last group name', () => { - let config = new ConnectionConfig(undefined, undefined, undefined); - let groups: IConnectionProfileGroup[] = configValueToConcat.user; - let expectedLength = configValueToConcat.user.length + 2; - let newGroups: string = 'ROOT/g1/g1-1'; - let color: string = 'red'; - - let result: ISaveGroupResult = config.saveGroup(groups, newGroups, color, newGroups); - assert.notEqual(result, undefined); - assert.equal(result.groups.length, expectedLength, 'The result groups length is invalid'); - let newGroup = result.groups.find(g => g.name === 'g1-1'); - assert.equal(result.newGroupId, newGroup.id, 'The groups id is invalid'); - }); - - test('saveGroup should only add the groups that are not in the tree', () => { - let config = new ConnectionConfig(undefined, undefined, undefined); - let groups: IConnectionProfileGroup[] = configValueToConcat.user; - let expectedLength = configValueToConcat.user.length + 1; - let newGroups: string = 'ROOT/g2/g2-5'; - let color: string = 'red'; - - let result: ISaveGroupResult = config.saveGroup(groups, newGroups, color, newGroups); - assert.notEqual(result, undefined); - assert.equal(result.groups.length, expectedLength, 'The result groups length is invalid'); - let newGroup = result.groups.find(g => g.name === 'g2-5'); - assert.equal(result.newGroupId, newGroup.id, 'The groups id is invalid'); - }); - - test('saveGroup should not add any new group if tree already has all the groups in the full path', () => { - let config = new ConnectionConfig(undefined, undefined, undefined); - let groups: IConnectionProfileGroup[] = configValueToConcat.user; - let expectedLength = configValueToConcat.user.length; - let newGroups: string = 'ROOT/g2/g2-1'; - let color: string = 'red'; - - let result: ISaveGroupResult = config.saveGroup(groups, newGroups, color, newGroups); - assert.notEqual(result, undefined); - assert.equal(result.groups.length, expectedLength, 'The result groups length is invalid'); - let newGroup = result.groups.find(g => g.name === 'g2-1'); - assert.equal(result.newGroupId, newGroup.id, 'The groups id is invalid'); - }); - - test('deleteConnection should remove the connection from config', done => { - let newProfile: IConnectionProfile = { - serverName: 'server3', - databaseName: 'database', - userName: 'user', - password: 'password', - authenticationType: '', - savePassword: true, - groupFullName: 'g3', - groupId: 'g3', - getOptionsKey: undefined, - matches: undefined, - providerName: 'MSSQL', - options: {}, - saveProfile: true, - id: undefined, - connectionName: undefined - }; - - let expectedNumberOfConnections = connections.user.length - 1; - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionsArrayName)) - .returns(() => connections); - - let connectionProfile = new ConnectionProfile(capabilitiesService.object, newProfile); - connectionProfile.options['databaseDisplayName'] = 'database'; - - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - config.deleteConnection(connectionProfile).then(() => { - configEditingServiceMock.verify(y => y.writeConfiguration(ConfigurationTarget.USER, - TypeMoq.It.is(c => (c.value as IConnectionProfileStore[]).length === expectedNumberOfConnections)), TypeMoq.Times.once()); - done(); - }).catch(error => { - done(error); - }); - }); - - test('deleteConnectionGroup should remove the children connections and subgroups from config', done => { - let newProfile: IConnectionProfile = { - serverName: 'server3', - databaseName: 'database', - userName: 'user', - password: 'password', - authenticationType: '', - savePassword: true, - groupFullName: 'g3', - groupId: 'g3', - getOptionsKey: undefined, - matches: undefined, - providerName: 'MSSQL', - options: {}, - saveProfile: true, - id: undefined, - connectionName: undefined - }; - let connectionProfile = new ConnectionProfile(capabilitiesService.object, newProfile); - connectionProfile.options['databaseDisplayName'] = 'database'; - - let connectionProfileGroup = new ConnectionProfileGroup('g3', undefined, 'g3', undefined, undefined); - let childGroup = new ConnectionProfileGroup('g3-1', connectionProfileGroup, 'g3-1', undefined, undefined); - connectionProfileGroup.addGroups([childGroup]); - connectionProfileGroup.addConnections([connectionProfile]); - - let expectedNumberOfConnections = connections.user.length - 1; - let expectedNumberOfGroups = configValueToConcat.user.length - 2; - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionsArrayName)) - .returns(() => connections); - - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionGroupsArrayName)) - .returns(() => configValueToConcat); - - - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - config.deleteGroup(connectionProfileGroup).then(() => { - configEditingServiceMock.verify(y => y.writeConfiguration(ConfigurationTarget.USER, - TypeMoq.It.is(c => (c.value as IConnectionProfileStore[]).length === expectedNumberOfConnections)), TypeMoq.Times.once()); - configEditingServiceMock.verify(y => y.writeConfiguration(ConfigurationTarget.USER, - TypeMoq.It.is(c => (c.value as IConnectionProfileGroup[]).length === expectedNumberOfGroups)), TypeMoq.Times.once()); - done(); - }).catch(error => { - done(error); - }); - }); - - test('deleteConnection should not throw error for connection not in config', done => { - let newProfile: IConnectionProfile = { - serverName: 'server3', - databaseName: 'database', - userName: 'user', - password: 'password', - authenticationType: '', - savePassword: true, - groupFullName: 'g3', - groupId: 'newid', - getOptionsKey: undefined, - matches: undefined, - providerName: 'MSSQL', - options: {}, - saveProfile: true, - id: undefined, - connectionName: undefined - }; - - let expectedNumberOfConnections = connections.user.length; - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionsArrayName)) - .returns(() => connections); - - let connectionProfile = new ConnectionProfile(capabilitiesService.object, newProfile); - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - config.deleteConnection(connectionProfile).then(() => { - configEditingServiceMock.verify(y => y.writeConfiguration(ConfigurationTarget.USER, - TypeMoq.It.is(c => (c.value as IConnectionProfileStore[]).length === expectedNumberOfConnections)), TypeMoq.Times.once()); - done(); - }).catch(error => { - done(error); - }); - }); - - test('renameGroup should change group name', done => { - - let expectedNumberOfConnections = configValueToConcat.user.length; - let calledValue: any; - let called: boolean = false; - let nothing: void; - let configEditingServiceMock: TypeMoq.Mock = TypeMoq.Mock.ofType(ConfigurationEditingService); - configEditingServiceMock.setup(x => x.writeConfiguration(ConfigurationTarget.USER, TypeMoq.It.isAny())).callback((x: any, val: any) => { - calledValue = val.value as IConnectionProfileStore[]; - }).returns(() => Promise.resolve(undefined)); - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionGroupsArrayName)) - .returns(() => configValueToConcat); - - let connectionProfileGroup = new ConnectionProfileGroup('g-renamed', undefined, 'g2', undefined, undefined); - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - config.editGroup(connectionProfileGroup).then(() => { - configEditingServiceMock.verify(y => y.writeConfiguration(ConfigurationTarget.USER, - TypeMoq.It.is(c => (c.value as IConnectionProfileStore[]).length === expectedNumberOfConnections)), TypeMoq.Times.once()); - calledValue.forEach(con => { - if (con.id === 'g2') { - assert.equal(con.name, 'g-renamed', 'Group was not renamed'); - called = true; - } - }); - assert.equal(called, true, 'group was not renamed'); - }).then(() => done(), (err) => done(err)); - }); - - - test('change group(parent) for connection group', done => { - let expectedNumberOfConnections = configValueToConcat.user.length; - let calledValue: any; - let nothing: void; - let configEditingServiceMock: TypeMoq.Mock = TypeMoq.Mock.ofType(ConfigurationEditingService); - configEditingServiceMock.setup(x => x.writeConfiguration(ConfigurationTarget.USER, TypeMoq.It.isAny())).callback((x: any, val: any) => { - calledValue = val.value as IConnectionProfileStore[]; - }).returns(() => Promise.resolve(undefined)); - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionGroupsArrayName)) - .returns(() => configValueToConcat); - - let sourceProfileGroup = new ConnectionProfileGroup('g2', undefined, 'g2', undefined, undefined); - let targetProfileGroup = new ConnectionProfileGroup('g3', undefined, 'g3', undefined, undefined); - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - config.changeGroupIdForConnectionGroup(sourceProfileGroup, targetProfileGroup).then(() => { - configEditingServiceMock.verify(y => y.writeConfiguration(ConfigurationTarget.USER, - TypeMoq.It.is(c => (c.value as IConnectionProfileStore[]).length === expectedNumberOfConnections)), TypeMoq.Times.once()); - calledValue.forEach(con => { - if (con.id === 'g2') { - assert.equal(con.parentId, 'g3', 'Group parent was not changed'); - } - }); - }).then(() => done(), (err) => done(err)); - }); - - - test('change group(parent) for connection', done => { - let newProfile: IConnectionProfile = { - serverName: 'server3', - databaseName: 'database', - userName: 'user', - password: 'password', - authenticationType: '', - savePassword: true, - groupFullName: 'g3', - groupId: 'g3', - getOptionsKey: () => { return 'connectionId'; }, - matches: undefined, - providerName: 'MSSQL', - options: {}, - saveProfile: true, - id: 'test', - connectionName: undefined - }; - - let expectedNumberOfConnections = connections.user.length; - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionsArrayName)) - .returns(() => connections); - - let connectionProfile = new ConnectionProfile(capabilitiesService.object, newProfile); - let newId = 'newid'; - let calledValue: any; - let nothing: void; - let configEditingServiceMock: TypeMoq.Mock = TypeMoq.Mock.ofType(ConfigurationEditingService); - configEditingServiceMock.setup(x => x.writeConfiguration(ConfigurationTarget.USER, TypeMoq.It.isAny())).callback((x: any, val: any) => { - calledValue = val.value as IConnectionProfileStore[]; - }).returns(() => Promise.resolve(undefined)); - configEditingServiceMock.setup(x => x.writeConfiguration(ConfigurationTarget.WORKSPACE, TypeMoq.It.isAny())).callback((x: any, val: any) => { - - }).returns(() => Promise.resolve(undefined)); - - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - config.changeGroupIdForConnection(connectionProfile, newId).then(() => { - configEditingServiceMock.verify(y => y.writeConfiguration(ConfigurationTarget.USER, - TypeMoq.It.is(c => (c.value as IConnectionProfileStore[]).length === expectedNumberOfConnections)), TypeMoq.Times.atLeastOnce()); - calledValue.forEach(con => { - }); - }).then(() => done(), (err) => done(err)); - }); - - test('fixConnectionIds should replace duplicate ids with new ones', (done) => { - let profiles: IConnectionProfileStore[] = [ - { - options: {}, - groupId: '1', - id: '1', - providerName: undefined, - savePassword: true, - }, { - options: {}, - groupId: '1', - id: '2', - providerName: undefined, - savePassword: true, - }, { - options: {}, - groupId: '1', - id: '3', - providerName: undefined, - savePassword: true, - }, { - options: {}, - groupId: '1', - id: '2', - providerName: undefined, - savePassword: true, - }, { - options: {}, - groupId: '1', - id: '4', - providerName: undefined, - savePassword: true, - }, { - options: {}, - groupId: '1', - id: '3', - providerName: undefined, - savePassword: true, - }, { - options: {}, - groupId: '1', - id: '2', - providerName: undefined, - savePassword: true, - } - ]; - - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - config.fixConnectionIds(profiles); - let ids = profiles.map(x => x.id); - for (var index = 0; index < ids.length; index++) { - var id = ids[index]; - assert.equal(ids.lastIndexOf(id), index); - } - done(); - }); - - test('addConnection should not move the connection when editing', async () => { - // Set up the connection config - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionsArrayName)) - .returns(() => connections); - workspaceConfigurationServiceMock.setup(x => x.inspect( - Constants.connectionGroupsArrayName)) - .returns(() => configValueToConcat); - let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService.object); - - // Clone a connection and modify an option - const connectionIndex = 1; - const optionKey = 'testOption'; - const optionValue = 'testValue'; - let allConnections = config.getConnections(false); - let oldLength = allConnections.length; - let connectionToEdit = allConnections[connectionIndex].clone(); - connectionToEdit.options[optionKey] = optionValue; - await config.addConnection(connectionToEdit); - - // Get the connection and verify that it is in the same place and has been updated - let newConnections = config.getConnections(false); - assert.equal(newConnections.length, oldLength); - let editedConnection = newConnections[connectionIndex]; - assert.equal(editedConnection.getOptionsKey(), connectionToEdit.getOptionsKey()); - assert.equal(editedConnection.options[optionKey], optionValue); - }); - -}); diff --git a/src/sqltest/parts/connection/connectionStore.test.ts b/src/sqltest/parts/connection/connectionStore.test.ts index 1e5920b02b..a47048bde5 100644 --- a/src/sqltest/parts/connection/connectionStore.test.ts +++ b/src/sqltest/parts/connection/connectionStore.test.ts @@ -14,10 +14,8 @@ import { ConnectionStore } from 'sql/platform/connection/common/connectionStore' import { CredentialsService } from 'sql/platform/credentials/common/credentialsService'; import * as assert from 'assert'; import { Memento } from 'vs/workbench/common/memento'; -import { CapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; import * as azdata from 'azdata'; import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; -import { Emitter } from 'vs/base/common/event'; import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; import { ConnectionOptionSpecialType, ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes'; import { CapabilitiesTestService } from '../../stubs/capabilitiesTestService'; @@ -25,8 +23,6 @@ import { ConnectionProviderProperties } from 'sql/workbench/parts/connection/com suite('SQL ConnectionStore tests', () => { let defaultNamedProfile: IConnectionProfile; - let defaultUnnamedProfile: IConnectionProfile; - let profileForProvider2: IConnectionProfile; let context: TypeMoq.Mock; let credentialStore: TypeMoq.Mock; let connectionConfig: TypeMoq.Mock; @@ -58,42 +54,6 @@ suite('SQL ConnectionStore tests', () => { id: undefined }); - defaultUnnamedProfile = Object.assign({}, { - connectionName: 'new name', - serverName: 'unnamedServer', - databaseName: undefined, - authenticationType: 'SqlLogin', - userName: 'aUser', - password: 'asdf!@#$', - savePassword: true, - groupId: '', - groupFullName: '', - getOptionsKey: undefined, - matches: undefined, - providerName: 'MSSQL', - options: {}, - saveProfile: true, - id: undefined - }); - - profileForProvider2 = Object.assign({}, { - connectionName: 'new name', - serverName: 'unnamedServer', - databaseName: undefined, - authenticationType: 'SqlLogin', - userName: 'aUser', - password: 'asdf!@#$', - savePassword: true, - groupId: '', - groupFullName: '', - getOptionsKey: undefined, - matches: undefined, - providerName: 'MSSQL', - options: {}, - saveProfile: true, - id: undefined - }); - storageServiceMock = TypeMoq.Mock.ofType(StorageTestService); let momento = new Memento('ConnectionManagement', storageServiceMock.object); @@ -112,12 +72,6 @@ suite('SQL ConnectionStore tests', () => { workspaceConfigurationServiceMock.setup(x => x.getValue(Constants.sqlConfigSectionName)) .returns(() => configResult); - let extensionManagementServiceMock = { - getInstalled: () => { - return Promise.resolve([]); - } - }; - capabilitiesService = new CapabilitiesTestService(); let connectionProvider: azdata.ConnectionOption[] = [ { @@ -237,7 +191,7 @@ suite('SQL ConnectionStore tests', () => { // When saving 4 connections // Expect all of them to be saved even if size is limited to 3 - let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, + let connectionStore = new ConnectionStore(context.object, workspaceConfigurationServiceMock.object, credentialStore.object, capabilitiesService, connectionConfig.object); for (let i = 0; i < numCreds; i++) { let cred = Object.assign({}, defaultNamedProfile, { serverName: defaultNamedProfile.serverName + i }); @@ -264,7 +218,7 @@ suite('SQL ConnectionStore tests', () => { .returns(() => Promise.resolve(true)); const numCreds = 3; - let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, + let connectionStore = new ConnectionStore(context.object, workspaceConfigurationServiceMock.object, credentialStore.object, capabilitiesService, connectionConfig.object); connectionStore.clearActiveConnections(); connectionStore.clearRecentlyUsed(); @@ -283,7 +237,7 @@ suite('SQL ConnectionStore tests', () => { }); test('getRecentlyUsedConnections should return connection for given provider', () => { - let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, + let connectionStore = new ConnectionStore(context.object, workspaceConfigurationServiceMock.object, credentialStore.object, capabilitiesService, connectionConfig.object); let connections = connectionStore.getRecentlyUsedConnections(['Provider2']); assert.notEqual(connections, undefined); @@ -297,7 +251,7 @@ suite('SQL ConnectionStore tests', () => { // Given we save the same connection twice // Then expect the only 1 instance of that connection to be listed in the MRU - let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, + let connectionStore = new ConnectionStore(context.object, workspaceConfigurationServiceMock.object, credentialStore.object, capabilitiesService, connectionConfig.object); connectionStore.clearActiveConnections(); connectionStore.clearRecentlyUsed(); @@ -325,7 +279,8 @@ suite('SQL ConnectionStore tests', () => { }) .returns(() => Promise.resolve(true)); - let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, + // Given we save 1 connection with password and multiple other connections without + let connectionStore = new ConnectionStore(context.object, workspaceConfigurationServiceMock.object, credentialStore.object, capabilitiesService, connectionConfig.object); connectionStore.clearActiveConnections(); connectionStore.clearRecentlyUsed(); @@ -380,7 +335,7 @@ suite('SQL ConnectionStore tests', () => { test('can clear connections list', (done) => { connectionConfig.setup(x => x.getConnections(TypeMoq.It.isAny())).returns(() => []); - let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, + let connectionStore = new ConnectionStore(context.object, workspaceConfigurationServiceMock.object, credentialStore.object, capabilitiesService, connectionConfig.object); // When we clear the connections list and get the list of available connection items @@ -398,7 +353,7 @@ suite('SQL ConnectionStore tests', () => { test('isPasswordRequired should return true for MSSQL SqlLogin', () => { - let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, + let connectionStore = new ConnectionStore(context.object, workspaceConfigurationServiceMock.object, credentialStore.object, capabilitiesService, connectionConfig.object); let expected: boolean = true; @@ -408,7 +363,7 @@ suite('SQL ConnectionStore tests', () => { }); test('isPasswordRequired should return true for MSSQL SqlLogin for connection profile object', () => { - let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, + let connectionStore = new ConnectionStore(context.object, workspaceConfigurationServiceMock.object, credentialStore.object, capabilitiesService, connectionConfig.object); let connectionProfile = new ConnectionProfile(capabilitiesService, defaultNamedProfile); let expected: boolean = true; @@ -433,7 +388,7 @@ suite('SQL ConnectionStore tests', () => { capabilitiesService.capabilities[providerName] = { connection: providerCapabilities }; - let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, + let connectionStore = new ConnectionStore(context.object, workspaceConfigurationServiceMock.object, credentialStore.object, capabilitiesService, connectionConfig.object); let connectionProfile: IConnectionProfile = Object.assign({}, defaultNamedProfile, { providerName: providerName }); let expected: boolean = false; @@ -450,7 +405,7 @@ suite('SQL ConnectionStore tests', () => { connectionConfig.setup(x => x.addConnection(TypeMoq.It.isAny())).returns(() => Promise.resolve(savedConnection)); credentialStore.setup(x => x.saveCredential(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(true)); - let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, + let connectionStore = new ConnectionStore(context.object, workspaceConfigurationServiceMock.object, credentialStore.object, capabilitiesService, connectionConfig.object); connectionStore.saveProfile(connectionProfile).then(profile => { @@ -467,7 +422,7 @@ suite('SQL ConnectionStore tests', () => { }); test('addConnectionToMemento should not add duplicate items', () => { - let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, + let connectionStore = new ConnectionStore(context.object, workspaceConfigurationServiceMock.object, credentialStore.object, capabilitiesService, connectionConfig.object); let mementoKey = 'RECENT_CONNECTIONS2'; connectionStore.clearFromMemento(mementoKey); @@ -509,7 +464,7 @@ suite('SQL ConnectionStore tests', () => { }); test('getGroupFromId returns undefined when there is no group with the given ID', () => { - let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, + let connectionStore = new ConnectionStore(context.object, workspaceConfigurationServiceMock.object, credentialStore.object, capabilitiesService, connectionConfig.object); let group = connectionStore.getGroupFromId('invalidId'); assert.equal(group, undefined, 'Returned group was not undefined when there was no group with the given ID'); @@ -525,7 +480,7 @@ suite('SQL ConnectionStore tests', () => { groups.push(parentGroup, childGroup); let newConnectionConfig = TypeMoq.Mock.ofType(ConnectionConfig); newConnectionConfig.setup(x => x.getAllGroups()).returns(() => groups); - let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, + let connectionStore = new ConnectionStore(context.object, workspaceConfigurationServiceMock.object, credentialStore.object, capabilitiesService, newConnectionConfig.object); // If I look up the parent group using its ID, then I get back the correct group @@ -538,7 +493,7 @@ suite('SQL ConnectionStore tests', () => { }); test('getProfileWithoutPassword can return the profile without credentials in the password property or options dictionary', () => { - let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object, + let connectionStore = new ConnectionStore(context.object, workspaceConfigurationServiceMock.object, credentialStore.object, capabilitiesService, connectionConfig.object); let profile = Object.assign({}, defaultNamedProfile); profile.options['password'] = profile.password; @@ -550,4 +505,4 @@ suite('SQL ConnectionStore tests', () => { let profileWithoutCredentials = connectionStore.getProfileWithoutPassword(profile); assert.deepEqual(profileWithoutCredentials.toIConnectionProfile(), expectedProfile); }); -}); \ No newline at end of file +}); diff --git a/test/all.js b/test/all.js index eca3bdd612..4b0789ea28 100644 --- a/test/all.js +++ b/test/all.js @@ -102,7 +102,7 @@ function main() { if (argv.forceLoad) { // {{SQL CARBON EDIT}} - var allFiles = glob.sync(out + '/sqltest/**/*.js'); + var allFiles = glob.sync(out + '/(sqltest|sql)/**/*.js'); allFiles = allFiles.map(function (source) { return path.join(__dirname, '..', source); });