extensions tslint cleanup/Connection config refactor (#4370)

* various clean ups

* formatting

* remove linting

* formatting

* IConfigurationService is even better

* messing with connection config tests

* update tests

* formatting

* foramtting

* remove unused code

* add more tests
This commit is contained in:
Anthony Dresser
2019-03-20 11:59:07 -07:00
committed by GitHub
parent 6cb7153bdd
commit 4472764f3a
27 changed files with 1019 additions and 1319 deletions

View File

@@ -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;
}
}
}

View File

@@ -24,7 +24,7 @@ export class CreateClusterModel implements Scriptable {
}
public async changeKubernetesContext(targetContext: string): Promise<void> {
await setContext(this._kubectl, targetContext)
await setContext(this._kubectl, targetContext);
}
public getDefaultPorts(): Thenable<ClusterPorts> {

View File

@@ -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/**/*"
]
}

View File

@@ -6,4 +6,4 @@
"include": [
"src/**/*"
]
}
}

View File

@@ -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/**/*"
]
}

View File

@@ -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')
}
};

View File

@@ -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/**/*"
]
}

View File

@@ -58,4 +58,3 @@ export class JupyterNotebookProvider implements nb.NotebookProvider {
return [];
}
}

View File

@@ -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/**/*"
]
}

View File

@@ -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,

View File

@@ -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<IConnectionProfileGroup[]>(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<IConnectionProfile> {
return new Promise<IConnectionProfile>((resolve, reject) => {
if (profile.saveProfile) {
this.addGroupFromProfile(profile).then(groupId => {
let profiles = this._workspaceConfigurationService.inspect<IConnectionProfileStore[]>(Constants.connectionsArrayName).user;
if (!profiles) {
profiles = [];
}
if (profile.saveProfile) {
return this.addGroupFromProfile(profile).then(groupId => {
let profiles = this.configurationService.inspect<IConnectionProfileStore[]>(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<string> {
return new Promise<string>((resolve, reject) => {
if (profile.groupId && profile.groupId !== Utils.defaultGroupId) {
resolve(profile.groupId);
} else {
let groups = this._workspaceConfigurationService.inspect<IConnectionProfileGroup[]>(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<IConnectionProfileGroup[]>(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<string> {
return new Promise<string>((resolve, reject) => {
if (profileGroup.id) {
resolve(profileGroup.id);
if (profileGroup.id) {
return Promise.resolve(profileGroup.id);
} else {
let groups = this.configurationService.inspect<IConnectionProfileGroup[]>(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<IConnectionProfileGroup[]>(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<IConnectionProfileStore[]>(Constants.connectionsArrayName);
let profiles: IConnectionProfileStore[];
if (configs) {
if (configTarget === ConfigurationTarget.USER) {
profiles = <IConnectionProfileStore[]>configs.user;
profiles = configs.user;
} else if (configTarget === ConfigurationTarget.WORKSPACE) {
profiles = <IConnectionProfileStore[]>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<void> {
// Get all connections in the settings
let profiles = this._workspaceConfigurationService.inspect<IConnectionProfileStore[]>(Constants.connectionsArrayName).user;
let profiles = this.configurationService.inspect<IConnectionProfileStore[]>(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<IConnectionProfileStore[]>(Constants.connectionsArrayName).user;
let profiles = this.configurationService.inspect<IConnectionProfileStore[]>(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<IConnectionProfileGroup[]>(Constants.connectionGroupsArrayName).user;
let groups = this.configurationService.inspect<IConnectionProfileGroup[]>(Constants.connectionGroupsArrayName).user;
// Remove subgroups in the settings
groups = groups.filter((grp) => {
return !subgroups.some((item) => item.id === grp.id);
});
return new Promise<void>((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<void> {
let groups = this._workspaceConfigurationService.inspect<IConnectionProfileGroup[]>(Constants.connectionGroupsArrayName).user;
let groups = this.configurationService.inspect<IConnectionProfileGroup[]>(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<void> {
return new Promise<void>((resolve, reject) => {
let profiles = target === ConfigurationTarget.USER ? this._workspaceConfigurationService.inspect<IConnectionProfileStore[]>(Constants.connectionsArrayName).user :
this._workspaceConfigurationService.inspect<IConnectionProfileStore[]>(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<IConnectionProfileStore[]>(Constants.connectionsArrayName).user :
this.configurationService.inspect<IConnectionProfileStore[]>(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<void> {
return new Promise<void>((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<void> {
let groups = this._workspaceConfigurationService.inspect<IConnectionProfileGroup[]>(Constants.connectionGroupsArrayName).user;
let groups = this.configurationService.inspect<IConnectionProfileGroup[]>(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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(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<void> {
return new Promise<void>((resolve, reject) => {
let configValue: IConfigurationValue = {
key: key,
value: profiles
};
this._configurationEditService.writeConfiguration(target, configValue).then(result => {
this._workspaceConfigurationService.reloadConfiguration().then(() => {
resolve();
});
}, (error => {
reject(error);
}));
});
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -70,4 +70,4 @@ export class ConnectionManagementInfo {
* Owner uri assigned to the connection
*/
public ownerUri: string;
}
}

View File

@@ -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<azdata.DidChangeLanguageFlavorParams>();
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

View File

@@ -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';

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}

View File

@@ -34,4 +34,3 @@ export const passwordChars = '***************';
export const sqlLogin = 'SqlLogin';
export const integrated = 'Integrated';
export const azureMFA = 'AzureMFA';

View File

@@ -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.

View File

@@ -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;

View File

@@ -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<ICapabilitiesService>;
let msSQLCapabilities: ProviderFeatures;
let capabilities: ProviderFeatures[];
let onCapabilitiesRegistered = new Emitter<ProviderFeatures>();
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<IConnectionProfileStore[]>(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<IConnectionProfileStore[]>(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<IConnectionProfileStore[]>(Constants.connectionsArrayName).user.length, testConnections.length + 1);
assert.equal(configurationService.inspect<IConnectionProfileStore[]>(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<IConnectionProfileStore[]>(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<IConnectionProfileStore[]>(Constants.connectionsArrayName).user.length, testConnections.length - 1);
assert.equal(configurationService.inspect<IConnectionProfileGroup[]>(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<IConnectionProfileStore[]>(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<IConnectionProfileGroup[]>(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<IConnectionProfileGroup[]>(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<IConnectionProfileGroup[]>(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<IConnectionProfileStore[]>(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<IConnectionProfileStore[]>(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<IConnectionProfileGroup[]>(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<IConnectionProfileGroup[]>(Constants.connectionGroupsArrayName).user;
assert.equal(editGroups.length, testGroups.length);
}
});
});

View File

@@ -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<T>(): Promise<T> {
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<void> {
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<T>(key: string, overrides?: IConfigurationOverrides): {
default: T,
user: T,
workspace?: T,
workspaceFolder?: T
value: T,
} {
return {
value: getConfigurationValue<T>(this.configuration.user, key),
default: undefined,
user: getConfigurationValue<T>(this.configuration.user, key),
workspace: getConfigurationValue<T>(this.configuration.workspace, key),
workspaceFolder: undefined
};
}
public keys() {
return {
default: getConfigurationKeys(),
user: Object.keys(this.configuration),
workspace: [],
workspaceFolder: []
};
}
public getConfigurationData() {
return null;
}
}

View File

@@ -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<ICapabilitiesService>;
let workspaceConfigurationServiceMock: TypeMoq.Mock<WorkspaceConfigurationTestService>;
let configEditingServiceMock: TypeMoq.Mock<ConfigurationEditingService>;
let msSQLCapabilities: ProviderFeatures;
let capabilities: ProviderFeatures[];
let onCapabilitiesRegistered = new Emitter<ProviderFeatures>();
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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
Constants.connectionsArrayName))
.returns(() => connections);
workspaceConfigurationServiceMock.setup(x => x.inspect<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
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<IConfigurationValue>(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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
Constants.connectionsArrayName))
.returns(() => connections);
workspaceConfigurationServiceMock.setup(x => x.inspect<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
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<IConfigurationValue>(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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
Constants.connectionsArrayName))
.returns(() => connections);
workspaceConfigurationServiceMock.setup(x => x.inspect<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
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<IConfigurationValue>(c => (c.value as IConnectionProfileStore[]).length === expectedNumberOfConnections)), TypeMoq.Times.once());
configEditingServiceMock.verify(y => y.writeConfiguration(ConfigurationTarget.USER,
TypeMoq.It.is<IConfigurationValue>(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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
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<ICapabilitiesService> = TypeMoq.Mock.ofType(CapabilitiesTestService);
capabilitiesService2.setup(x => x.getCapabilities('MSSQL')).returns(() => msSQLCapabilities2);
(capabilitiesService2.object as any).onCapabilitiesRegistered = onCapabilitiesRegistered.event;
workspaceConfigurationServiceMock.setup(x => x.inspect<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
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<IConfigurationValue>(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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
Constants.connectionsArrayName))
.returns(() => connections);
workspaceConfigurationServiceMock.setup(x => x.inspect<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
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<IConfigurationValue>(c => (c.value as IConnectionProfileStore[]).length === expectedNumberOfConnections)), TypeMoq.Times.once());
configEditingServiceMock.verify(y => y.writeConfiguration(ConfigurationTarget.USER,
TypeMoq.It.is<IConfigurationValue>(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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
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<IConfigurationValue>(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<ConfigurationEditingService> = 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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
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<IConfigurationValue>(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<ConfigurationEditingService> = 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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
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<IConfigurationValue>(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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
Constants.connectionsArrayName))
.returns(() => connections);
let connectionProfile = new ConnectionProfile(capabilitiesService.object, newProfile);
let newId = 'newid';
let calledValue: any;
let nothing: void;
let configEditingServiceMock: TypeMoq.Mock<ConfigurationEditingService> = 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<IConfigurationValue>(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<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
Constants.connectionsArrayName))
.returns(() => connections);
workspaceConfigurationServiceMock.setup(x => x.inspect<IConnectionProfileStore[] | IConnectionProfileGroup[] | azdata.DataProtocolServerCapabilities[]>(
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);
});
});

View File

@@ -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<Memento>;
let credentialStore: TypeMoq.Mock<CredentialsService>;
let connectionConfig: TypeMoq.Mock<ConnectionConfig>;
@@ -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);
});
});
});

View File

@@ -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);
});