From e01723f1958f1ac9dec5fd63125405595a8301b3 Mon Sep 17 00:00:00 2001 From: Alex Ma Date: Mon, 22 Jun 2020 13:51:39 -0700 Subject: [PATCH] Additional tests for connection (#10944) * Added providerRegistered test * test for EditConnectionDialog * changed wording * added test for connectionInfo * utils.ts tests added * hasRegisteredServers test * commented out editconnection tests, addl. tests * added onConnectionChangedNotification test * added changeGroupId tests * Added connection profile changes * added connectIfNotConnected test * added delete connection test * isRecent and disconnect editor tests * added registerIconProvider test * Fix for ensureDefaultLanguageFlavor test * added a few tests * utils prefix test updated * added utils tests --- .../test/common/connectionStore.test.ts | 10 + .../objectExplorer/test/browser/utils.test.ts | 66 +++ .../browser/connectionManagementService.ts | 2 +- .../connectionManagementService.test.ts | 431 +++++++++++++++++- 4 files changed, 495 insertions(+), 14 deletions(-) create mode 100644 src/sql/workbench/contrib/objectExplorer/test/browser/utils.test.ts diff --git a/src/sql/platform/connection/test/common/connectionStore.test.ts b/src/sql/platform/connection/test/common/connectionStore.test.ts index 1c83b11a71..77477cbcbb 100644 --- a/src/sql/platform/connection/test/common/connectionStore.test.ts +++ b/src/sql/platform/connection/test/common/connectionStore.test.ts @@ -8,6 +8,7 @@ import * as azdata from 'azdata'; import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; import { IConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; import { ConnectionStore } from 'sql/platform/connection/common/connectionStore'; +import { fixupConnectionCredentials } from 'sql/platform/connection/common/connectionInfo'; import { IConnectionProfile, ConnectionOptionSpecialType, ServiceOptionType } from 'sql/platform/connection/common/interfaces'; import { TestConfigurationService } from 'sql/platform/connection/test/common/testConfigurationService'; import { TestCredentialsService } from 'sql/platform/credentials/test/common/testCredentialsService'; @@ -251,6 +252,15 @@ suite('ConnectionStore', () => { assert.equal(credentialsService.credentials.size, 1); }); + test('fixupConnectionCredentials should fix blank connection profile', () => { + let blankConnectionProfile = new ConnectionProfile(capabilitiesService, ''); + let resultProfile = fixupConnectionCredentials(blankConnectionProfile); + assert.equal(resultProfile.serverName, ''); + assert.equal(resultProfile.databaseName, ''); + assert.equal(resultProfile.userName, ''); + assert.equal(resultProfile.password, ''); + }); + test('can clear connections list', async () => { const storageService = new InMemoryStorageService(); const configurationService = new TestConfigurationService(); diff --git a/src/sql/workbench/contrib/objectExplorer/test/browser/utils.test.ts b/src/sql/workbench/contrib/objectExplorer/test/browser/utils.test.ts new file mode 100644 index 0000000000..aacb316eb4 --- /dev/null +++ b/src/sql/workbench/contrib/objectExplorer/test/browser/utils.test.ts @@ -0,0 +1,66 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; +import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; +import { TestCapabilitiesService } from 'sql/platform/capabilities/test/common/testCapabilitiesService'; +import { mssqlProviderName } from 'sql/platform/connection/common/constants'; +import * as ConnectionUtils from 'sql/platform/connection/common/utils'; + +suite('Connection Utilities tests', () => { + let capabilitiesService = new TestCapabilitiesService(); + let connection = new ConnectionProfile(capabilitiesService, { + connectionName: 'Test', + savePassword: false, + groupFullName: 'testGroup', + serverName: 'testServerName', + databaseName: 'master', + authenticationType: 'inetgrated', + password: 'test', + userName: 'testUsername', + groupId: undefined, + providerName: mssqlProviderName, + options: {}, + saveProfile: true, + id: 'testID' + }); + + test('findProfileInGroup - test if utils can find profile in group', () => { + let conProfGroup = new ConnectionProfileGroup('testGroup', undefined, 'testGroup', undefined, undefined); + let conProfGroupChild = new ConnectionProfileGroup('testGroupChild', conProfGroup, 'testGroupChild', undefined, undefined); + conProfGroup.addGroups([conProfGroupChild]); + conProfGroupChild.addConnections([connection]); + assert.equal(connection, ConnectionUtils.findProfileInGroup(connection, [conProfGroup])); + }); + + test('getUriPrefix - test if getUriPrefix finds the correct prefix from fake uri name', () => { + let testUri = 'test://testpath'; + assert.equal('test://', ConnectionUtils.getUriPrefix(testUri)); + let badTestUri = '://>test#% { + assert(ConnectionUtils.isMaster(connection)); + }); + + test('parseTimeString - test if time is parsed correctly', () => { + //Should return false if undefined. + assert(!ConnectionUtils.parseTimeString(undefined)); + + let emptyTime = '.'; + //Should return false if there are not 1-2 string parts split by period. + assert(!ConnectionUtils.parseTimeString(emptyTime)); + + let testTime = '28:06:42.12'; + let testTimeInMS = 101202012; + //should properly return the time in milliseconds. + assert.equal(testTimeInMS, ConnectionUtils.parseTimeString(testTime)); + }); +}); diff --git a/src/sql/workbench/services/connection/browser/connectionManagementService.ts b/src/sql/workbench/services/connection/browser/connectionManagementService.ts index dc924f0573..372203e19f 100644 --- a/src/sql/workbench/services/connection/browser/connectionManagementService.ts +++ b/src/sql/workbench/services/connection/browser/connectionManagementService.ts @@ -769,7 +769,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti * @param uri document identifier */ public ensureDefaultLanguageFlavor(uri: string): void { - if (!this.getProviderIdFromUri(uri)) { + if (this.getProviderIdFromUri(uri) === '') { // Lookup the default settings and use this let defaultProvider = this.getDefaultProviderId(); if (defaultProvider) { diff --git a/src/sql/workbench/services/connection/test/browser/connectionManagementService.test.ts b/src/sql/workbench/services/connection/test/browser/connectionManagementService.test.ts index 06e646e759..5e99000077 100644 --- a/src/sql/workbench/services/connection/test/browser/connectionManagementService.test.ts +++ b/src/sql/workbench/services/connection/test/browser/connectionManagementService.test.ts @@ -9,7 +9,7 @@ import { ConnectionStatusManager } from 'sql/platform/connection/common/connecti import { ConnectionStore } from 'sql/platform/connection/common/connectionStore'; import { INewConnectionParams, ConnectionType, - IConnectionCompletionOptions, IConnectionResult, + IConnectionCompletionOptions, IConnectionResult, IConnectionParams, RunQueryOnConnectionMode } from 'sql/platform/connection/common/connectionManagement'; import * as Constants from 'sql/platform/connection/common/constants'; @@ -102,7 +102,7 @@ suite('SQL ConnectionManagementService tests', () => { connectionDialogService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(none)); connectionStore.setup(x => x.addRecentConnection(TypeMoq.It.isAny())).returns(() => Promise.resolve()); - connectionStore.setup(x => x.saveProfile(TypeMoq.It.isAny(), TypeMoq.It.is(x => true), TypeMoq.It.is(x => true))).returns(() => Promise.resolve(connectionProfile)); + connectionStore.setup(x => x.saveProfile(TypeMoq.It.is(profile => true), TypeMoq.It.is(x => true), TypeMoq.It.is(x => true))).returns(profile => Promise.resolve(profile)); workbenchEditorService.setup(x => x.openEditor(undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(undefined)); connectionStore.setup(x => x.addSavedPassword(TypeMoq.It.is( c => c.serverName === connectionProfile.serverName))).returns(() => Promise.resolve({ profile: connectionProfile, savedCred: true })); @@ -204,7 +204,7 @@ suite('SQL ConnectionManagementService tests', () => { if (options) { if (options.saveTheConnection) { - connectionStore.verify(x => x.saveProfile(TypeMoq.It.isAny(), TypeMoq.It.is(x => true), TypeMoq.It.is(x => true)), TypeMoq.Times.once()); + connectionStore.verify(x => x.saveProfile(TypeMoq.It.is(profile => true), TypeMoq.It.is(x => true), TypeMoq.It.is(x => true)), TypeMoq.Times.once()); } if (options.showDashboard) { workbenchEditorService.verify(x => x.openEditor(undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once()); @@ -217,7 +217,7 @@ suite('SQL ConnectionManagementService tests', () => { } - async function connect(uri: string, options?: IConnectionCompletionOptions, fromDialog?: boolean, connection?: IConnectionProfile, error?: string, errorCode?: number, errorCallStack?: string): Promise { + async function connect(uri: string, options?: IConnectionCompletionOptions, fromDialog?: boolean, connection?: IConnectionProfile, error?: string, errorCode?: number, errorCallStack?: string, serverInfo?: azdata.ServerInfo): Promise { let connectionToUse = connection ? connection : connectionProfile; let id = connectionToUse.getOptionsKey(); let defaultUri = 'connection:' + (id ? id : connectionToUse.serverName + ':' + connectionToUse.databaseName); @@ -233,7 +233,7 @@ suite('SQL ConnectionManagementService tests', () => { errorNumber: errorCode, messages: errorCallStack, ownerUri: uri ? uri : defaultUri, - serverInfo: undefined + serverInfo: serverInfo }; connectionManagementService.onConnectionComplete(0, info); }); @@ -294,6 +294,12 @@ suite('SQL ConnectionManagementService tests', () => { }); }); + test('showConnectionDialog should not be called when using showEditConnectionDialog', () => { + return connectionManagementService.showEditConnectionDialog(connectionProfile).then(() => { + verifyShowConnectionDialog(connectionProfile, ConnectionType.default, undefined, false, undefined, false); + }); + }); + test('connect should save profile given options with saveProfile set to true', () => { let uri: string = 'Editor Uri'; let options: IConnectionCompletionOptions = { @@ -441,8 +447,202 @@ suite('SQL ConnectionManagementService tests', () => { }); }); + test('Accessors for event emitters should return emitter function', () => { + let onAddConnectionProfile1 = connectionManagementService.onAddConnectionProfile; + assert.equal(typeof (onAddConnectionProfile1), 'function'); + let onDeleteConnectionProfile1 = connectionManagementService.onDeleteConnectionProfile; + assert.equal(typeof (onDeleteConnectionProfile1), 'function'); + let onConnect1 = connectionManagementService.onConnect; + assert.equal(typeof (onConnect1), 'function'); + }); + + test('onConnectionChangedNotification should call onConnectionChanged event', () => { + let uri = 'Test Uri'; + let options: IConnectionCompletionOptions = { + params: undefined, + saveTheConnection: true, + showDashboard: false, + showConnectionDialogOnError: false, + showFirewallRuleOnError: true + }; + + return connect(uri, options).then(result => { + let saveConnection = connectionManagementService.getConnectionProfile(uri); + let changedConnectionInfo: azdata.ChangedConnectionInfo = { connectionUri: uri, connection: saveConnection }; + let called = false; + connectionManagementService.onConnectionChanged((params: IConnectionParams) => { + assert.equal(uri, params.connectionUri); + assert.equal(saveConnection, params.connectionProfile); + called = true; + }); + connectionManagementService.onConnectionChangedNotification(0, changedConnectionInfo); + assert.ok(called, 'expected onConnectionChanged event to be sent'); + }); + }); + + test('changeGroupIdForconnection should change the groupId for a connection profile', () => { + let profile = assign({}, connectionProfile); + profile.options = { password: profile.password }; + profile.id = 'test_id'; + let newGroupId = 'new_group_id'; + connectionStore.setup(x => x.changeGroupIdForConnection(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve()); + connectionManagementService.changeGroupIdForConnection(profile, newGroupId).then(() => { + assert.equal(profile.groupId, newGroupId); + }); + }); + + test('changeGroupIdForConnectionGroup should call changeGroupIdForConnectionGroup in ConnectionStore', () => { + let sourceProfileGroup = createConnectionGroup('original_id'); + let targetProfileGroup = createConnectionGroup('new_id'); + let called = false; + connectionStore.setup(x => x.changeGroupIdForConnectionGroup(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => { + called = true; + return Promise.resolve(); + }); + connectionManagementService.changeGroupIdForConnectionGroup(sourceProfileGroup, targetProfileGroup).then(() => { + assert.ok(called, 'expected changeGroupIdForConnectionGroup to be called on ConnectionStore'); + }); + }); + + test('findExistingConnection should find connection for connectionProfile with same info', () => { + let profile = assign({}, connectionProfile); + let uri1 = 'connection:connectionId'; + let options: IConnectionCompletionOptions = { + params: { + connectionType: ConnectionType.editor, + input: { + onConnectSuccess: undefined, + onConnectReject: undefined, + onConnectStart: undefined, + onDisconnect: undefined, + onConnectCanceled: undefined, + uri: uri1, + }, + queryRange: undefined, + runQueryOnCompletion: RunQueryOnConnectionMode.none, + isEditConnection: false + }, + saveTheConnection: true, + showDashboard: false, + showConnectionDialogOnError: true, + showFirewallRuleOnError: true + }; + let connectionInfoString = 'providerName:' + profile.providerName + '|authenticationType:' + + profile.authenticationType + '|databaseName:' + profile.databaseName + '|serverName:' + + profile.serverName + '|userName:' + profile.userName; + return connect(uri1, options, true, profile).then(() => { + let returnedProfile = connectionManagementService.findExistingConnection(profile); + assert.equal(returnedProfile.getConnectionInfoId(), connectionInfoString); + }); + }); + + test('deleteConnection should delete the connection properly', () => { + let profile = assign({}, connectionProfile); + let uri1 = 'connection:connectionId'; + let options: IConnectionCompletionOptions = { + params: { + connectionType: ConnectionType.editor, + input: { + onConnectSuccess: undefined, + onConnectReject: undefined, + onConnectStart: undefined, + onDisconnect: undefined, + onConnectCanceled: undefined, + uri: uri1, + }, + queryRange: undefined, + runQueryOnCompletion: RunQueryOnConnectionMode.none, + isEditConnection: false + }, + saveTheConnection: true, + showDashboard: false, + showConnectionDialogOnError: true, + showFirewallRuleOnError: true + }; + + connectionStore.setup(x => x.deleteConnectionFromConfiguration(TypeMoq.It.isAny())).returns(() => Promise.resolve()); + return connect(uri1, options, true, profile).then(() => { + assert(connectionManagementService.deleteConnection(profile)); + }); + }); + + test('deleteConnectionGroup should delete connections in connection group', () => { + let profile = assign({}, connectionProfile); + let profileGroup = createConnectionGroup('original_id'); + profileGroup.addConnections([profile]); + let uri1 = 'connection:connectionId'; + let options: IConnectionCompletionOptions = { + params: { + connectionType: ConnectionType.editor, + input: { + onConnectSuccess: undefined, + onConnectReject: undefined, + onConnectStart: undefined, + onDisconnect: undefined, + onConnectCanceled: undefined, + uri: uri1, + }, + queryRange: undefined, + runQueryOnCompletion: RunQueryOnConnectionMode.none, + isEditConnection: false + }, + saveTheConnection: true, + showDashboard: false, + showConnectionDialogOnError: true, + showFirewallRuleOnError: true + }; + + connectionStore.setup(x => x.deleteGroupFromConfiguration(TypeMoq.It.isAny())).returns(() => Promise.resolve()); + return connect(uri1, options, true, profile).then(() => { + return connectionManagementService.deleteConnectionGroup(profileGroup).then(result => { + assert(result); + }); + }); + }); + + test('canChangeConnectionConfig returns true when connection can be moved to another group', () => { + connectionStore.setup(x => x.canChangeConnectionConfig(TypeMoq.It.isAny(), TypeMoq.It.isAnyString())).returns(() => { + return true; + }); + let profile = assign({}, connectionProfile); + let newGroupId = 'test_group_id'; + assert(connectionManagementService.canChangeConnectionConfig(profile, newGroupId)); + }); + + test('connectIfNotConnected should not try to connect with already connected profile', () => { + let profile = assign({}, connectionProfile); + let uri1 = 'connection:connectionId'; //must use default connection uri for test to work. + let options: IConnectionCompletionOptions = { + params: { + connectionType: ConnectionType.editor, + input: { + onConnectSuccess: undefined, + onConnectReject: undefined, + onConnectStart: undefined, + onDisconnect: undefined, + onConnectCanceled: undefined, + uri: uri1, + }, + queryRange: undefined, + runQueryOnCompletion: RunQueryOnConnectionMode.none, + isEditConnection: false + }, + saveTheConnection: true, + showDashboard: false, + showConnectionDialogOnError: true, + showFirewallRuleOnError: true + }; + + return connect(uri1, options, true, profile).then(result => { + assert.equal(result.connected, true); + return connectionManagementService.connectIfNotConnected(profile, undefined, true).then(result => { + assert.equal(result, uri1); + }); + }); + }); + test('Edit Connection - Changing connection profile name for same URI should persist after edit', () => { - let profile = connectionProfile; + let profile = assign({}, connectionProfile); let uri1 = 'test_uri1'; let newname = 'connection renamed'; let options: IConnectionCompletionOptions = { @@ -468,10 +668,10 @@ suite('SQL ConnectionManagementService tests', () => { return connect(uri1, options, true, profile).then(result => { assert.equal(result.connected, true); - let newProfile = connectionProfile; + let newProfile = assign({}, connectionProfile); newProfile.connectionName = newname; options.params.isEditConnection = true; - return connect(uri1, options, true, profile).then(result => { + return connect(uri1, options, true, newProfile).then(result => { assert.equal(result.connected, true); assert.equal(connectionManagementService.getConnectionProfile(uri1).connectionName, newname); }); @@ -479,10 +679,10 @@ suite('SQL ConnectionManagementService tests', () => { }); test('Edit Connection - Connecting a different URI with same profile via edit should not change profile ID.', () => { - let profile = connectionProfile; - profile.id = '0451'; let uri1 = 'test_uri1'; let uri2 = 'test_uri2'; + let profile = assign({}, connectionProfile); + profile.id = '0451'; let options: IConnectionCompletionOptions = { params: { connectionType: ConnectionType.editor, @@ -575,6 +775,47 @@ suite('SQL ConnectionManagementService tests', () => { }); }); + test('hasRegisteredServers should return true as there is one registered server', () => { + assert(connectionManagementService.hasRegisteredServers()); + }); + + + test('getAdvancedProperties should return a list of properties for connectionManagementService', () => { + let propertyNames = ['connectionName', 'serverName', 'databaseName', 'userName', 'authenticationType', 'password']; + let advancedProperties = connectionManagementService.getAdvancedProperties(); + assert.equal(propertyNames[0], advancedProperties[0].name); + assert.equal(propertyNames[1], advancedProperties[1].name); + assert.equal(propertyNames[2], advancedProperties[2].name); + assert.equal(propertyNames[3], advancedProperties[3].name); + assert.equal(propertyNames[4], advancedProperties[4].name); + assert.equal(propertyNames[5], advancedProperties[5].name); + }); + + test('saveProfileGroup should return groupId from connection group', () => { + let newConnectionGroup = createConnectionGroup(connectionProfile.groupId); + connectionStore.setup(x => x.saveProfileGroup(TypeMoq.It.isAny())).returns(() => Promise.resolve(connectionProfile.groupId)); + connectionManagementService.saveProfileGroup(newConnectionGroup).then(result => { + assert.equal(result, connectionProfile.groupId); + }); + }); + + test('editGroup should fire onAddConnectionProfile', () => { + let newConnectionGroup = createConnectionGroup(connectionProfile.groupId); + let called = false; + connectionStore.setup(x => x.editGroup(TypeMoq.It.isAny())).returns(() => Promise.resolve()); + connectionManagementService.onAddConnectionProfile(() => { + called = true; + }); + return connectionManagementService.editGroup(newConnectionGroup).then(() => { + assert(called); + }); + }); + + test('getFormattedUri should return formatted uri when given default type uri', () => { + let testUri = 'connection:'; + assert.equal('connection:connectionId', connectionManagementService.getFormattedUri(testUri, connectionProfile)); + }); + test('failed firewall rule connection and failed during open firewall rule should open the firewall rule dialog and connection dialog with error', () => { handleFirewallRuleResult.canHandleFirewallRule = true; resolveHandleFirewallRuleDialog = true; @@ -728,6 +969,94 @@ suite('SQL ConnectionManagementService tests', () => { }); }); + test('disconnect editor should disconnect uri from connection', () => { + let uri = 'editor to remove'; + let options: IConnectionCompletionOptions = { + params: { + connectionType: ConnectionType.editor, + input: { + onConnectSuccess: undefined, + onConnectReject: undefined, + onConnectStart: undefined, + onDisconnect: () => { }, + onConnectCanceled: undefined, + uri: uri + }, + queryRange: undefined, + runQueryOnCompletion: RunQueryOnConnectionMode.none + }, + saveTheConnection: true, + showDashboard: false, + showConnectionDialogOnError: true, + showFirewallRuleOnError: true + }; + + return connect(uri, options, false, connectionProfileWithEmptySavedPassword).then(() => { + return connectionManagementService.disconnectEditor(options.params.input).then(result => { + assert(result); + }); + }); + }); + + test('registerIconProvider should register icon provider for connectionManagementService', () => { + let profile = assign({}, connectionProfile); + let serverInfo: azdata.ServerInfo = { + serverMajorVersion: 0, + serverMinorVersion: 0, + serverReleaseVersion: 0, + engineEditionId: 0, + serverVersion: 'test_version', + serverLevel: 'test_level', + serverEdition: 'test_edition', + azureVersion: 0, + osVersion: 'test_version', + options: { isBigDataCluster: 'test' }, + isCloud: true + }; + let uri: string = 'Editor Uri'; + let options: IConnectionCompletionOptions = { + params: { + connectionType: ConnectionType.editor, + input: { + onConnectSuccess: undefined, + onConnectReject: undefined, + onConnectStart: undefined, + onDisconnect: undefined, + onConnectCanceled: undefined, + uri: uri + }, + queryRange: undefined, + runQueryOnCompletion: RunQueryOnConnectionMode.none + }, + saveTheConnection: true, + showDashboard: false, + showConnectionDialogOnError: true, + showFirewallRuleOnError: true + }; + + let called = false; + let mockIconProvider: azdata.IconProvider = { + providerId: Constants.mssqlProviderName, + handle: 0, + getConnectionIconId(connection: azdata.IConnectionProfile, serverInfo: azdata.ServerInfo): Thenable { + let iconName: string = undefined; + if (connection.providerName === 'MSSQL') { + if (serverInfo.isCloud) { + iconName = 'mssql:cloud'; + } else if (serverInfo.options['isBigDataCluster']) { + iconName = 'mssql:cluster'; + } + } + called = true; + return Promise.resolve(iconName); + } + }; + connectionManagementService.registerIconProvider('MSSQL', mockIconProvider); + return connect(uri, options, true, profile, undefined, undefined, undefined, serverInfo).then(() => { + assert(called); + }); + }); + test('doChangeLanguageFlavor should throw on unknown provider', () => { // given a provider that will never exist let invalidProvider = 'notaprovider'; @@ -753,6 +1082,7 @@ suite('SQL ConnectionManagementService tests', () => { assert.ok(called, 'expected onLanguageFlavorChanged event to be sent'); }); + test('getUniqueConnectionProvidersByNameMap should return non CMS providers', () => { let nameToDisplayNameMap: { [providerDisplayName: string]: string } = { 'MSSQL': 'SQL Server', 'MSSQL-CMS': 'SQL Server' }; let providerNames = Object.keys(connectionManagementService.getUniqueConnectionProvidersByNameMap(nameToDisplayNameMap)); @@ -768,21 +1098,21 @@ suite('SQL ConnectionManagementService tests', () => { assert.equal(providerNames[1], expectedNames[1]); }); - test.skip('ensureDefaultLanguageFlavor should not send event if uri is connected', () => { // {{SQL CARBON EDIT}} this test is broken regardless of my changes + test('ensureDefaultLanguageFlavor should not send event if uri is connected', () => { let uri: string = 'Editor Uri'; let options: IConnectionCompletionOptions = { params: undefined, - saveTheConnection: false, + saveTheConnection: true, showDashboard: false, showConnectionDialogOnError: false, showFirewallRuleOnError: true }; - let connectionManagementService = createConnectionManagementService(); let called = false; connectionManagementService.onLanguageFlavorChanged((changeParams: azdata.DidChangeLanguageFlavorParams) => { called = true; }); return connect(uri, options).then(() => { + called = false; //onLanguageFlavorChanged is called when connecting, must set back to false. connectionManagementService.ensureDefaultLanguageFlavor(uri); assert.equal(called, false, 'do not expect flavor change to be called'); }); @@ -810,6 +1140,45 @@ suite('SQL ConnectionManagementService tests', () => { }); }); + test('list and change database tests', () => { + // Set up the connection management service with a connection corresponding to a default database + let dbName = 'master'; + let newDbName = 'renamed_master'; + let serverName = 'test_server'; + let userName = 'test_user'; + let connectionProfileWithoutDb: IConnectionProfile = assign(connectionProfile, + { serverName: serverName, databaseName: '', userName: userName, getOptionsKey: () => undefined }); + let connectionProfileWithDb: IConnectionProfile = assign(connectionProfileWithoutDb, { databaseName: dbName }); + // Save the database with a URI that has the database name filled in, to mirror Carbon's behavior + let ownerUri = Utils.generateUri(connectionProfileWithDb); + let listDatabasesThenable = (connectionUri: string) => { + let databaseResult: azdata.ListDatabasesResult = { databaseNames: [] }; + if (connectionUri === ownerUri) { + databaseResult = { databaseNames: [dbName] }; + } + return Promise.resolve(databaseResult); + }; + let changeDatabasesThenable = (connectionUri: string, newDatabase: string) => { + let result = false; + if ((connectionUri === ownerUri) && (newDatabase === newDbName)) { + result = true; + } + return Promise.resolve(result); + }; + mssqlConnectionProvider.setup(x => x.listDatabases(ownerUri)).returns(() => listDatabasesThenable(ownerUri)); + mssqlConnectionProvider.setup(x => x.changeDatabase(ownerUri, newDbName)).returns(() => changeDatabasesThenable(ownerUri, newDbName)); + return connect(ownerUri, undefined, false, connectionProfileWithoutDb).then(() => { + return connectionManagementService.listDatabases(ownerUri).then(result => { + assert.equal(result.databaseNames.length, 1); + assert.equal(result.databaseNames[0], dbName); + return connectionManagementService.changeDatabase(ownerUri, newDbName).then(result => { + assert(result); + assert.equal(newDbName, connectionManagementService.getConnectionProfile(ownerUri).databaseName); + }); + }); + }); + }); + test('getTabColorForUri returns undefined when there is no connection for the given URI', () => { let connectionManagementService = createConnectionManagementService(); let color = connectionManagementService.getTabColorForUri('invalidUri'); @@ -855,6 +1224,10 @@ suite('SQL ConnectionManagementService tests', () => { assert.equal(foundUri, uri); }); + test('provider is registered and working', () => { + assert.equal(connectionManagementService.providerRegistered('MSSQL'), true); + }); + test('getConectionUriFromId returns undefined if the given connection is not active', () => { let profile = assign({}, connectionProfile); profile.options = { password: profile.password }; @@ -1023,6 +1396,38 @@ suite('SQL ConnectionManagementService tests', () => { }); }); +test('isRecent should evaluate whether a profile was recently connected or not', () => { + const connectionStatusManagerMock = TypeMoq.Mock.ofType(ConnectionStatusManager, TypeMoq.MockBehavior.Loose); + const connectionStoreMock = TypeMoq.Mock.ofType(ConnectionStore, TypeMoq.MockBehavior.Loose, new TestStorageService()); + connectionStoreMock.setup(x => x.getRecentlyUsedConnections()).returns(() => { + return [createConnectionProfile('1')]; + }); + let profile1 = createConnectionProfile('1'); + let profile2 = createConnectionProfile('2'); + const connectionManagementService = new ConnectionManagementService(connectionStoreMock.object, connectionStatusManagerMock.object, undefined, undefined, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, getBasicExtensionService()); + assert(connectionManagementService.isRecent(profile1)); + assert(!connectionManagementService.isRecent(profile2)); +}); + +test('clearRecentConnection and ConnectionsList should call connectionStore functions', () => { + const connectionStatusManagerMock = TypeMoq.Mock.ofType(ConnectionStatusManager, TypeMoq.MockBehavior.Loose); + const connectionStoreMock = TypeMoq.Mock.ofType(ConnectionStore, TypeMoq.MockBehavior.Loose, new TestStorageService()); + let called = false; + connectionStoreMock.setup(x => x.clearRecentlyUsed()).returns(() => { + called = true; + }); + connectionStoreMock.setup(x => x.removeRecentConnection(TypeMoq.It.isAny())).returns(() => { + called = true; + }); + let profile1 = createConnectionProfile('1'); + const connectionManagementService = new ConnectionManagementService(connectionStoreMock.object, connectionStatusManagerMock.object, undefined, undefined, undefined, undefined, undefined, new TestCapabilitiesService(), undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined, getBasicExtensionService()); + connectionManagementService.clearRecentConnection(profile1); + assert(called); + called = false; + connectionManagementService.clearRecentConnectionsList(); + assert(called); +}); + function createConnectionProfile(id: string): ConnectionProfile { const capabilitiesService = new TestCapabilitiesService();