SQL Operations Studio Public Preview 1 (0.23) release source code

This commit is contained in:
Karl Burtram
2017-11-09 14:30:27 -08:00
parent b88ecb8d93
commit 3cdac41339
8829 changed files with 759707 additions and 286 deletions

View File

@@ -0,0 +1,103 @@
/*---------------------------------------------------------------------------------------------
* 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 TelemetryUtils from 'sql/common/telemetryUtilities';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { TelemetryServiceStub } from 'sqltest/stubs/telemetryServiceStub';
import * as TypeMoq from 'typemoq';
import { TPromise } from 'vs/base/common/winjs.base';
import * as assert from 'assert';
suite('SQL Telemetry Utilities tests', () => {
let telemetryService: TypeMoq.Mock<ITelemetryService>;
let none: void;
let providerName: string = 'provider name';
let telemetryKey: string = 'tel key';
let connectionProfile = {
databaseName: '',
serverName: '',
authenticationType: '',
getOptionsKey: () => '',
matches: undefined,
groupFullName: '',
groupId: '',
id: '',
options: {},
password: '',
providerName: providerName,
savePassword: true,
saveProfile: true,
userName: ''
};
setup(() => {
telemetryService = TypeMoq.Mock.ofType(TelemetryServiceStub, TypeMoq.MockBehavior.Strict);
telemetryService.setup(x => x.publicLog(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(x => TPromise.as(none));
});
test('addTelemetry should add provider id using the connection', (done) => {
let data: TelemetryUtils.IConnectionTelemetryData = {
};
TelemetryUtils.addTelemetry(telemetryService.object, telemetryKey, data, connectionProfile).then(() => {
telemetryService.verify(x => x.publicLog(TypeMoq.It.is(a => a === telemetryKey), TypeMoq.It.is(b => b.provider === providerName)), TypeMoq.Times.once());
done();
}).catch(err => {
assert.fail(err);
done(err);
});
});
test('addTelemetry should pass the telemetry data to telemetry service', (done) => {
let data: TelemetryUtils.IConnectionTelemetryData = {
target: 'target',
from: 'from'
};
data.test1 = '1';
TelemetryUtils.addTelemetry(telemetryService.object, telemetryKey, data, connectionProfile).then(() => {
telemetryService.verify(x => x.publicLog(
TypeMoq.It.is(a => a === telemetryKey),
TypeMoq.It.is(b => b.provider === providerName
&& b.from === data.from
&& b.target === data.target
&& b.test1 === data.test1
&& b.connection === undefined)), TypeMoq.Times.once());
done();
}).catch(err => {
assert.fail(err);
done(err);
});
});
test('addTelemetry should not crash not given data', (done) => {
TelemetryUtils.addTelemetry(telemetryService.object, telemetryKey).then(() => {
telemetryService.verify(x => x.publicLog(
TypeMoq.It.is(a => a === telemetryKey),
TypeMoq.It.is(b => b !== undefined)), TypeMoq.Times.once());
done();
}).catch(err => {
assert.fail(err);
done(err);
});
});
test('addTelemetry should try to get the provider name from data first', (done) => {
let data: TelemetryUtils.IConnectionTelemetryData = {
connection: connectionProfile
};
data.provider = providerName + '1';
TelemetryUtils.addTelemetry(telemetryService.object, telemetryKey, data, connectionProfile).then(() => {
telemetryService.verify(x => x.publicLog(TypeMoq.It.is(a => a === telemetryKey), TypeMoq.It.is(b => b.provider === data.provider)), TypeMoq.Times.once());
done();
}).catch(err => {
assert.fail(err);
done(err);
});
});
});

View File

@@ -0,0 +1,191 @@
/*---------------------------------------------------------------------------------------------
* 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 assert from 'assert';
import * as data from 'data';
import * as TypeMoq from 'typemoq';
import { AddAccountAction, RemoveAccountAction } from 'sql/parts/accountManagement/common/accountActions';
import { AccountManagementTestService } from 'sqltest/stubs/accountManagementStubs';
import { MessageServiceStub } from 'sqltest/stubs/messageServiceStub';
import { ErrorMessageServiceStub } from 'sqltest/stubs/errorMessageServiceStub';
let testAccount = <data.Account>{
key: {
providerId: 'azure',
accountId: 'testAccount'
},
displayInfo: {
contextualLogo: { light: '', dark: '' },
displayName: 'Test Account',
contextualDisplayName: 'Azure Account'
},
isStale: false
};
suite('Account Management Dialog Actions Tests', () => {
test('AddAccount - Success', (done) => {
// Setup: Create an AddAccountAction object
let param = 'azure';
let mocks = createAddAccountAction(true, true, param);
// If: I run the action when it will resolve
mocks.action.run()
.then(result => {
// Then:
// ... I should have gotten true back
assert.ok(result);
// ... The account management service should have gotten a add account request
mocks.accountMock.verify(x => x.addAccount(param), TypeMoq.Times.once());
})
.then(
() => done(),
err => done(err)
);
});
test('AddAccount - Failure', (done) => {
// Setup: Create an AddAccountAction object
let param = 'azure';
let mocks = createAddAccountAction(false, true, param);
// If: I run the action when it will reject
mocks.action.run().then(result => {
// Then:
// ... The result should be false since the operation failed
assert.ok(!result);
// ... The account management service should have gotten a add account request
mocks.accountMock.verify(x => x.addAccount(param), TypeMoq.Times.once());
done();
}, error => {
// Should fail as rejected actions cause the debugger to crash
done(error);
});
});
test('RemoveAccount - Confirm Success', (done) => {
// Setup: Create an AddAccountAction object
let ams = getMockAccountManagementService(true);
let ms = getMockMessageService(true);
let es = getMockErrorMessageService();
let action = new RemoveAccountAction(testAccount, ms.object, es.object, ams.object);
// If: I run the action when it will resolve
action.run()
.then(result => {
// Then:
// ... I should have gotten true back
assert.ok(result);
// ... A confirmation dialog should have opened
ms.verify(x => x.confirm(TypeMoq.It.isAny()), TypeMoq.Times.once());
// ... The account management service should have gotten a remove account request
ams.verify(x => x.removeAccount(TypeMoq.It.isValue(testAccount.key)), TypeMoq.Times.once());
})
.then(
() => done(),
err => done(err)
);
});
test('RemoveAccount - Declined Success', (done) => {
// Setup: Create an AddAccountAction object
let ams = getMockAccountManagementService(true);
let ms = getMockMessageService(false);
let es = getMockErrorMessageService();
let action = new RemoveAccountAction(testAccount, ms.object, es.object, ams.object);
// If: I run the action when it will resolve
action.run()
.then(result => {
try {
// Then:
// ... I should have gotten false back
assert.ok(!result);
// ... A confirmation dialog should have opened
ms.verify(x => x.confirm(TypeMoq.It.isAny()), TypeMoq.Times.once());
// ... The account management service should not have gotten a remove account request
ams.verify(x => x.removeAccount(TypeMoq.It.isAny()), TypeMoq.Times.never());
done();
} catch (e) {
done(e);
}
});
});
test('RemoveAccount - Failure', (done) => {
// Setup: Create an AddAccountAction object
let ams = getMockAccountManagementService(false);
let ms = getMockMessageService(true);
let es = getMockErrorMessageService();
let action = new RemoveAccountAction(testAccount, ms.object, es.object, ams.object);
// If: I run the action when it will reject
action.run().then(result => {
// Then:
// ... The result should be false since the operation failed
assert.ok(!result);
// ... The account management service should have gotten a remove account request
ams.verify(x => x.removeAccount(TypeMoq.It.isValue(testAccount.key)), TypeMoq.Times.once());
done();
}, error => {
// Should fail as rejected actions cause the debugger to crash
done(error);
});
});
});
function createAddAccountAction(resolve: boolean, confirm: boolean, param: string): IAddActionMocks {
let ams = getMockAccountManagementService(resolve);
let mockMessageService = getMockMessageService(confirm);
let mockErrorMessageService = getMockErrorMessageService();
return {
accountMock: ams,
messageMock: mockMessageService,
errorMessageMock: mockErrorMessageService,
action: new AddAccountAction(param, mockMessageService.object,
mockErrorMessageService.object, ams.object)
};
}
function getMockAccountManagementService(resolve: boolean): TypeMoq.Mock<AccountManagementTestService> {
let mockAccountManagementService = TypeMoq.Mock.ofType(AccountManagementTestService);
mockAccountManagementService.setup(x => x.addAccount(TypeMoq.It.isAnyString()))
.returns(resolve ? () => Promise.resolve(null) : () => Promise.reject(null));
mockAccountManagementService.setup(x => x.removeAccount(TypeMoq.It.isAny()))
.returns(resolve ? () => Promise.resolve(true) : () => Promise.reject(null).then());
return mockAccountManagementService;
}
function getMockMessageService(confirm: boolean): TypeMoq.Mock<MessageServiceStub> {
let mockMessageService = TypeMoq.Mock.ofType(MessageServiceStub);
mockMessageService.setup(x => x.confirm(TypeMoq.It.isAny()))
.returns(() => confirm);
return mockMessageService;
}
function getMockErrorMessageService(): TypeMoq.Mock<ErrorMessageServiceStub> {
let mockMessageService = TypeMoq.Mock.ofType(ErrorMessageServiceStub);
mockMessageService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()));
return mockMessageService;
}
interface IAddActionMocks
{
accountMock: TypeMoq.Mock<AccountManagementTestService>;
messageMock: TypeMoq.Mock<MessageServiceStub>;
errorMessageMock: TypeMoq.Mock<ErrorMessageServiceStub>;
action: AddAccountAction;
}

View File

@@ -0,0 +1,104 @@
/*---------------------------------------------------------------------------------------------
* 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 assert from 'assert';
import * as TypeMoq from 'typemoq';
import { Emitter } from 'vs/base/common/event';
import { AccountDialog } from 'sql/parts/accountManagement/accountDialog/accountDialog';
import { AccountDialogController } from 'sql/parts/accountManagement/accountDialog/accountDialogController';
import { AccountViewModel } from 'sql/parts/accountManagement/accountDialog/accountViewModel';
import { AccountManagementTestService } from 'sqltest/stubs/accountManagementStubs';
import { ErrorMessageServiceStub } from 'sqltest/stubs/errorMessageServiceStub';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { AccountListRenderer } from 'sql/parts/accountManagement/common/accountListRenderer';
import { ContextKeyServiceStub } from 'sqltest/stubs/contextKeyServiceStub';
// TESTS ///////////////////////////////////////////////////////////////////
suite('Account Management Dialog Controller Tests', () => {
test('Open Account Dialog - Dialog Doesn\'t Exist', () => {
// Setup: Create instance of the controller
let instantiationService = createInstantiationService();
let controller = new AccountDialogController(instantiationService, undefined);
assert.strictEqual(controller.accountDialog, undefined);
// If: I open the account dialog when one hasn't been opened
controller.openAccountDialog();
// Then:
// ... The account dialog should be defined
assert.notStrictEqual(controller.accountDialog, undefined);
});
test('Open Account Dialog - Dialog Exists', () => {
// Setup: Create instance of the controller with an account dialog already loaded
let instantiationService = createInstantiationService();
let controller = new AccountDialogController(instantiationService, undefined);
controller.openAccountDialog();
let accountDialog = controller.accountDialog;
// If: I open the account dialog when one has already been opened
controller.openAccountDialog();
// Then: It should be the same dialog that already existed
assert.equal(controller.accountDialog, accountDialog);
});
test('Add Account Failure - Error Message Shown', () => {
// Setup:
// ... Create instantiation service that returns mock emitter for account dialog
let mockEventEmitter = new Emitter<string>();
let instantiationService = createInstantiationService(mockEventEmitter);
// ... Create a mock instance of the error message service
let errorMessageServiceStub = new ErrorMessageServiceStub();
let mockErrorMessageService = TypeMoq.Mock.ofInstance(errorMessageServiceStub);
mockErrorMessageService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()));
// ... Create instance of the controller with an opened dialog
let controller = new AccountDialogController(instantiationService, mockErrorMessageService.object);
controller.openAccountDialog();
// If: The account dialog reports a failure adding an account
mockEventEmitter.fire('Error message');
// Then: An error dialog should have been opened
mockErrorMessageService.verify(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
});
});
function createInstantiationService(addAccountFailureEmitter?: Emitter<string>): InstantiationService {
// Create a mock account dialog view model
let accountViewModel = new AccountViewModel(new AccountManagementTestService());
let mockAccountViewModel = TypeMoq.Mock.ofInstance(accountViewModel);
let mockEvent = new Emitter<any>();
mockAccountViewModel.setup(x => x.addProviderEvent).returns(() => mockEvent.event);
mockAccountViewModel.setup(x => x.removeProviderEvent).returns(() => mockEvent.event);
mockAccountViewModel.setup(x => x.updateAccountListEvent).returns(() => mockEvent.event);
// Create a mocked out instantiation service
let instantiationService = TypeMoq.Mock.ofType(InstantiationService, TypeMoq.MockBehavior.Strict);
instantiationService.setup(x => x.createInstance<AccountViewModel>(TypeMoq.It.isValue(AccountViewModel)))
.returns(() => mockAccountViewModel.object);
instantiationService.setup(x => x.createInstance<AccountListRenderer>(TypeMoq.It.isValue(AccountListRenderer)))
.returns(() => undefined);
// Create a mock account dialog
let accountDialog = new AccountDialog(null, null, null, instantiationService.object, null, null, null, new ContextKeyServiceStub());
let mockAccountDialog = TypeMoq.Mock.ofInstance(accountDialog);
mockAccountDialog.setup(x => x.onAddAccountErrorEvent)
.returns(() => { return addAccountFailureEmitter ? addAccountFailureEmitter.event : mockEvent.event; });
mockAccountDialog.setup(x => x.onCloseEvent)
.returns(() => mockEvent.event);
mockAccountDialog.setup(x => x.render())
.returns(() => undefined);
mockAccountDialog.setup(x => x.open())
.returns(() => undefined);
instantiationService.setup(x => x.createInstance<AccountDialog>(TypeMoq.It.isValue(AccountDialog)))
.returns(() => mockAccountDialog.object);
return instantiationService.object;
}

View File

@@ -0,0 +1,224 @@
/*---------------------------------------------------------------------------------------------
* 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 assert from 'assert';
import * as data from 'data';
import * as TypeMoq from 'typemoq';
import { EventVerifierSingle } from 'sqltest/utils/eventVerifier';
import { Emitter } from 'vs/base/common/event';
import { AccountViewModel } from 'sql/parts/accountManagement/accountDialog/accountViewModel';
import { AccountProviderAddedEventParams, UpdateAccountListEventParams } from 'sql/services/accountManagement/eventTypes';
import { AccountManagementTestService } from 'sqltest/stubs/accountManagementStubs';
// SUITE STATE /////////////////////////////////////////////////////////////
let mockAddProviderEmitter: Emitter<AccountProviderAddedEventParams>;
let mockRemoveProviderEmitter: Emitter<data.AccountProviderMetadata>;
let mockUpdateAccountEmitter: Emitter<UpdateAccountListEventParams>;
let providers: data.AccountProviderMetadata[];
let accounts: data.Account[];
suite('Account Management Dialog ViewModel Tests', () => {
suiteSetup(() => {
providers = [{
id: 'azure',
displayName: 'Azure'
}];
let account1 = {
key: { providerId: 'azure', accountId: 'account1' },
name: 'Account 1',
displayInfo: {
contextualDisplayName: 'Microsoft Account',
contextualLogo: null,
displayName: 'Account 1'
},
properties: [],
isStale: false
};
let account2 = {
key: { providerId: 'azure', accountId: 'account2' },
name: 'Account 2',
displayInfo: {
contextualDisplayName: 'Work/School Account',
contextualLogo: null,
displayName: 'Account 2'
},
properties: [],
isStale: true
};
accounts = [account1, account2];
// Setup event mocks for the account management service
mockAddProviderEmitter = new Emitter<AccountProviderAddedEventParams>();
mockRemoveProviderEmitter = new Emitter<data.AccountProviderMetadata>();
mockUpdateAccountEmitter = new Emitter<UpdateAccountListEventParams>();
});
test('Construction - Events are properly defined', () => {
// If: I create an account viewmodel
let mockAccountManagementService = getMockAccountManagementService(false, false);
let vm = new AccountViewModel(mockAccountManagementService.object);
// Then:
// ... All the events for the view models should be properly initialized
assert.notEqual(vm.addProviderEvent, undefined);
assert.notEqual(vm.removeProviderEvent, undefined);
assert.notEqual(vm.updateAccountListEvent, undefined);
// ... All the events should properly fire
let argAddProvider: AccountProviderAddedEventParams = { addedProvider: providers[0], initialAccounts: [] };
let evAddProvider = new EventVerifierSingle<AccountProviderAddedEventParams>();
vm.addProviderEvent(evAddProvider.eventHandler);
mockAddProviderEmitter.fire(argAddProvider);
evAddProvider.assertFired(argAddProvider);
let argRemoveProvider = providers[0];
let evRemoveProvider = new EventVerifierSingle<data.AccountProviderMetadata>();
vm.removeProviderEvent(evRemoveProvider.eventHandler);
mockRemoveProviderEmitter.fire(argRemoveProvider);
evRemoveProvider.assertFired(argRemoveProvider);
let argUpdateAccounts: UpdateAccountListEventParams = { providerId: providers[0].id, accountList: accounts };
let evUpdateAccounts = new EventVerifierSingle<UpdateAccountListEventParams>();
vm.updateAccountListEvent(evUpdateAccounts.eventHandler);
mockUpdateAccountEmitter.fire(argUpdateAccounts);
evUpdateAccounts.assertFired(argUpdateAccounts);
});
test('Initialize - Success', done => {
// Setup: Create a viewmodel with event handlers
let mockAccountManagementService = getMockAccountManagementService(true, true);
let evAddProvider = new EventVerifierSingle<AccountProviderAddedEventParams>();
let evRemoveProvider = new EventVerifierSingle<data.AccountProviderMetadata>();
let evUpdateAccounts = new EventVerifierSingle<UpdateAccountListEventParams>();
let vm = getViewModel(mockAccountManagementService.object, evAddProvider, evRemoveProvider, evUpdateAccounts);
// If: I initialize the view model
vm.initialize()
.then(results => {
// Then:
// ... None of the events should have fired
assertNoEventsFired(evAddProvider, evRemoveProvider, evUpdateAccounts);
// ... The account management service should have been called
mockAccountManagementService.verify(x => x.getAccountProviderMetadata(), TypeMoq.Times.once());
mockAccountManagementService.verify(x => x.getAccountsForProvider(TypeMoq.It.isAny()), TypeMoq.Times.once());
// ... The results that were returned should be an array of account provider added event params
assert.ok(Array.isArray(results));
assert.equal(results.length, 1);
assert.equal(results[0].addedProvider, providers[0]);
assert.equal(results[0].initialAccounts, accounts);
}).then(
() => done(),
err => done(err)
);
});
test('Initialize - Get providers fails', done => {
// Setup: Create a mock account management service that rejects looking up providers
let mockAccountManagementService = getMockAccountManagementService(false, true);
let evAddProvider = new EventVerifierSingle<AccountProviderAddedEventParams>();
let evRemoveProvider = new EventVerifierSingle<data.AccountProviderMetadata>();
let evUpdateAccounts = new EventVerifierSingle<UpdateAccountListEventParams>();
let vm = getViewModel(mockAccountManagementService.object, evAddProvider, evRemoveProvider, evUpdateAccounts);
// If: I initialize the view model
vm.initialize()
.then(results => {
// Then
// ... None of the events should have fired
assertNoEventsFired(evAddProvider, evRemoveProvider, evUpdateAccounts);
// ... The account management service should have been called for providers, but not accounts
mockAccountManagementService.verify(x => x.getAccountProviderMetadata(), TypeMoq.Times.once());
mockAccountManagementService.verify(x => x.getAccountsForProvider(TypeMoq.It.isAny()), TypeMoq.Times.never());
// ... The results that were returned should be an empty array
assert.ok(Array.isArray(results));
assert.equal(results.length, 0);
})
.then(
() => done(),
err => done(err)
);
});
test('Initialize - Get accounts fails', done => {
// Setup: Create a mock account management service that rejects the promise
let mockAccountManagementService = getMockAccountManagementService(true, false);
let evAddProvider = new EventVerifierSingle<AccountProviderAddedEventParams>();
let evRemoveProvider = new EventVerifierSingle<data.AccountProviderMetadata>();
let evUpdateAccounts = new EventVerifierSingle<UpdateAccountListEventParams>();
let vm = getViewModel(mockAccountManagementService.object, evAddProvider, evRemoveProvider, evUpdateAccounts);
// If: I initialize the view model
vm.initialize()
.then(result => {
// Then:
// ... None of the events should have fired
assertNoEventsFired(evAddProvider, evRemoveProvider, evUpdateAccounts);
// ... The account management service should have been called
mockAccountManagementService.verify(x => x.getAccountProviderMetadata(), TypeMoq.Times.once());
mockAccountManagementService.verify(x => x.getAccountsForProvider(TypeMoq.It.isAny()), TypeMoq.Times.once());
// ... The results should include the provider
assert.ok(Array.isArray(result));
assert.equal(result.length, 1);
assert.equal(result[0].addedProvider, providers[0]);
assert.equal(result[0].initialAccounts, accounts);
}).then(
() => done(),
err => done()
);
});
});
function getMockAccountManagementService(resolveProviders: boolean, resolveAccounts: boolean): TypeMoq.Mock<AccountManagementTestService> {
let mockAccountManagementService = TypeMoq.Mock.ofType(AccountManagementTestService);
mockAccountManagementService.setup(x => x.getAccountProviderMetadata())
.returns(() => resolveProviders ? Promise.resolve(providers) : Promise.reject(null).then());
mockAccountManagementService.setup(x => x.getAccountsForProvider(TypeMoq.It.isAny()))
.returns(() => resolveAccounts ? Promise.resolve(accounts) : Promise.reject(null).then());
mockAccountManagementService.setup(x => x.addAccountProviderEvent)
.returns(() => mockAddProviderEmitter.event);
mockAccountManagementService.setup(x => x.removeAccountProviderEvent)
.returns(() => mockRemoveProviderEmitter.event);
mockAccountManagementService.setup(x => x.updateAccountListEvent)
.returns(() => mockUpdateAccountEmitter.event);
return mockAccountManagementService;
}
function getViewModel(
ams: AccountManagementTestService,
evAdd: EventVerifierSingle<AccountProviderAddedEventParams>,
evRemove: EventVerifierSingle<data.AccountProviderMetadata>,
evUpdate: EventVerifierSingle<UpdateAccountListEventParams>
): AccountViewModel {
let vm = new AccountViewModel(ams);
vm.addProviderEvent(evAdd.eventHandler);
vm.removeProviderEvent(evRemove.eventHandler);
vm.updateAccountListEvent(evUpdate.eventHandler);
return vm;
}
function assertNoEventsFired(
evAdd: EventVerifierSingle<AccountProviderAddedEventParams>,
evRemove: EventVerifierSingle<data.AccountProviderMetadata>,
evUpdate: EventVerifierSingle<UpdateAccountListEventParams>
): void {
evAdd.assertNotFired();
evRemove.assertNotFired();
evUpdate.assertNotFired();
}

View File

@@ -0,0 +1,30 @@
/*---------------------------------------------------------------------------------------------
* 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 assert from 'assert';
import data = require('data');
import * as TypeMoq from 'typemoq';
import { AdminService } from 'sql/parts/admin/common/adminService';
suite('SQL AdminService tests', () => {
let adminService: AdminService;
setup(() => {
adminService = new AdminService(
undefined, undefined, undefined, undefined
);
});
test('createDatabase should call tools service provider', done => {
done();
// adminService.createDatabase(undefined, undefined).then((result) => {
// assert.notEqual(result, undefined, 'Result is undefined');
// done();
// });
});
});

View File

@@ -0,0 +1,415 @@
/*---------------------------------------------------------------------------------------------
* 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 OptionsDialogHelper from 'sql/base/browser/ui/modal/optionsDialogHelper';
import { ServiceOptionType } from 'sql/parts/connection/common/connectionManagement';
import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
import data = require('data');
import { Builder, $ } from 'vs/base/browser/builder';
import * as TypeMoq from 'typemoq';
import * as assert from 'assert';
suite('Advanced options helper tests', () => {
var possibleInputs: string[];
let options: { [name: string]: any };
var categoryOption: data.ServiceOption;
var booleanOption: data.ServiceOption;
var numberOption: data.ServiceOption;
var stringOption: data.ServiceOption;
var defaultGroupOption: data.ServiceOption;
var isValid: boolean;
var inputValue: string;
var inputBox: TypeMoq.Mock<InputBox>;
var optionsMap: { [optionName: string]: OptionsDialogHelper.IOptionElement };
setup(() => {
options = {};
optionsMap = {};
categoryOption = {
name: 'applicationIntent',
displayName: 'Application Intent',
description: 'Declares the application workload type when connecting to a server',
groupName: 'Initialization',
categoryValues: [
{ displayName: 'ReadWrite', name: 'ReadWrite' },
{ displayName: 'ReadOnly', name: 'ReadOnly' }
],
defaultValue: null,
isRequired: false,
valueType: ServiceOptionType.category,
objectType: undefined,
isArray: undefined
};
booleanOption = {
name: 'asynchronousProcessing',
displayName: 'Asynchronous processing enabled',
description: 'When true, enables usage of the Asynchronous functionality in the .Net Framework Data Provider',
groupName: 'Initialization',
categoryValues: null,
defaultValue: null,
isRequired: false,
valueType: ServiceOptionType.boolean,
objectType: undefined,
isArray: undefined
};
numberOption = {
name: 'connectTimeout',
displayName: 'Connect Timeout',
description: 'The length of time (in seconds) to wait for a connection to the server before terminating the attempt and generating an error',
groupName: 'Initialization',
categoryValues: null,
defaultValue: '15',
isRequired: false,
valueType: ServiceOptionType.number,
objectType: undefined,
isArray: undefined
};
stringOption = {
name: 'currentLanguage',
displayName: 'Current Language',
description: 'The SQL Server language record name',
groupName: 'Initialization',
categoryValues: null,
defaultValue: null,
isRequired: false,
valueType: ServiceOptionType.string,
objectType: undefined,
isArray: undefined
};
defaultGroupOption = {
name: 'defaultGroupOption',
displayName: 'Default Group',
description: 'Test string option',
groupName: undefined,
categoryValues: null,
defaultValue: null,
isRequired: false,
valueType: ServiceOptionType.string,
objectType: undefined,
isArray: undefined
};
let builder: Builder = $().div();
inputBox = TypeMoq.Mock.ofType(InputBox, TypeMoq.MockBehavior.Loose, builder.getHTMLElement(), null, null);
inputBox.callBase = true;
inputBox.setup(x => x.validate()).returns(() => isValid);
inputBox.setup(x => x.value).returns(() => inputValue);
});
test('create default but not required category options should set the option value and possible inputs correctly', () => {
categoryOption.defaultValue = 'ReadWrite';
categoryOption.isRequired = false;
possibleInputs = [];
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(categoryOption, options, possibleInputs);
assert.equal(optionValue, 'ReadWrite');
assert.equal(possibleInputs.length, 3);
assert.equal(possibleInputs[0], '');
assert.equal(possibleInputs[1], 'ReadWrite');
assert.equal(possibleInputs[2], 'ReadOnly');
});
test('create default and required category options should set the option value and possible inputs correctly', () => {
categoryOption.defaultValue = 'ReadWrite';
categoryOption.isRequired = true;
possibleInputs = [];
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(categoryOption, options, possibleInputs);
assert.equal(optionValue, 'ReadWrite');
assert.equal(possibleInputs.length, 2);
assert.equal(possibleInputs[0], 'ReadWrite');
assert.equal(possibleInputs[1], 'ReadOnly');
});
test('create no default and not required category options should set the option value and possible inputs correctly', () => {
categoryOption.defaultValue = null;
categoryOption.isRequired = false;
possibleInputs = [];
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(categoryOption, options, possibleInputs);
assert.equal(optionValue, '');
assert.equal(possibleInputs.length, 3);
assert.equal(possibleInputs[0], '');
assert.equal(possibleInputs[1], 'ReadWrite');
assert.equal(possibleInputs[2], 'ReadOnly');
});
test('create no default but required category options should set the option value and possible inputs correctly', () => {
categoryOption.defaultValue = null;
categoryOption.isRequired = true;
possibleInputs = [];
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(categoryOption, options, possibleInputs);
assert.equal(optionValue, 'ReadWrite');
assert.equal(possibleInputs.length, 2);
assert.equal(possibleInputs[0], 'ReadWrite');
assert.equal(possibleInputs[1], 'ReadOnly');
});
test('create not required category options with option value should set the option value and possible inputs correctly', () => {
categoryOption.defaultValue = null;
categoryOption.isRequired = false;
possibleInputs = [];
options['applicationIntent'] = 'ReadOnly';
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(categoryOption, options, possibleInputs);
assert.equal(optionValue, 'ReadOnly');
assert.equal(possibleInputs.length, 3);
assert.equal(possibleInputs[0], '');
assert.equal(possibleInputs[1], 'ReadWrite');
assert.equal(possibleInputs[2], 'ReadOnly');
});
test('create required category options with option value should set the option value and possible inputs correctly', () => {
categoryOption.defaultValue = null;
categoryOption.isRequired = true;
possibleInputs = [];
options['applicationIntent'] = 'ReadOnly';
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(categoryOption, options, possibleInputs);
assert.equal(optionValue, 'ReadOnly');
assert.equal(possibleInputs.length, 2);
assert.equal(possibleInputs[0], 'ReadWrite');
assert.equal(possibleInputs[1], 'ReadOnly');
});
test('create default but not required boolean options should set the option value and possible inputs correctly', () => {
booleanOption.defaultValue = 'False';
booleanOption.isRequired = false;
possibleInputs = [];
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(booleanOption, options, possibleInputs);
assert.equal(optionValue, 'False');
assert.equal(possibleInputs.length, 3);
assert.equal(possibleInputs[0], '');
assert.equal(possibleInputs[1], 'True');
assert.equal(possibleInputs[2], 'False');
});
test('create default and required boolean options should set the option value and possible inputs correctly', () => {
booleanOption.defaultValue = 'False';
booleanOption.isRequired = true;
possibleInputs = [];
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(booleanOption, options, possibleInputs);
assert.equal(optionValue, 'False');
assert.equal(possibleInputs.length, 2);
assert.equal(possibleInputs[0], 'True');
assert.equal(possibleInputs[1], 'False');
});
test('create no default and not required boolean options should set the option value and possible inputs correctly', () => {
booleanOption.defaultValue = null;
booleanOption.isRequired = false;
possibleInputs = [];
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(booleanOption, options, possibleInputs);
assert.equal(optionValue, '');
assert.equal(possibleInputs.length, 3);
assert.equal(possibleInputs[0], '');
assert.equal(possibleInputs[1], 'True');
assert.equal(possibleInputs[2], 'False');
});
test('create no default but required boolean options should set the option value and possible inputs correctly', () => {
booleanOption.defaultValue = null;
booleanOption.isRequired = true;
possibleInputs = [];
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(booleanOption, options, possibleInputs);
assert.equal(optionValue, 'True');
assert.equal(possibleInputs.length, 2);
assert.equal(possibleInputs[0], 'True');
assert.equal(possibleInputs[1], 'False');
});
test('create not required boolean options with option value should set the option value and possible inputs correctly', () => {
booleanOption.defaultValue = null;
booleanOption.isRequired = false;
possibleInputs = [];
options['asynchronousProcessing'] = true;
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(booleanOption, options, possibleInputs);
assert.equal(optionValue, 'True');
assert.equal(possibleInputs.length, 3);
assert.equal(possibleInputs[0], '');
assert.equal(possibleInputs[1], 'True');
assert.equal(possibleInputs[2], 'False');
});
test('create required boolean options with option value should set the option value and possible inputs correctly', () => {
booleanOption.defaultValue = null;
booleanOption.isRequired = true;
possibleInputs = [];
options['asynchronousProcessing'] = 'False';
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(booleanOption, options, possibleInputs);
assert.equal(optionValue, 'False');
assert.equal(possibleInputs.length, 2);
assert.equal(possibleInputs[0], 'True');
assert.equal(possibleInputs[1], 'False');
});
test('create default number options should set the option value and possible inputs correctly', () => {
numberOption.defaultValue = '15';
numberOption.isRequired = true;
possibleInputs = [];
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(numberOption, options, possibleInputs);
assert.equal(optionValue, '15');
});
test('create number options with option value should set the option value and possible inputs correctly', () => {
numberOption.defaultValue = '15';
numberOption.isRequired = false;
possibleInputs = [];
options['connectTimeout'] = '45';
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(numberOption, options, possibleInputs);
assert.equal(optionValue, '45');
});
test('create default string options should set the option value and possible inputs correctly', () => {
stringOption.defaultValue = 'Japanese';
stringOption.isRequired = true;
possibleInputs = [];
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(stringOption, options, possibleInputs);
assert.equal(optionValue, 'Japanese');
});
test('create string options with option value should set the option value and possible inputs correctly', () => {
stringOption.defaultValue = 'Japanese';
stringOption.isRequired = false;
possibleInputs = [];
options['currentLanguage'] = 'Spanish';
var optionValue = OptionsDialogHelper.getOptionValueAndCategoryValues(stringOption, options, possibleInputs);
assert.equal(optionValue, 'Spanish');
});
test('validate undefined and optional number input should return no error', () => {
isValid = true;
inputValue = '';
numberOption.isRequired = false;
optionsMap = {};
optionsMap['connectTimeout'] = {
optionWidget: inputBox.object,
option: numberOption,
optionValue: null
};
var error = OptionsDialogHelper.validateInputs(optionsMap);
assert.equal(error, true);
});
test('validate a valid optional number input should return no error', () => {
isValid = true;
inputValue = '30';
numberOption.isRequired = false;
optionsMap = {};
optionsMap['connectTimeout'] = {
optionWidget: inputBox.object,
option: numberOption,
optionValue: null
};
var error = OptionsDialogHelper.validateInputs(optionsMap);
assert.equal(error, true);
});
test('validate a valid required number input should return no error', () => {
isValid = true;
inputValue = '30';
numberOption.isRequired = true;
optionsMap = {};
optionsMap['connectTimeout'] = {
optionWidget: inputBox.object,
option: numberOption,
optionValue: null
};
var error = OptionsDialogHelper.validateInputs(optionsMap);
assert.equal(error, true);
});
test('validate invalid optional number option should return an expected error', () => {
isValid = false;
inputValue = 'abc';
numberOption.isRequired = false;
optionsMap = {};
optionsMap['connectTimeout'] = {
optionWidget: inputBox.object,
option: numberOption,
optionValue: null
};
var error = OptionsDialogHelper.validateInputs(optionsMap);
assert.equal(error, false);
});
test('validate required optional number option should return an expected error', () => {
isValid = false;
inputValue = '';
numberOption.isRequired = true;
optionsMap = {};
optionsMap['connectTimeout'] = {
optionWidget: inputBox.object,
option: numberOption,
optionValue: null
};
var error = OptionsDialogHelper.validateInputs(optionsMap);
assert.equal(error, false);
});
test('update options should delete option entry if the input value is an empty string', () => {
isValid = true;
inputValue = '';
numberOption.isRequired = false;
optionsMap = {};
optionsMap['connectTimeout'] = {
optionWidget: inputBox.object,
option: numberOption,
optionValue: '45'
};
options['connectTimeout'] = '45';
OptionsDialogHelper.updateOptions(options, optionsMap);
assert.equal(options['connectTimeout'], undefined);
});
test('update options should update correct option value', () => {
isValid = true;
inputValue = '50';
numberOption.isRequired = false;
optionsMap = {};
optionsMap['connectTimeout'] = {
optionWidget: inputBox.object,
option: numberOption,
optionValue: '45'
};
options['connectTimeout'] = '45';
OptionsDialogHelper.updateOptions(options, optionsMap);
assert.equal(options['connectTimeout'], 50);
});
test('update options should add the option value to options', () => {
isValid = true;
inputValue = '50';
numberOption.isRequired = false;
optionsMap = {};
optionsMap['connectTimeout'] = {
optionWidget: inputBox.object,
option: numberOption,
optionValue: '45'
};
options = {};
OptionsDialogHelper.updateOptions(options, optionsMap);
assert.equal(options['connectTimeout'], 50);
});
test('groupOptionsByCategory converts a list of options to a map of category names to lists of options', () => {
let optionsList = [categoryOption, booleanOption, numberOption, stringOption, defaultGroupOption];
let optionsMap = OptionsDialogHelper.groupOptionsByCategory(optionsList);
let categoryNames = Object.keys(optionsMap);
assert.equal(categoryNames.includes('Initialization'), true);
assert.equal(categoryNames.includes('General'), true);
assert.equal(categoryNames.length, 2);
assert.equal(optionsMap['Initialization'].length, 4);
assert.equal(optionsMap['General'].length, 1);
});
});

View File

@@ -0,0 +1,106 @@
/*---------------------------------------------------------------------------------------------
* 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 { OptionsDialog } from 'sql/base/browser/ui/modal/optionsDialog';
import { AdvancedPropertiesController } from 'sql/parts/connection/connectionDialog/advancedPropertiesController';
import { Builder, $ } from 'vs/base/browser/builder';
import { ContextKeyServiceStub } from 'sqltest/stubs/contextKeyServiceStub';
import * as data from 'data';
import * as TypeMoq from 'typemoq';
import * as assert from 'assert';
suite('Advanced properties dialog tests', () => {
var advancedController: AdvancedPropertiesController;
var providerOptions: data.ConnectionOption[];
setup(() => {
advancedController = new AdvancedPropertiesController(() => { }, null);
providerOptions = [
{
name: 'a1',
displayName: undefined,
description: undefined,
groupName: 'a',
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: null,
valueType: 0
},
{
name: 'b1',
displayName: undefined,
description: undefined,
groupName: 'b',
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: null,
valueType: 0
},
{
name: 'noType',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: null,
valueType: 0
},
{
name: 'a2',
displayName: undefined,
description: undefined,
groupName: 'a',
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: null,
valueType: 0
},
{
name: 'b2',
displayName: undefined,
description: undefined,
groupName: 'b',
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: null,
valueType: 0
}
];
});
test('advanced dialog should open when showDialog in advancedController get called', () => {
var isAdvancedDialogCalled = false;
let options: { [name: string]: any } = {};
let builder: Builder = $().div();
let advanceDialog = TypeMoq.Mock.ofType(OptionsDialog, TypeMoq.MockBehavior.Strict,
'', // title
'', // name
{}, // options
undefined, // partsService
undefined, // themeService
undefined, // Context view service
undefined, // telemetry service
new ContextKeyServiceStub() // contextkeyservice
);
advanceDialog.setup(x => x.open(TypeMoq.It.isAny(), TypeMoq.It.isAny())).callback(() => {
isAdvancedDialogCalled = true;
});
advancedController.advancedDialog = advanceDialog.object;
advancedController.showDialog(providerOptions, builder.getHTMLElement(), options);
assert.equal(isAdvancedDialogCalled, true);
});
});

View File

@@ -0,0 +1,931 @@
/*---------------------------------------------------------------------------------------------
* 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/parts/connection/common/connectionConfig';
import { IConnectionProfile, IConnectionProfileStore } from 'sql/parts/connection/common/interfaces';
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
import { ConfigurationTarget, IConfigurationValue } from 'vs/workbench/services/configuration/common/configurationEditing';
import { IConfigurationValue as TConfigurationValue } from 'vs/platform/configuration/common/configuration';
import { WorkspaceConfigurationTestService } from 'sqltest/stubs/workspaceConfigurationTestService';
import { ConfigurationEditingService } from 'vs/workbench/services/configuration/node/configurationEditingService';
import * as Constants from 'sql/parts/connection/common/constants';
import { IConnectionProfileGroup, ConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup';
import { TPromise } from 'vs/base/common/winjs.base';
import * as assert from 'assert';
import { CapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
import data = require('data');
import { Emitter } from 'vs/base/common/event';
suite('SQL ConnectionConfig tests', () => {
let capabilitiesService: TypeMoq.Mock<CapabilitiesService>;
let workspaceConfigurationServiceMock: TypeMoq.Mock<WorkspaceConfigurationTestService>;
let configEditingServiceMock: TypeMoq.Mock<ConfigurationEditingService>;
let msSQLCapabilities: data.DataProtocolServerCapabilities;
let capabilities: data.DataProtocolServerCapabilities[];
let onProviderRegistered = new Emitter<data.DataProtocolServerCapabilities>();
let configValueToConcat: TConfigurationValue<IConnectionProfileGroup[]> = {
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: [],
folder: []
};
let configValueToMerge: TConfigurationValue<IConnectionProfileGroup[]> = {
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: [],
folder: []
};
let connections: TConfigurationValue<IConnectionProfileStore[]> = {
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: [],
folder: []
};
setup(() => {
capabilitiesService = TypeMoq.Mock.ofType(CapabilitiesService);
capabilities = [];
let connectionProvider: data.ConnectionProviderOptions = {
options: [
{
name: 'serverName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 0,
valueType: 0
},
{
name: 'databaseName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 1,
valueType: 0
},
{
name: 'userName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 3,
valueType: 0
},
{
name: 'authenticationType',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 2,
valueType: 0
},
{
name: 'password',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 4,
valueType: 0
}
]
};
msSQLCapabilities = {
protocolVersion: '1',
providerName: 'MSSQL',
providerDisplayName: 'MSSQL',
connectionProvider: connectionProvider,
adminServicesProvider: undefined,
features: undefined
};
capabilities.push(msSQLCapabilities);
capabilitiesService.setup(x => x.getCapabilities()).returns(() => capabilities);
capabilitiesService.setup(x => x.onProviderRegisteredEvent).returns(() => onProviderRegistered.event);
workspaceConfigurationServiceMock = TypeMoq.Mock.ofType(WorkspaceConfigurationTestService);
workspaceConfigurationServiceMock.setup(x => x.reloadConfiguration())
.returns(() => TPromise.as<{}>({}));
configEditingServiceMock = TypeMoq.Mock.ofType(ConfigurationEditingService);
let nothing: void;
configEditingServiceMock.setup(x => x.writeConfiguration(ConfigurationTarget.USER, TypeMoq.It.isAny())).returns(() => TPromise.as<void>(nothing));
configEditingServiceMock.setup(x => x.writeConfiguration(ConfigurationTarget.WORKSPACE, TypeMoq.It.isAny())).returns(() => TPromise.as<void>(nothing));
});
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.lookup<IConnectionProfile[] | IConnectionProfileGroup[] | data.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.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.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
};
let expectedNumberOfConnections = connections.user.length + 1;
workspaceConfigurationServiceMock.setup(x => x.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.DataProtocolServerCapabilities[]>(
Constants.connectionsArrayName))
.returns(() => connections);
workspaceConfigurationServiceMock.setup(x => x.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.DataProtocolServerCapabilities[]>(
Constants.connectionGroupsArrayName))
.returns(() => configValueToConcat);
let connectionProfile = new ConnectionProfile(msSQLCapabilities, 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 => {
assert.fail();
done();
});
});
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
};
let expectedNumberOfConnections = connections.user.length;
workspaceConfigurationServiceMock.setup(x => x.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.DataProtocolServerCapabilities[]>(
Constants.connectionsArrayName))
.returns(() => connections);
workspaceConfigurationServiceMock.setup(x => x.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.DataProtocolServerCapabilities[]>(
Constants.connectionGroupsArrayName))
.returns(() => configValueToConcat);
let connectionProfile = new ConnectionProfile(msSQLCapabilities, 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 => {
assert.fail();
done();
});
});
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
};
let expectedNumberOfConnections = connections.user.length + 1;
let expectedNumberOfGroups = configValueToConcat.user.length + 1;
workspaceConfigurationServiceMock.setup(x => x.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.DataProtocolServerCapabilities[]>(
Constants.connectionsArrayName))
.returns(() => connections);
workspaceConfigurationServiceMock.setup(x => x.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.DataProtocolServerCapabilities[]>(
Constants.connectionGroupsArrayName))
.returns(() => configValueToConcat);
let connectionProfile = new ConnectionProfile(msSQLCapabilities, 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 => {
assert.fail();
done();
});
});
test('getConnections should return connections from user and workspace settings given getWorkspaceConnections set to true', () => {
let getWorkspaceConnections: boolean = true;
workspaceConfigurationServiceMock.setup(x => x.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.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.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.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: TConfigurationValue<IConnectionProfileStore[]> = {
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,
folder: []
};
workspaceConfigurationServiceMock.setup(x => x.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.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].connectionProvider.options.concat({
name: oldOptionName,
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 0,
valueType: 0
});
let capabilitiesFromConfig: data.DataProtocolServerCapabilities[] = [];
let connectionProvider: data.ConnectionProviderOptions = {
options: optionsMetadataFromConfig
};
let msSQLCapabilities2 = {
protocolVersion: '1',
providerName: 'MSSQL',
providerDisplayName: 'MSSQL',
connectionProvider: connectionProvider,
adminServicesProvider: undefined,
features: undefined
};
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<CapabilitiesService> = TypeMoq.Mock.ofType(CapabilitiesService);
capabilitiesService2.setup(x => x.getCapabilities()).returns(() => []);
capabilitiesService2.setup(x => x.onProviderRegisteredEvent).returns(() => onProviderRegistered.event);
workspaceConfigurationServiceMock.setup(x => x.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.DataProtocolServerCapabilities[]>(
Constants.connectionsArrayName))
.returns(() => configValue);
let config = new ConnectionConfig(configEditingServiceMock.object, workspaceConfigurationServiceMock.object, capabilitiesService2.object, capabilitiesFromConfig);
let allConnections = config.getConnections(false);
allConnections.forEach(element => {
assert.notEqual(element.serverName, undefined);
assert.notEqual(element.getOptionsKey().indexOf('oldOptionValue|'), -1);
});
onProviderRegistered.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, 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, 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, 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
};
let expectedNumberOfConnections = connections.user.length - 1;
workspaceConfigurationServiceMock.setup(x => x.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.DataProtocolServerCapabilities[]>(
Constants.connectionsArrayName))
.returns(() => connections);
let connectionProfile = new ConnectionProfile(msSQLCapabilities, 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 => {
assert.fail();
done();
});
});
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
};
let connectionProfile = new ConnectionProfile(msSQLCapabilities, 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.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.DataProtocolServerCapabilities[]>(
Constants.connectionsArrayName))
.returns(() => connections);
workspaceConfigurationServiceMock.setup(x => x.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.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 => {
assert.fail();
done();
});
});
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
};
let expectedNumberOfConnections = connections.user.length;
workspaceConfigurationServiceMock.setup(x => x.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.DataProtocolServerCapabilities[]>(
Constants.connectionsArrayName))
.returns(() => connections);
let connectionProfile = new ConnectionProfile(msSQLCapabilities, 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 => {
assert.fail();
done();
});
});
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(() => TPromise.as<void>(nothing));
workspaceConfigurationServiceMock.setup(x => x.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.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(() => TPromise.as<void>(nothing));
workspaceConfigurationServiceMock.setup(x => x.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.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'
};
let expectedNumberOfConnections = connections.user.length;
workspaceConfigurationServiceMock.setup(x => x.lookup<IConnectionProfileStore[] | IConnectionProfileGroup[] | data.DataProtocolServerCapabilities[]>(
Constants.connectionsArrayName))
.returns(() => connections);
let connectionProfile = new ConnectionProfile(msSQLCapabilities, 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(() => TPromise.as<void>(nothing));
configEditingServiceMock.setup(x => x.writeConfiguration(ConfigurationTarget.WORKSPACE, TypeMoq.It.isAny())).callback((x: any, val: any) => {
}).returns(() => TPromise.as<void>(nothing));
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();
});
});

View File

@@ -0,0 +1,87 @@
/*---------------------------------------------------------------------------------------------
* 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 { ConnectionDialogService } from 'sql/parts/connection/connectionDialog/connectionDialogService';
import { ConnectionDialogWidget } from 'sql/parts/connection/connectionDialog/connectionDialogWidget';
import { ConnectionManagementService } from 'sql/parts/connection/common/connectionManagementService';
import { ConnectionType, IConnectableInput, IConnectionResult, INewConnectionParams } from 'sql/parts/connection/common/connectionManagement';
import { ContextKeyServiceStub } from 'sqltest/stubs/contextKeyServiceStub';
import { ErrorMessageServiceStub } from 'sqltest/stubs/errorMessageServiceStub';
import * as TypeMoq from 'typemoq';
suite('ConnectionDialogService tests', () => {
let connectionDialogService: ConnectionDialogService;
let mockConnectionManagementService: TypeMoq.Mock<ConnectionManagementService>;
let mockConnectionDialog: TypeMoq.Mock<ConnectionDialogWidget>;
setup(() => {
let errorMessageService = getMockErrorMessageService();
connectionDialogService = new ConnectionDialogService(undefined, undefined, undefined, errorMessageService.object, undefined);
mockConnectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Strict, {}, {});
(connectionDialogService as any)._connectionManagementService = mockConnectionManagementService.object;
mockConnectionDialog = TypeMoq.Mock.ofType(ConnectionDialogWidget, TypeMoq.MockBehavior.Strict,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
new ContextKeyServiceStub()
);
mockConnectionDialog.setup(c => c.resetConnection());
(connectionDialogService as any)._connectionDialog = mockConnectionDialog.object;
});
function getMockErrorMessageService(): TypeMoq.Mock<ErrorMessageServiceStub> {
let mockMessageService = TypeMoq.Mock.ofType(ErrorMessageServiceStub);
mockMessageService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()));
return mockMessageService;
}
function testHandleDefaultOnConnectUri(isEditor: boolean): Thenable<void> {
let testUri = 'test_uri';
let connectionParams = <INewConnectionParams>{
connectionType: isEditor ? ConnectionType.editor : ConnectionType.default,
input: <IConnectableInput>{
uri: testUri,
onConnectStart: undefined,
onConnectSuccess: undefined,
onConnectReject: undefined,
onDisconnect: undefined
},
runQueryOnCompletion: undefined,
querySelection: undefined
};
mockConnectionManagementService.setup(x => x.connectAndSaveProfile(undefined, TypeMoq.It.is(_ => true), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(
() => Promise.resolve(<IConnectionResult>{ connected: true, errorMessage: undefined, errorCode: undefined }));
// If I call handleDefaultOnConnect with the given parameters
let thenable: Thenable<void> = (connectionDialogService as any).handleDefaultOnConnect(connectionParams, undefined);
return thenable.then(() => {
// Then the Connection Management Service's connect method was called with the expected URI
let expectedUri = isEditor ? testUri : undefined;
mockConnectionManagementService.verify(
x => x.connectAndSaveProfile(undefined, TypeMoq.It.is(uri => uri === expectedUri), TypeMoq.It.isAny(), TypeMoq.It.isAny()),
TypeMoq.Times.once());
});
}
test('handleDefaultOnConnect uses params URI for editor connections', done => {
testHandleDefaultOnConnectUri(true).then(() => done(), err => {
done(err);
});
});
test('handleDefaultOnConnect uses undefined URI for non-editor connections', done => {
testHandleDefaultOnConnectUri(false).then(() => done(), err => {
done(err);
});
});
});

View File

@@ -0,0 +1,563 @@
/*---------------------------------------------------------------------------------------------
* 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 { ConnectionDialogTestService } from 'sqltest/stubs/connectionDialogTestService';
import { ConnectionManagementService } from 'sql/parts/connection/common/connectionManagementService';
import { ConnectionStatusManager } from 'sql/parts/connection/common/connectionStatusManager';
import { ConnectionStore } from 'sql/parts/connection/common/connectionStore';
import {
INewConnectionParams, ConnectionType,
IConnectionCompletionOptions, IConnectionResult,
RunQueryOnConnectionMode
} from 'sql/parts/connection/common/connectionManagement';
import * as Constants from 'sql/parts/connection/common/constants';
import * as Utils from 'sql/parts/connection/common/utils';
import { WorkbenchEditorTestService } from 'sqltest/stubs/workbenchEditorTestService';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { EditorGroupTestService } from 'sqltest/stubs/editorGroupService';
import { CapabilitiesTestService } from 'sqltest/stubs/capabilitiesTestService';
import { ConnectionProviderStub } from 'sqltest/stubs/connectionProviderStub';
import * as data from 'data';
import { TPromise } from 'vs/base/common/winjs.base';
import { WorkspaceConfigurationTestService } from 'sqltest/stubs/workspaceConfigurationTestService';
import * as assert from 'assert';
import * as TypeMoq from 'typemoq';
suite('SQL ConnectionManagementService tests', () => {
let capabilitiesService: CapabilitiesTestService;
let connectionDialogService: TypeMoq.Mock<ConnectionDialogTestService>;
let connectionStore: TypeMoq.Mock<ConnectionStore>;
let workbenchEditorService: TypeMoq.Mock<WorkbenchEditorTestService>;
let editorGroupService: TypeMoq.Mock<EditorGroupTestService>;
let connectionStatusManager: ConnectionStatusManager;
let mssqlConnectionProvider: TypeMoq.Mock<ConnectionProviderStub>;
let otherConnectionProvider: TypeMoq.Mock<ConnectionProviderStub>;
let workspaceConfigurationServiceMock: TypeMoq.Mock<WorkspaceConfigurationTestService>;
let none: void;
let connectionProfile: IConnectionProfile = {
serverName: 'new server',
databaseName: 'database',
userName: 'user',
password: 'password',
authenticationType: 'integrated',
savePassword: true,
groupFullName: 'g2/g2-2',
groupId: 'group id',
getOptionsKey: () => { return 'connectionId'; },
matches: undefined,
providerName: 'MSSQL',
options: {},
saveProfile: true,
id: undefined
};
let connectionProfileWithEmptySavedPassword: IConnectionProfile =
Object.assign({}, connectionProfile, { password: '', serverName: connectionProfile.serverName + 1 });
let connectionProfileWithEmptyUnsavedPassword: IConnectionProfile =
Object.assign({}, connectionProfile, { password: '', serverName: connectionProfile.serverName + 2, savePassword: false });
let connectionManagementService: ConnectionManagementService;
let configResult: { [key: string]: any } = {};
setup(() => {
capabilitiesService = new CapabilitiesTestService();
connectionDialogService = TypeMoq.Mock.ofType(ConnectionDialogTestService);
connectionStore = TypeMoq.Mock.ofType(ConnectionStore);
workbenchEditorService = TypeMoq.Mock.ofType(WorkbenchEditorTestService);
editorGroupService = TypeMoq.Mock.ofType(EditorGroupTestService);
connectionStatusManager = new ConnectionStatusManager(capabilitiesService);
mssqlConnectionProvider = TypeMoq.Mock.ofType(ConnectionProviderStub);
otherConnectionProvider = TypeMoq.Mock.ofType(ConnectionProviderStub);
connectionDialogService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), undefined)).returns(() => TPromise.as(none));
connectionDialogService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), undefined, undefined)).returns(() => TPromise.as(none));
connectionDialogService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => TPromise.as(none));
connectionDialogService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), undefined, TypeMoq.It.isAny())).returns(() => TPromise.as(none));
connectionStore.setup(x => x.addActiveConnection(TypeMoq.It.isAny())).returns(() => Promise.resolve());
connectionStore.setup(x => x.saveProfile(TypeMoq.It.isAny())).returns(() => Promise.resolve(connectionProfile));
workbenchEditorService.setup(x => x.openEditor(undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => TPromise.as(undefined));
editorGroupService.setup(x => x.getStacksModel()).returns(() => undefined);
connectionStore.setup(x => x.addSavedPassword(TypeMoq.It.is<IConnectionProfile>(
c => c.serverName === connectionProfile.serverName))).returns(() => Promise.resolve({ profile: connectionProfile, savedCred: true }));
connectionStore.setup(x => x.addSavedPassword(TypeMoq.It.is<IConnectionProfile>(
c => c.serverName === connectionProfileWithEmptySavedPassword.serverName))).returns(
() => Promise.resolve({ profile: connectionProfileWithEmptySavedPassword, savedCred: true }));
connectionStore.setup(x => x.addSavedPassword(TypeMoq.It.is<IConnectionProfile>(
c => c.serverName === connectionProfileWithEmptyUnsavedPassword.serverName))).returns(
() => Promise.resolve({ profile: connectionProfileWithEmptyUnsavedPassword, savedCred: false }));
connectionStore.setup(x => x.isPasswordRequired(TypeMoq.It.isAny())).returns(() => true);
mssqlConnectionProvider.setup(x => x.connect(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => undefined);
otherConnectionProvider.setup(x => x.connect(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => undefined);
// setup configuration to return a config that can be modified later.
workspaceConfigurationServiceMock = TypeMoq.Mock.ofType(WorkspaceConfigurationTestService);
workspaceConfigurationServiceMock.setup(x => x.getConfiguration(Constants.sqlConfigSectionName))
.returns(() => configResult);
connectionManagementService = createConnectionManagementService();
connectionManagementService.registerProvider('MSSQL', mssqlConnectionProvider.object);
});
function createConnectionManagementService(): ConnectionManagementService {
let connectionManagementService = new ConnectionManagementService(
undefined,
connectionStore.object,
connectionDialogService.object,
undefined,
undefined,
undefined,
workbenchEditorService.object,
undefined,
undefined,
undefined,
undefined,
workspaceConfigurationServiceMock.object,
undefined,
capabilitiesService,
undefined,
editorGroupService.object,
undefined,
undefined,
undefined,
undefined
);
return connectionManagementService;
}
function verifyShowDialog(connectionProfile: IConnectionProfile, connectionType: ConnectionType, uri: string, error?: string, didShow: boolean = true): void {
if (connectionProfile) {
connectionDialogService.verify(x => x.showDialog(
TypeMoq.It.isAny(),
TypeMoq.It.is<INewConnectionParams>(p => p.connectionType === connectionType && (uri === undefined || p.input.uri === uri)),
TypeMoq.It.is<IConnectionProfile>(c => c.serverName === connectionProfile.serverName), error),
didShow ? TypeMoq.Times.once() : TypeMoq.Times.never());
} else {
connectionDialogService.verify(x => x.showDialog(
TypeMoq.It.isAny(),
TypeMoq.It.is<INewConnectionParams>(p => p.connectionType === connectionType && ((uri === undefined && p.input === undefined) || p.input.uri === uri)),
undefined, error), didShow ? TypeMoq.Times.once() : TypeMoq.Times.never());
}
}
function verifyOptions(options?: IConnectionCompletionOptions, fromDialog?: boolean): void {
if (options) {
if (options.saveTheConnection) {
connectionStore.verify(x => x.saveProfile(TypeMoq.It.isAny()), TypeMoq.Times.once());
}
if (options.showDashboard) {
workbenchEditorService.verify(x => x.openEditor(undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
}
}
if (fromDialog !== undefined && !fromDialog) {
connectionStore.verify(x => x.addSavedPassword(TypeMoq.It.isAny()), TypeMoq.Times.once());
}
}
function connect(uri: string, options?: IConnectionCompletionOptions, fromDialog?: boolean, connection?: IConnectionProfile, error?: string): Promise<IConnectionResult> {
let connectionToUse = connection ? connection : connectionProfile;
return new Promise<IConnectionResult>((resolve, reject) => {
let id = connectionToUse.getOptionsKey();
let defaultUri = 'connection://' + (id ? id : connection.serverName + ':' + connection.databaseName);
connectionManagementService.onConnectionRequestSent(() => {
let info: data.ConnectionInfoSummary = {
connectionId: error ? undefined : 'id',
connectionSummary: {
databaseName: connectionToUse.databaseName,
serverName: connectionToUse.serverName,
userName: connectionToUse.userName
},
errorMessage: error,
errorNumber: undefined,
messages: error,
ownerUri: uri ? uri : defaultUri,
serverInfo: undefined
};
connectionManagementService.onConnectionComplete(0, info);
});
connectionManagementService.cancelConnectionForUri(uri).then(() => {
if (fromDialog) {
resolve(connectionManagementService.connectAndSaveProfile(connectionToUse, uri, options));
} else {
resolve(connectionManagementService.connect(connectionToUse, uri, options));
}
});
});
}
test('showConnectionDialog should open the dialog with default type given no parameters', done => {
connectionManagementService.showConnectionDialog().then(() => {
verifyShowDialog(undefined, ConnectionType.default, undefined);
done();
}).catch(err => {
done(err);
});
});
test('showConnectionDialog should open the dialog with given type given valid input', done => {
let params: INewConnectionParams = {
connectionType: ConnectionType.editor,
input: {
onConnectReject: undefined,
onConnectStart: undefined,
onDisconnect: undefined,
onConnectSuccess: undefined,
uri: 'Editor Uri'
},
runQueryOnCompletion: RunQueryOnConnectionMode.executeQuery
};
connectionManagementService.showConnectionDialog(params).then(() => {
verifyShowDialog(undefined, params.connectionType, params.input.uri);
done();
}).catch(err => {
done(err);
});
});
test('showConnectionDialog should pass the model to the dialog if there is a model assigned to the uri', done => {
let params: INewConnectionParams = {
connectionType: ConnectionType.editor,
input: {
onConnectReject: undefined,
onConnectStart: undefined,
onDisconnect: undefined,
onConnectSuccess: undefined,
uri: 'Editor Uri'
},
runQueryOnCompletion: RunQueryOnConnectionMode.executeQuery
};
connect(params.input.uri).then(() => {
let saveConnection = connectionManagementService.getConnectionProfile(params.input.uri);
assert.notEqual(saveConnection, undefined, `profile was not added to the connections`);
assert.equal(saveConnection.serverName, connectionProfile.serverName, `Server names are different`);
connectionManagementService.showConnectionDialog(params).then(() => {
verifyShowDialog(connectionProfile, params.connectionType, params.input.uri);
done();
}).catch(err => {
done(err);
});
});
});
test('connect should save profile given options with saveProfile set to true', done => {
let uri: string = 'Editor Uri';
let options: IConnectionCompletionOptions = {
params: undefined,
saveTheConnection: true,
showDashboard: false,
showConnectionDialogOnError: false,
showFirewallRuleOnError: false
};
connect(uri, options).then(() => {
verifyOptions(options);
done();
}).catch(err => {
done(err);
});
});
/* Andresse 10/5/17 commented this test out since it was only working before my changes by the chance of how Promises work
If we want to continue to test this, the connection logic needs to be rewritten to actually wait for everything to be done before it resolves */
// test('connect should show dashboard given options with showDashboard set to true', done => {
// let uri: string = 'Editor Uri';
// let options: IConnectionCompletionOptions = {
// params: undefined,
// saveTheConnection: false,
// showDashboard: true,
// showConnectionDialogOnError: false
// };
// connect(uri, options).then(() => {
// verifyOptions(options);
// done();
// }).catch(err => {
// done(err);
// });
// });
test('connect should pass the params in options to onConnectSuccess callback', done => {
let uri: string = 'Editor Uri';
let paramsInOnConnectSuccess: INewConnectionParams;
let options: IConnectionCompletionOptions = {
params: {
connectionType: ConnectionType.editor,
input: {
onConnectSuccess: (params?: INewConnectionParams) => {
paramsInOnConnectSuccess = params;
},
onConnectReject: undefined,
onConnectStart: undefined,
onDisconnect: undefined,
uri: uri
},
querySelection: undefined,
runQueryOnCompletion: RunQueryOnConnectionMode.none
},
saveTheConnection: true,
showDashboard: false,
showConnectionDialogOnError: true,
showFirewallRuleOnError: false
};
connect(uri, options).then(() => {
verifyOptions(options);
assert.notEqual(paramsInOnConnectSuccess, undefined);
assert.equal(paramsInOnConnectSuccess.connectionType, options.params.connectionType);
done();
}).catch(err => {
done(err);
});
});
test('connectAndSaveProfile should show not load the password', done => {
let uri: string = 'Editor Uri';
let options: IConnectionCompletionOptions = undefined;
connect(uri, options, true).then(() => {
verifyOptions(options, true);
done();
}).catch(err => {
done(err);
});
});
test('connect with undefined uri and options should connect using the default uri', done => {
let uri = undefined;
let options: IConnectionCompletionOptions = undefined;
connect(uri, options).then(() => {
assert.equal(connectionManagementService.isProfileConnected(connectionProfile), true);
done();
}).catch(err => {
done(err);
});
});
test('failed connection should open the dialog if connection fails', done => {
let uri = undefined;
let error: string = 'error';
let expectedConnection: boolean = false;
let expectedError: string = error;
let options: IConnectionCompletionOptions = {
params: undefined,
saveTheConnection: false,
showDashboard: false,
showConnectionDialogOnError: true,
showFirewallRuleOnError: false
};
connect(uri, options, false, connectionProfile, error).then(result => {
assert.equal(result.connected, expectedConnection);
assert.equal(result.errorMessage, expectedError);
verifyShowDialog(connectionProfile, ConnectionType.default, uri, error);
done();
}).catch(err => {
done(err);
});
});
test('failed connection should not open the dialog if the option is set to false even if connection fails', done => {
let uri = undefined;
let error: string = 'error when options set to false';
let expectedConnection: boolean = false;
let expectedError: string = error;
let options: IConnectionCompletionOptions = {
params: undefined,
saveTheConnection: false,
showDashboard: false,
showConnectionDialogOnError: false,
showFirewallRuleOnError: false
};
connect(uri, options, false, connectionProfile, error).then(result => {
assert.equal(result.connected, expectedConnection);
assert.equal(result.errorMessage, expectedError);
// TODO: not sure how to verify not called
done();
}).catch(err => {
done(err);
});
});
test('connect when password is empty and unsaved should open the dialog', done => {
let uri = undefined;
let expectedConnection: boolean = false;
let expectedError: string = undefined;
let options: IConnectionCompletionOptions = {
params: undefined,
saveTheConnection: false,
showDashboard: false,
showConnectionDialogOnError: true,
showFirewallRuleOnError: false
};
connect(uri, options, false, connectionProfileWithEmptyUnsavedPassword).then(result => {
assert.equal(result.connected, expectedConnection);
assert.equal(result.errorMessage, expectedError);
verifyShowDialog(connectionProfileWithEmptyUnsavedPassword, ConnectionType.default, uri, expectedError);
done();
}).catch(err => {
done(err);
});
});
test('connect when password is empty and saved should not open the dialog', done => {
let uri = undefined;
let expectedConnection: boolean = true;
let expectedError: string = undefined;
let options: IConnectionCompletionOptions = {
params: undefined,
saveTheConnection: false,
showDashboard: false,
showConnectionDialogOnError: true,
showFirewallRuleOnError: false
};
connect(uri, options, false, connectionProfileWithEmptySavedPassword).then(result => {
assert.equal(result.connected, expectedConnection);
assert.equal(result.errorMessage, expectedError);
verifyShowDialog(connectionProfileWithEmptySavedPassword, ConnectionType.default, uri, expectedError, false);
done();
}).catch(err => {
done(err);
});
});
test('connect from editor when empty password when it is required and saved should not open the dialog', done => {
let uri = 'editor 3';
let expectedConnection: boolean = true;
let expectedError: string = undefined;
let options: IConnectionCompletionOptions = {
params: {
connectionType: ConnectionType.editor,
input: {
onConnectSuccess: undefined,
onConnectReject: undefined,
onConnectStart: undefined,
onDisconnect: undefined,
uri: uri
},
querySelection: undefined,
runQueryOnCompletion: RunQueryOnConnectionMode.none
},
saveTheConnection: true,
showDashboard: false,
showConnectionDialogOnError: true,
showFirewallRuleOnError: false
};
connect(uri, options, false, connectionProfileWithEmptySavedPassword).then(result => {
assert.equal(result.connected, expectedConnection);
assert.equal(result.errorMessage, expectedError);
verifyShowDialog(connectionProfileWithEmptySavedPassword, ConnectionType.editor, uri, expectedError, false);
done();
}).catch(err => {
done(err);
});
});
test('doChangeLanguageFlavor should throw on unknown provider', done => {
// given a provider that will never exist
let invalidProvider = 'notaprovider';
// when I call doChangeLanguageFlavor
// Then I expect it to throw
assert.throws(() => connectionManagementService.doChangeLanguageFlavor('file://my.sql', 'sql', invalidProvider));
done();
});
test('doChangeLanguageFlavor should send event for known provider', done => {
// given a provider that is registered
let uri = 'file://my.sql';
let language = 'sql';
let flavor = 'MSSQL';
// when I call doChangeLanguageFlavor
try {
let called = false;
connectionManagementService.onLanguageFlavorChanged((changeParams: data.DidChangeLanguageFlavorParams) => {
called = true;
assert.equal(changeParams.uri, uri);
assert.equal(changeParams.language, language);
assert.equal(changeParams.flavor, flavor);
});
connectionManagementService.doChangeLanguageFlavor(uri, language, flavor);
assert.ok(called, 'expected onLanguageFlavorChanged event to be sent');
done();
} catch (error) {
done(error);
}
});
test('ensureDefaultLanguageFlavor should not send event if uri is connected', done => {
let uri: string = 'Editor Uri';
let options: IConnectionCompletionOptions = {
params: undefined,
saveTheConnection: false,
showDashboard: false,
showConnectionDialogOnError: false,
showFirewallRuleOnError: false
};
let connectionManagementService = createConnectionManagementService();
let called = false;
connectionManagementService.onLanguageFlavorChanged((changeParams: data.DidChangeLanguageFlavorParams) => {
called = true;
});
connect(uri, options).then(() => {
connectionManagementService.ensureDefaultLanguageFlavor(uri);
assert.equal(called, false, 'do not expect flavor change to be called');
done();
}).catch(err => {
done(err);
});
});
test('getConnectionId returns the URI associated with a connection that has had its database filled in', done => {
// Set up the connection management service with a connection corresponding to a default database
let dbName = 'master';
let serverName = 'test_server';
let userName = 'test_user';
let connectionProfileWithoutDb: IConnectionProfile = Object.assign(connectionProfile,
{ serverName: serverName, databaseName: '', userName: userName, getOptionsKey: () => undefined });
let connectionProfileWithDb: IConnectionProfile = Object.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);
connect(ownerUri, undefined, false, connectionProfileWithoutDb).then(() => {
try {
// If I get the URI for the connection with or without a database from the connection management service
let actualUriWithDb = connectionManagementService.getConnectionId(connectionProfileWithDb);
let actualUriWithoutDb = connectionManagementService.getConnectionId(connectionProfileWithoutDb);
// Then the retrieved URIs should match the one on the connection
let expectedUri = Utils.generateUri(connectionProfileWithoutDb);
assert.equal(actualUriWithDb, expectedUri);
assert.equal(actualUriWithoutDb, expectedUri);
done();
} catch (err) {
done(err);
}
}, err => done(err));
});
});

View File

@@ -0,0 +1,206 @@
/*---------------------------------------------------------------------------------------------
* 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 { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
import { IConnectionProfile, IConnectionProfileStore } from 'sql/parts/connection/common/interfaces';
import data = require('data');
import * as assert from 'assert';
suite('SQL ConnectionProfileInfo tests', () => {
let msSQLCapabilities: data.DataProtocolServerCapabilities;
let connectionProfile: IConnectionProfile = {
serverName: 'new server',
databaseName: 'database',
userName: 'user',
password: 'password',
authenticationType: '',
savePassword: true,
groupFullName: 'g2/g2-2',
groupId: 'group id',
getOptionsKey: undefined,
matches: undefined,
providerName: 'MSSQL',
options: {},
saveProfile: true,
id: undefined
};
let storedProfile: IConnectionProfileStore = {
groupId: 'groupId',
id: 'id',
options: {
serverName: 'new server',
databaseName: 'database',
userName: 'user',
password: 'password',
authenticationType: ''
},
providerName: 'MSSQL',
savePassword: true
};
setup(() => {
let capabilities: data.DataProtocolServerCapabilities[] = [];
let connectionProvider: data.ConnectionProviderOptions = {
options: [
{
name: 'serverName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 0,
valueType: 0
},
{
name: 'databaseName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 1,
valueType: 0
},
{
name: 'userName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 3,
valueType: 0
},
{
name: 'authenticationType',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 2,
valueType: 0
},
{
name: 'password',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 4,
valueType: 0
}
]
};
msSQLCapabilities = {
protocolVersion: '1',
providerName: 'MSSQL',
providerDisplayName: 'MSSQL',
connectionProvider: connectionProvider,
adminServicesProvider: undefined,
features: undefined
};
capabilities.push(msSQLCapabilities);
});
test('set properties should set the values correctly', () => {
let conn = new ConnectionProfile(msSQLCapabilities, undefined);
assert.equal(conn.serverName, undefined);
conn.serverName = connectionProfile.serverName;
conn.databaseName = connectionProfile.databaseName;
conn.authenticationType = connectionProfile.authenticationType;
conn.password = connectionProfile.password;
conn.userName = connectionProfile.userName;
conn.groupId = connectionProfile.groupId;
conn.groupFullName = connectionProfile.groupFullName;
conn.savePassword = connectionProfile.savePassword;
assert.equal(conn.serverName, connectionProfile.serverName);
assert.equal(conn.databaseName, connectionProfile.databaseName);
assert.equal(conn.authenticationType, connectionProfile.authenticationType);
assert.equal(conn.password, connectionProfile.password);
assert.equal(conn.userName, connectionProfile.userName);
assert.equal(conn.groupId, connectionProfile.groupId);
assert.equal(conn.groupFullName, connectionProfile.groupFullName);
assert.equal(conn.savePassword, connectionProfile.savePassword);
});
test('constructor should initialize the options given a valid model', () => {
let conn = new ConnectionProfile(msSQLCapabilities, connectionProfile);
assert.equal(conn.serverName, connectionProfile.serverName);
assert.equal(conn.databaseName, connectionProfile.databaseName);
assert.equal(conn.authenticationType, connectionProfile.authenticationType);
assert.equal(conn.password, connectionProfile.password);
assert.equal(conn.userName, connectionProfile.userName);
assert.equal(conn.groupId, connectionProfile.groupId);
assert.equal(conn.groupFullName, connectionProfile.groupFullName);
assert.equal(conn.savePassword, connectionProfile.savePassword);
});
test('getOptionsKey should create a valid unique id', () => {
let conn = new ConnectionProfile(msSQLCapabilities, connectionProfile);
let expectedId = 'providerName:MSSQL|authenticationType:|databaseName:database|serverName:new server|userName:user|databaseDisplayName:database|group:group id';
let id = conn.getOptionsKey();
assert.equal(id, expectedId);
});
test('createFromStoredProfile should create connection profile from stored profile', () => {
let savedProfile = storedProfile;
let connectionProfile = ConnectionProfile.createFromStoredProfile(savedProfile, msSQLCapabilities);
assert.equal(savedProfile.groupId, connectionProfile.groupId);
assert.deepEqual(savedProfile.options, connectionProfile.options);
assert.deepEqual(savedProfile.providerName, connectionProfile.providerName);
assert.deepEqual(savedProfile.savePassword, connectionProfile.savePassword);
assert.deepEqual(savedProfile.id, connectionProfile.id);
});
test('createFromStoredProfile should set the id to new guid if not set in stored profile', () => {
let savedProfile = Object.assign({}, storedProfile, { id: undefined });
let connectionProfile = ConnectionProfile.createFromStoredProfile(savedProfile, msSQLCapabilities);
assert.equal(savedProfile.groupId, connectionProfile.groupId);
assert.deepEqual(savedProfile.options, connectionProfile.options);
assert.deepEqual(savedProfile.providerName, connectionProfile.providerName);
assert.equal(savedProfile.savePassword, connectionProfile.savePassword);
assert.notEqual(connectionProfile.id, undefined);
assert.equal(savedProfile.id, undefined);
});
test('withoutPassword should create a new instance without password', () => {
let conn = new ConnectionProfile(msSQLCapabilities, connectionProfile);
assert.notEqual(conn.password, '');
let withoutPassword = conn.withoutPassword();
assert.equal(withoutPassword.password, '');
});
test('unique id should not include password', () => {
let conn = new ConnectionProfile(msSQLCapabilities, connectionProfile);
let withoutPassword = conn.withoutPassword();
assert.equal(withoutPassword.getOptionsKey(), conn.getOptionsKey());
});
test('cloneWithDatabase should create new profile with new id', () => {
let conn = new ConnectionProfile(msSQLCapabilities, connectionProfile);
let newProfile = conn.cloneWithDatabase('new db');
assert.notEqual(newProfile.id, conn.id);
assert.equal(newProfile.databaseName, 'new db');
});
});

View File

@@ -0,0 +1,148 @@
/*---------------------------------------------------------------------------------------------
* 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 { ConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup';
import * as assert from 'assert';
suite('SQL ConnectionProfileGroup tests', () => {
let root: ConnectionProfileGroup;
let Groups1 = 'G1';
let Groups11 = 'G11';
let Groups2 = 'G2';
let group1Node: ConnectionProfileGroup;
let group11Node: ConnectionProfileGroup;
let group2Node: ConnectionProfileGroup;
setup(() => {
root = new ConnectionProfileGroup(ConnectionProfileGroup.RootGroupName, undefined, ConnectionProfileGroup.RootGroupName, undefined, undefined);
group1Node = new ConnectionProfileGroup(Groups1, root, Groups1, undefined, undefined);
group2Node = new ConnectionProfileGroup(Groups2, root, Groups2, undefined, undefined);
group11Node = new ConnectionProfileGroup(Groups11, root, Groups11, undefined, undefined);
root.addGroups([group1Node]);
group1Node.addGroups([group11Node]);
root.addGroups([group2Node]);
});
test('Root name should be returned as empty string', () => {
assert.equal(root.name, '');
});
test('Fullname should return the group full name correctly', () => {
assert.equal(group1Node.fullName, 'G1');
assert.equal(group2Node.fullName, 'G2');
assert.equal(group11Node.fullName, 'G1/G11');
});
test('getGroupFullNameParts should return a list With ROOT in it given an empty string', () => {
let groupFullName: string = '';
let expected: string[] = [ConnectionProfileGroup.RootGroupName];
let actual = ConnectionProfileGroup.getGroupFullNameParts(groupFullName);
assert.deepEqual(actual, expected);
});
test('getGroupFullNameParts should return a list With ROOT in it given null', () => {
let groupFullName: string = undefined;
let expected: string[] = [ConnectionProfileGroup.RootGroupName];
let actual = ConnectionProfileGroup.getGroupFullNameParts(groupFullName);
assert.deepEqual(actual, expected);
});
test('getGroupFullNameParts should return a list With ROOT in it given /', () => {
let groupFullName: string = '/';
let expected: string[] = [ConnectionProfileGroup.RootGroupName];
let actual = ConnectionProfileGroup.getGroupFullNameParts(groupFullName);
assert.deepEqual(actual, expected);
});
test('getGroupFullNameParts should add ROOT as first item if not added already and string starts with /', () => {
let groupFullName: string = '/Groups/Group1';
let expected: string[] = [ConnectionProfileGroup.RootGroupName, 'Groups', 'Group1'];
let actual = ConnectionProfileGroup.getGroupFullNameParts(groupFullName);
assert.deepEqual(actual, expected);
});
test('getGroupFullNameParts should add ROOT as first item if not added already', () => {
let groupFullName: string = 'Groups/Group1';
let expected: string[] = [ConnectionProfileGroup.RootGroupName, 'Groups', 'Group1'];
let actual = ConnectionProfileGroup.getGroupFullNameParts(groupFullName);
assert.deepEqual(actual, expected);
});
test('getGroupFullNameParts should not add ROOT if already added and string starts with /', () => {
let groupFullName: string = '/ROOT/Groups/Group1';
let expected: string[] = [ConnectionProfileGroup.RootGroupName, 'Groups', 'Group1'];
let actual = ConnectionProfileGroup.getGroupFullNameParts(groupFullName);
assert.deepEqual(actual, expected);
});
test('getGroupFullNameParts should not add ROOT if already added', () => {
let groupFullName: string = 'ROOT/Groups/Group1';
let expected: string[] = [ConnectionProfileGroup.RootGroupName, 'Groups', 'Group1'];
let actual = ConnectionProfileGroup.getGroupFullNameParts(groupFullName);
assert.deepEqual(actual, expected);
});
test('getGroupFullNameParts should not add ROOT if already added and it is not uppercase', () => {
let groupFullName: string = 'rOOT/Groups/Group1';
let expected: string[] = [ConnectionProfileGroup.RootGroupName, 'Groups', 'Group1'];
let actual = ConnectionProfileGroup.getGroupFullNameParts(groupFullName);
assert.deepEqual(actual, expected);
});
test('isRoot should return true given empty string', () => {
let name: string = '';
let expected: boolean = true;
let actual = ConnectionProfileGroup.isRoot(name);
assert.deepEqual(actual, expected);
});
test('isRoot should return true given null', () => {
let name: string = undefined;
let expected: boolean = true;
let actual = ConnectionProfileGroup.isRoot(name);
assert.deepEqual(actual, expected);
});
test('isRoot should return true given /', () => {
let name: string = '/';
let expected: boolean = true;
let actual = ConnectionProfileGroup.isRoot(name);
assert.deepEqual(actual, expected);
});
test('isRoot should return true given root', () => {
let name: string = 'root';
let expected: boolean = true;
let actual = ConnectionProfileGroup.isRoot(name);
assert.deepEqual(actual, expected);
});
test('sameGroupName should return true given root', () => {
let name1: string = '/';
let name2: string = '';
let expected: boolean = true;
let actual = ConnectionProfileGroup.sameGroupName(name1, name2);
assert.deepEqual(actual, expected);
});
test('sameGroupName should return true given same group names', () => {
let name1: string = '/group1';
let name2: string = '/Group1';
let expected: boolean = true;
let actual = ConnectionProfileGroup.sameGroupName(name1, name2);
assert.deepEqual(actual, expected);
});
test('sameGroupName should return false given two different groups', () => {
let name1: string = '/';
let name2: string = '/Group1';
let expected: boolean = false;
let actual = ConnectionProfileGroup.sameGroupName(name1, name2);
assert.deepEqual(actual, expected);
});
});

View File

@@ -0,0 +1,239 @@
/*---------------------------------------------------------------------------------------------
* 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 assert from 'assert';
import data = require('data');
import { ConnectionStatusManager } from 'sql/parts/connection/common/connectionStatusManager';
import * as Utils from 'sql/parts/connection/common/utils';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { CapabilitiesTestService } from 'sqltest/stubs/capabilitiesTestService';
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
let connections: ConnectionStatusManager;
let capabilitiesService: CapabilitiesTestService;
let connectionProfileObject: ConnectionProfile;
let connectionProfile: IConnectionProfile = {
serverName: 'new server',
databaseName: 'database',
userName: 'user',
password: 'password',
authenticationType: '',
savePassword: true,
groupFullName: 'g2/g2-2',
groupId: 'group id',
getOptionsKey: () => 'connection1',
matches: undefined,
providerName: 'MSSQL',
options: {},
saveProfile: true,
id: undefined
};
let editorConnectionProfile: IConnectionProfile = {
serverName: 'new server',
databaseName: 'database',
userName: 'user',
password: 'password',
authenticationType: '',
savePassword: true,
groupFullName: 'g2/g2-2',
groupId: 'group id',
getOptionsKey: () => 'connection2',
matches: undefined,
providerName: 'MSSQL',
options: {},
saveProfile: true,
id: undefined
};
let connectionProfileWithoutDbName: IConnectionProfile = {
serverName: 'new server',
databaseName: '',
userName: 'user',
password: 'password',
authenticationType: '',
savePassword: true,
groupFullName: 'g2/g2-2',
groupId: 'group id',
getOptionsKey: () => 'connection1',
matches: undefined,
providerName: 'MSSQL',
options: {},
saveProfile: true,
id: undefined
};
let connection1Id: string;
let connection2Id: string;
let connection3Id: string;
suite('SQL ConnectionStatusManager tests', () => {
setup(() => {
capabilitiesService = new CapabilitiesTestService();
connectionProfileObject = new ConnectionProfile(capabilitiesService.getCapabilities().find(x => x.providerName === 'MSSQL')
, connectionProfile);
connections = new ConnectionStatusManager(capabilitiesService);
connection1Id = Utils.generateUri(connectionProfile);
connection2Id = 'connection2Id';
connection3Id = 'connection3Id';
connections.addConnection(connectionProfile, connection1Id);
connections.addConnection(editorConnectionProfile, connection2Id);
connections.addConnection(connectionProfileWithoutDbName, connection3Id);
});
test('findConnection should return undefined given invalid id', () => {
let id: string = 'invalid id';
let expected = undefined;
let actual = connections.findConnection(id);
assert.equal(actual, expected);
});
test('findConnection should return connection given valid id', () => {
let id: string = connection1Id;
let expected = connectionProfileObject;
let actual = connections.findConnection(id);
assert.deepEqual(actual.connectionProfile, expected);
});
test('getConnectionProfile should return undefined given invalid id', () => {
let id: string = 'invalid id';
let expected = undefined;
let actual = connections.getConnectionProfile(id);
assert.equal(actual, expected);
});
test('getConnectionProfile should return connection given valid id', () => {
let id: string = connection1Id;
let expected = connectionProfileObject;
let actual = connections.getConnectionProfile(id);
assert.deepEqual(actual, expected);
});
test('hasConnection should return false given invalid id', () => {
let id: string = 'invalid id';
let expected = false;
let actual = connections.hasConnection(id);
assert.equal(actual, expected);
});
test('hasConnection should return true given valid id', () => {
let id: string = connection1Id;
let expected = true;
let actual = connections.hasConnection(id);
assert.equal(actual, expected);
});
test('addConnection should set connecting to true', () => {
let expected = true;
let summary: data.ConnectionInfoSummary = {
ownerUri: connection1Id,
connectionId: connection1Id,
messages: undefined,
errorMessage: undefined,
errorNumber: undefined,
serverInfo: undefined,
connectionSummary: undefined
};
connections.onConnectionComplete(summary);
let actual = connections.addConnection(connectionProfile, connection1Id).connecting;
assert.equal(actual, expected);
});
test('onConnectionComplete should set connecting to false', () => {
let expected = false;
let summary: data.ConnectionInfoSummary = {
ownerUri: connection1Id,
connectionId: connection1Id,
messages: undefined,
errorMessage: undefined,
errorNumber: undefined,
serverInfo: undefined,
connectionSummary: undefined
};
connections.onConnectionComplete(summary);
let actual = connections.findConnection(connection1Id).connecting;
assert.equal(actual, expected);
actual = connections.isConnecting(connection1Id);
assert.equal(actual, expected);
});
test('updateConnection should update the connection info', () => {
let expected = connectionProfile.groupId + '1';
let expectedConnectionId = 'new id';
connections.addConnection(connectionProfile, connection1Id);
let updatedConnection = Object.assign({}, connectionProfile, { groupId: expected, getOptionsKey: () => connectionProfile.getOptionsKey() + expected, id: expectedConnectionId });
let actualId = connections.updateConnectionProfile(updatedConnection, connection1Id);
let newId = Utils.generateUri(updatedConnection);
let actual = connections.getConnectionProfile(newId).groupId;
let actualConnectionId = connections.getConnectionProfile(newId).id;
assert.equal(actual, expected);
assert.equal(actualId, newId);
assert.equal(actualConnectionId, expectedConnectionId);
});
test('updateDatabaseName should update the database name in connection', () => {
let dbName: string = 'db name';
let summary: data.ConnectionInfoSummary = {
connectionSummary: {
databaseName: dbName,
serverName: undefined,
userName: undefined
}
, ownerUri: connection3Id,
connectionId: 'connection id',
errorMessage: undefined,
errorNumber: undefined,
messages: undefined,
serverInfo: undefined
};
//The original connection didn't have database name
let connectionStatus = connections.findConnection(connection3Id);
connectionStatus.connectionProfile.databaseName = '';
//Verify database name changed after connection is complete
connections.updateDatabaseName(summary);
connectionStatus = connections.findConnection(connection3Id);
assert.equal(connectionStatus.connectionProfile.databaseName, dbName);
});
test('getOriginalOwnerUri should return the original uri given uri with db name', () => {
let dbName: string = 'db name';
let summary: data.ConnectionInfoSummary = {
connectionSummary: {
databaseName: dbName,
serverName: undefined,
userName: undefined
}
, ownerUri: connection3Id,
connectionId: 'connection id',
errorMessage: undefined,
errorNumber: undefined,
messages: undefined,
serverInfo: undefined
};
//The original connection didn't have database name
let connectionStatus = connections.findConnection(connection3Id);
connectionStatus.connectionProfile.databaseName = '';
//Verify database name changed after connection is complete
connections.updateDatabaseName(summary);
connectionStatus = connections.findConnection(connection3Id);
let ownerUriWithDbName = Utils.generateUriWithPrefix(connectionStatus.connectionProfile, 'connection://');
//The uri assigned to connection without db name should be the original one
let connectionWitDbStatus = connections.getOriginalOwnerUri(ownerUriWithDbName);
assert.equal(connectionWitDbStatus, connection3Id);
});
test('getOriginalOwnerUri should return given uri if the original uri is the same as the given uri', () => {
let connectionStatus = connections.getOriginalOwnerUri(connection2Id);
assert.equal(connectionStatus, connection2Id);
});
});

View File

@@ -0,0 +1,459 @@
/*---------------------------------------------------------------------------------------------
* 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 } from 'sql/parts/connection/common/connectionConfig';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { WorkspaceConfigurationTestService } from 'sqltest/stubs/workspaceConfigurationTestService';
import * as Constants from 'sql/parts/connection/common/constants';
import { StorageTestService } from 'sqltest/stubs/storageTestService';
import { ConnectionStore } from 'sql/parts/connection/common/connectionStore';
import { CredentialsService } from 'sql/services/credentials/credentialsService';
import * as assert from 'assert';
import { Memento } from 'vs/workbench/common/memento';
import { CapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
import * as data from 'data';
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
import { Emitter } from 'vs/base/common/event';
import { IConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup';
suite('SQL ConnectionStore tests', () => {
let defaultNamedProfile: IConnectionProfile;
let defaultUnnamedProfile: IConnectionProfile;
let context: TypeMoq.Mock<Memento>;
let credentialStore: TypeMoq.Mock<CredentialsService>;
let connectionConfig: TypeMoq.Mock<ConnectionConfig>;
let workspaceConfigurationServiceMock: TypeMoq.Mock<WorkspaceConfigurationTestService>;
let storageServiceMock: TypeMoq.Mock<StorageTestService>;
let capabilitiesService: TypeMoq.Mock<CapabilitiesService>;
let mementoArray: any = [];
let maxRecent = 5;
let msSQLCapabilities: data.DataProtocolServerCapabilities;
let defaultNamedConnectionProfile: ConnectionProfile;
let onProviderRegistered = new Emitter<data.DataProtocolServerCapabilities>();
setup(() => {
defaultNamedProfile = Object.assign({}, {
serverName: 'namedServer',
databaseName: 'bcd',
authenticationType: 'SqlLogin',
userName: 'cde',
password: 'asdf!@#$',
savePassword: true,
groupId: '',
groupFullName: '',
getOptionsKey: undefined,
matches: undefined,
providerName: 'MSSQL',
options: {},
saveProfile: true,
id: undefined
});
defaultUnnamedProfile = Object.assign({}, {
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
});
let momento = new Memento('ConnectionManagement');
context = TypeMoq.Mock.ofInstance(momento);
context.setup(x => x.getMemento(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => mementoArray);
credentialStore = TypeMoq.Mock.ofType(CredentialsService);
connectionConfig = TypeMoq.Mock.ofType(ConnectionConfig);
// setup configuration to return maxRecent for the #MRU items
let configResult: { [key: string]: any } = {};
configResult[Constants.configMaxRecentConnections] = maxRecent;
workspaceConfigurationServiceMock = TypeMoq.Mock.ofType(WorkspaceConfigurationTestService);
workspaceConfigurationServiceMock.setup(x => x.getConfiguration(Constants.sqlConfigSectionName))
.returns(() => configResult);
storageServiceMock = TypeMoq.Mock.ofType(StorageTestService);
capabilitiesService = TypeMoq.Mock.ofType(CapabilitiesService);
let capabilities: data.DataProtocolServerCapabilities[] = [];
let connectionProvider: data.ConnectionProviderOptions = {
options: [
{
name: 'serverName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 0,
valueType: 0
},
{
name: 'databaseName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 1,
valueType: 0
},
{
name: 'userName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 3,
valueType: 0
},
{
name: 'authenticationType',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 2,
valueType: 0
},
{
name: 'password',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 4,
valueType: 0
}
]
};
msSQLCapabilities = {
protocolVersion: '1',
providerName: 'MSSQL',
providerDisplayName: 'MSSQL',
connectionProvider: connectionProvider,
adminServicesProvider: undefined,
features: undefined
};
capabilities.push(msSQLCapabilities);
capabilitiesService.setup(x => x.getCapabilities()).returns(() => capabilities);
capabilitiesService.setup(x => x.onProviderRegisteredEvent).returns(() => onProviderRegistered.event);
connectionConfig.setup(x => x.getCapabilities('MSSQL')).returns(() => msSQLCapabilities);
let groups: IConnectionProfileGroup[] = [
{
id: 'root',
name: 'root',
parentId: '',
color: '',
description: ''
},
{
id: 'g1',
name: 'g1',
parentId: 'root',
color: 'blue',
description: 'g1'
}
];
connectionConfig.setup(x => x.getAllGroups()).returns(() => groups);
defaultNamedConnectionProfile = new ConnectionProfile(msSQLCapabilities, defaultNamedProfile);
});
test('addActiveConnection should limit recent connection saves to the MaxRecentConnections amount', (done) => {
// Given 5 is the max # creds
let numCreds = 6;
// setup memento for MRU to return a list we have access to
credentialStore.setup(x => x.saveCredential(TypeMoq.It.isAny(), TypeMoq.It.isAny()))
.returns(() => Promise.resolve(true));
// 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,
credentialStore.object, capabilitiesService.object, connectionConfig.object);
let promise = Promise.resolve();
for (let i = 0; i < numCreds; i++) {
let cred = Object.assign({}, defaultNamedProfile, { serverName: defaultNamedProfile.serverName + i });
let connectionProfile = new ConnectionProfile(msSQLCapabilities, cred);
promise = promise.then(() => {
return connectionStore.addActiveConnection(connectionProfile);
}).then(() => {
let current = connectionStore.getRecentlyUsedConnections();
if (i >= maxRecent) {
assert.equal(current.length, maxRecent, `expect only top ${maxRecent} creds to be saved`);
} else {
assert.equal(current.length, i + 1, `expect all credentials to be saved ${current.length}|${i + 1} `);
}
assert.equal(current[0].serverName, cred.serverName, 'Expect most recently saved item to be first in list');
assert.ok(!current[0].password);
});
}
promise.then(() => {
credentialStore.verify(x => x.saveCredential(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.exactly(numCreds));
let recentConnections = connectionStore.getActiveConnections();
assert.equal(numCreds, recentConnections.length, `expect number of active connection ${numCreds}|${recentConnections.length} `);
done();
}, err => {
// Must call done here so test indicates it's finished if errors occur
done(err);
});
});
test('addActiveConnection should add same connection exactly once', (done) => {
// setup memento for MRU to return a list we have access to
credentialStore.setup(x => x.saveCredential(TypeMoq.It.isAny(), TypeMoq.It.isAny()))
.returns(() => Promise.resolve(true));
// 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,
credentialStore.object, capabilitiesService.object, connectionConfig.object);
connectionStore.clearActiveConnections();
connectionStore.clearRecentlyUsed();
let promise = Promise.resolve();
let cred = Object.assign({}, defaultNamedProfile, { serverName: defaultNamedProfile.serverName + 1 });
let connectionProfile = new ConnectionProfile(msSQLCapabilities, cred);
promise = promise.then(() => {
return connectionStore.addActiveConnection(defaultNamedConnectionProfile);
}).then(() => {
return connectionStore.addActiveConnection(connectionProfile);
}).then(() => {
return connectionStore.addActiveConnection(connectionProfile);
}).then(() => {
let current = connectionStore.getRecentlyUsedConnections();
assert.equal(current.length, 2, 'expect 2 unique credentials to have been added');
assert.equal(current[0].serverName, cred.serverName, 'Expect most recently saved item to be first in list');
assert.ok(!current[0].password);
}).then(() => done(), err => done(err));
});
test('addActiveConnection should save password to credential store', (done) => {
// Setup credential store to capture credentials sent to it
let capturedCreds: any;
credentialStore.setup(x => x.saveCredential(TypeMoq.It.isAny(), TypeMoq.It.isAny()))
.callback((cred: string, pass: any) => {
capturedCreds = {
'credentialId': cred,
'password': pass
};
})
.returns(() => Promise.resolve(true));
// Given we save 1 connection with password and multiple other connections without
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object);
connectionStore.clearActiveConnections();
connectionStore.clearRecentlyUsed();
let integratedCred = Object.assign({}, defaultNamedProfile, {
serverName: defaultNamedProfile.serverName + 'Integrated',
authenticationType: 'Integrated',
userName: '',
password: ''
});
let noPwdCred = Object.assign({}, defaultNamedProfile, {
serverName: defaultNamedProfile.serverName + 'NoPwd',
password: ''
});
let connectionProfile = new ConnectionProfile(msSQLCapabilities, defaultNamedProfile);
let expectedCredCount = 0;
let promise = Promise.resolve();
promise = promise.then(() => {
expectedCredCount++;
return connectionStore.addActiveConnection(connectionProfile);
}).then(() => {
let current = connectionStore.getRecentlyUsedConnections();
// Then verify that since its password based we save the password
credentialStore.verify(x => x.saveCredential(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
assert.strictEqual(capturedCreds.password, defaultNamedProfile.password);
let credId: string = capturedCreds.credentialId;
assert.ok(credId.includes(ConnectionStore.CRED_PROFILE_USER), 'Expect credential to be marked as an Profile cred');
assert.ok(!current[0].password);
}).then(() => {
// When add integrated auth connection
expectedCredCount++;
let integratedCredConnectionProfile = new ConnectionProfile(msSQLCapabilities, integratedCred);
return connectionStore.addActiveConnection(integratedCredConnectionProfile);
}).then(() => {
let current = connectionStore.getRecentlyUsedConnections();
// then expect no to have credential store called, but MRU count upped to 2
credentialStore.verify(x => x.saveCredential(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
assert.equal(current.length, expectedCredCount, `expect ${expectedCredCount} unique credentials to have been added`);
}).then(() => {
// When add connection without password
expectedCredCount++;
let noPwdCredConnectionProfile = new ConnectionProfile(msSQLCapabilities, noPwdCred);
return connectionStore.addActiveConnection(noPwdCredConnectionProfile);
}).then(() => {
let current = connectionStore.getRecentlyUsedConnections();
// then expect no to have credential store called, but MRU count upped to 3
credentialStore.verify(x => x.saveCredential(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
assert.equal(current.length, expectedCredCount, `expect ${expectedCredCount} unique credentials to have been added`);
}).then(() => done(), err => done(err));
});
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,
credentialStore.object, capabilitiesService.object, connectionConfig.object);
// When we clear the connections list and get the list of available connection items
connectionStore.clearActiveConnections();
connectionStore.clearRecentlyUsed();
// Expect no connection items
let result = connectionStore.getActiveConnections();
let expectedCount = 0; // 1 for create connection profile
assert.equal(result.length, expectedCount);
result = connectionStore.getRecentlyUsedConnections();
assert.equal(result.length, expectedCount);
// Then test is complete
done();
});
test('isPasswordRequired should return true for MSSQL SqlLogin', () => {
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object);
let expected: boolean = true;
let actual = connectionStore.isPasswordRequired(defaultNamedProfile);
assert.equal(expected, actual);
});
test('isPasswordRequired should return true for MSSQL SqlLogin for connection profile object', () => {
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object);
let connectionProfile = new ConnectionProfile(msSQLCapabilities, defaultNamedProfile);
let expected: boolean = true;
let actual = connectionStore.isPasswordRequired(connectionProfile);
assert.equal(expected, actual);
});
test('isPasswordRequired should return false if the password is not required in capabilities', () => {
let providerName: string = 'providername';
let connectionProvider: data.ConnectionProviderOptions = {
options: msSQLCapabilities.connectionProvider.options.map(o => {
if (o.name === 'password') {
o.isRequired = false;
}
return o;
})
};
let providerCapabilities = {
protocolVersion: '1',
providerName: providerName,
providerDisplayName: providerName,
connectionProvider: connectionProvider,
adminServicesProvider: undefined,
features: undefined
};
connectionConfig.setup(x => x.getCapabilities(providerName)).returns(() => providerCapabilities);
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object);
let connectionProfile: IConnectionProfile = Object.assign({}, defaultNamedProfile, { providerName: providerName });
let expected: boolean = false;
let actual = connectionStore.isPasswordRequired(connectionProfile);
assert.equal(expected, actual);
});
test('saveProfile should save the password after the profile is saved', done => {
let password: string = 'asdf!@#$';
let groupId: string = 'group id';
let connectionProfile: IConnectionProfile = Object.assign({}, defaultNamedProfile, { password: password });
let savedConnection: IConnectionProfile = Object.assign({}, connectionProfile, { groupId: groupId, password: '' });
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,
credentialStore.object, capabilitiesService.object, connectionConfig.object);
connectionStore.saveProfile(connectionProfile).then(profile => {
// add connection should be called with a profile without password
connectionConfig.verify(x => x.addConnection(TypeMoq.It.is<IConnectionProfile>(c => c.password === '')), TypeMoq.Times.once());
credentialStore.verify(x => x.saveCredential(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.once());
assert.equal(profile.password, password, 'The returned profile should still keep the password');
assert.equal(profile.groupId, groupId, 'Group id should be set in the profile');
done();
}).catch(err => {
assert.fail(err);
done(err);
});
});
test('addConnectionToMemento should not add duplicate items', () => {
let connectionStore = new ConnectionStore(storageServiceMock.object, context.object, undefined, workspaceConfigurationServiceMock.object,
credentialStore.object, capabilitiesService.object, connectionConfig.object);
let mementoKey = 'RECENT_CONNECTIONS2';
connectionStore.clearFromMemento(mementoKey);
let connectionProfile: IConnectionProfile = Object.assign({}, defaultNamedProfile);
connectionStore.addConnectionToMemento(connectionProfile, mementoKey);
connectionProfile = Object.assign({}, defaultNamedProfile, { authenticationType: 'Integrated', userName: '' });
connectionStore.addConnectionToMemento(connectionProfile, mementoKey);
let currentList = connectionStore.getConnectionsFromMemento(mementoKey);
assert.equal(currentList.length, 2, 'Adding same connection with different auth');
connectionProfile = Object.assign({}, defaultNamedProfile, { groupFullName: 'new group' });
connectionStore.addConnectionToMemento(connectionProfile, mementoKey);
currentList = connectionStore.getConnectionsFromMemento(mementoKey);
assert.equal(currentList.length, 3, 'Adding same connection with different group name');
connectionProfile = Object.assign({}, defaultNamedProfile,
{ groupFullName: defaultNamedProfile.groupFullName.toUpperCase() });
connectionStore.addConnectionToMemento(connectionProfile, mementoKey);
currentList = connectionStore.getConnectionsFromMemento(mementoKey);
assert.equal(currentList.length, 3, 'Adding same connection with same group name but uppercase');
connectionProfile = Object.assign({}, defaultNamedProfile,
{ groupFullName: '' });
connectionStore.addConnectionToMemento(connectionProfile, mementoKey);
currentList = connectionStore.getConnectionsFromMemento(mementoKey);
assert.equal(currentList.length, 3, 'Adding same connection with group empty string');
connectionProfile = Object.assign({}, defaultNamedProfile,
{ groupFullName: '/' });
connectionStore.addConnectionToMemento(connectionProfile, mementoKey);
currentList = connectionStore.getConnectionsFromMemento(mementoKey);
assert.equal(currentList.length, 3, 'Adding same connection with group /');
});
});

View File

@@ -0,0 +1,516 @@
/*---------------------------------------------------------------------------------------------
* 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 { TPromise } from 'vs/base/common/winjs.base';
import * as TypeMoq from 'typemoq';
import * as assert from 'assert';
import { ConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup';
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
import {
RefreshAction, AddServerAction, DeleteConnectionAction, DisconnectConnectionAction,
ActiveConnectionsFilterAction, RecentConnectionsFilterAction
}
from 'sql/parts/registeredServer/viewlet/connectionTreeAction';
import { TestConnectionManagementService } from 'sqltest/stubs/connectionManagementService.test';
import { ErrorMessageServiceStub } from 'sqltest/stubs/errorMessageServiceStub';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { ServerTreeView } from 'sql/parts/registeredServer/viewlet/serverTreeView';
import * as Constants from 'sql/parts/connection/common/constants';
import * as LocalizedConstants from 'sql/parts/connection/common/localizedConstants';
import { ObjectExplorerService, ObjectExplorerNodeEventArgs } from 'sql/parts/registeredServer/common/objectExplorerService';
import { TreeNode } from 'sql/parts/registeredServer/common/treeNode';
import { NodeType } from 'sql/parts/registeredServer/common/nodeType';
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
import { ServerTreeDataSource } from 'sql/parts/registeredServer/viewlet/serverTreeDataSource';
import { Builder, $ } from 'vs/base/browser/builder';
import WinJS = require('vs/base/common/winjs.base');
import { Emitter } from 'vs/base/common/event';
import Severity from 'vs/base/common/severity';
import { ObjectExplorerActionsContext, ManageConnectionAction } from 'sql/parts/registeredServer/viewlet/objectExplorerActions';
import { IConnectionResult, IConnectionParams } from 'sql/parts/connection/common/connectionManagement';
import { TreeSelectionHandler } from 'sql/parts/registeredServer/viewlet/treeSelectionHandler';
suite('SQL Connection Tree Action tests', () => {
let errorMessageService: TypeMoq.Mock<ErrorMessageServiceStub>;
let connectionResult: IConnectionResult = {
connected: true,
errorMessage: undefined,
errorCode: undefined
};
setup(() => {
errorMessageService = TypeMoq.Mock.ofType(ErrorMessageServiceStub, TypeMoq.MockBehavior.Loose);
let nothing: void;
errorMessageService.setup(x => x.showDialog(Severity.Error, TypeMoq.It.isAnyString(), TypeMoq.It.isAnyString())).returns(() => nothing);
});
function createConnectionManagementService(isConnectedReturnValue: boolean): TypeMoq.Mock<TestConnectionManagementService> {
let connectionManagementService = TypeMoq.Mock.ofType(TestConnectionManagementService, TypeMoq.MockBehavior.Strict);
connectionManagementService.callBase = true;
connectionManagementService.setup(x => x.isConnected(undefined, TypeMoq.It.isAny())).returns(() => isConnectedReturnValue);
connectionManagementService.setup(x => x.connect(TypeMoq.It.isAny(), undefined, TypeMoq.It.isAny(), undefined)).returns(() => Promise.resolve(connectionResult));
connectionManagementService.setup(x => x.disconnect(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
connectionManagementService.setup(x => x.findExistingConnection(TypeMoq.It.isAny())).returns(() => undefined);
connectionManagementService.setup(x => x.showDashboard(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
connectionManagementService.setup(x => x.isProfileConnected(TypeMoq.It.isAny())).returns(() => isConnectedReturnValue);
connectionManagementService.setup(x => x.isProfileConnecting(TypeMoq.It.isAny())).returns(() => false);
connectionManagementService.setup(x => x.showConnectionDialog(undefined, TypeMoq.It.isAny())).returns(() => new Promise<void>((resolve, reject) => resolve()));
connectionManagementService.setup(x => x.onConnect).returns(() => new Emitter<IConnectionParams>().event);
connectionManagementService.setup(x => x.onDisconnect).returns(() => new Emitter<any>().event);
connectionManagementService.setup(x => x.deleteConnectionGroup(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
connectionManagementService.setup(x => x.deleteConnection(TypeMoq.It.isAny())).returns(() => Promise.resolve(true));
return connectionManagementService;
}
function createObjectExplorerService(connectionManagementService: TestConnectionManagementService): TypeMoq.Mock<ObjectExplorerService> {
let objectExplorerService = TypeMoq.Mock.ofType(ObjectExplorerService, TypeMoq.MockBehavior.Strict, connectionManagementService);
objectExplorerService.callBase = true;
objectExplorerService.setup(x => x.getObjectExplorerNode(TypeMoq.It.isAny())).returns(() => new TreeNode('', '', false, '', '', '', undefined, undefined));
objectExplorerService.setup(x => x.getObjectExplorerNode(undefined)).returns(() => new TreeNode('', '', false, '', '', '', undefined, undefined));
objectExplorerService.setup(x => x.onUpdateObjectExplorerNodes).returns(() => new Emitter<ObjectExplorerNodeEventArgs>().event);
objectExplorerService.setup(x => x.onUpdateObjectExplorerNodes).returns(() => new Emitter<ObjectExplorerNodeEventArgs>().event);
return objectExplorerService;
}
test('ManageConnectionAction - test if connect is called for manage action if not already connected', (done) => {
let isConnectedReturnValue: boolean = false;
let connectionManagementService = createConnectionManagementService(isConnectedReturnValue);
let objectExplorerService = createObjectExplorerService(connectionManagementService.object);
let treeSelectionMock = TypeMoq.Mock.ofType(TreeSelectionHandler);
let instantiationService = TypeMoq.Mock.ofType(InstantiationService, TypeMoq.MockBehavior.Loose);
instantiationService.setup(x => x.createInstance(TypeMoq.It.isAny())).returns((input) => {
return treeSelectionMock.object;
});
let manageConnectionAction: ManageConnectionAction = new ManageConnectionAction(ManageConnectionAction.ID,
ManageConnectionAction.LABEL, connectionManagementService.object, instantiationService.object, objectExplorerService.object);
let connection: ConnectionProfile = new ConnectionProfile(undefined, {
savePassword: false,
groupFullName: 'testGroup',
serverName: 'testServerName',
databaseName: 'testDatabaseName',
authenticationType: 'integrated',
password: 'test',
userName: 'testUsername',
groupId: undefined,
getOptionsKey: undefined,
matches: undefined,
providerName: 'MSSQL',
options: {},
saveProfile: true,
id: 'testId'
});
var actionContext = new ObjectExplorerActionsContext();
actionContext.connectionProfile = connection;
manageConnectionAction.run(actionContext).then((value) => {
connectionManagementService.verify(x => x.connect(TypeMoq.It.isAny(), undefined, TypeMoq.It.isAny(), undefined), TypeMoq.Times.once());
}).then(() => done(), (err) => done(err));
});
test('ManageConnectionAction - test if connect is called for manage action on database node if not already connected', (done) => {
let isConnectedReturnValue: boolean = false;
let connectionManagementService = createConnectionManagementService(isConnectedReturnValue);
let objectExplorerService = createObjectExplorerService(connectionManagementService.object);
let treeSelectionMock = TypeMoq.Mock.ofType(TreeSelectionHandler);
let instantiationService = TypeMoq.Mock.ofType(InstantiationService, TypeMoq.MockBehavior.Loose);
instantiationService.setup(x => x.createInstance(TypeMoq.It.isAny())).returns((input) => {
return treeSelectionMock.object;
});
let manageConnectionAction: ManageConnectionAction = new ManageConnectionAction(ManageConnectionAction.ID,
ManageConnectionAction.LABEL, connectionManagementService.object, instantiationService.object, objectExplorerService.object);
let connection: ConnectionProfile = new ConnectionProfile(undefined, {
savePassword: false,
groupFullName: 'testGroup',
serverName: 'testServerName',
databaseName: 'testDatabaseName',
authenticationType: 'integrated',
password: 'test',
userName: 'testUsername',
groupId: undefined,
getOptionsKey: undefined,
matches: undefined,
providerName: 'MSSQL',
options: {},
saveProfile: true,
id: 'testId'
});
let treeNode = new TreeNode(NodeType.Database, 'db node', false, '', '', '', undefined, undefined);
treeNode.connection = connection;
var actionContext = new ObjectExplorerActionsContext();
actionContext.treeNode = treeNode;
manageConnectionAction.run(actionContext).then((value) => {
connectionManagementService.verify(x => x.showDashboard(TypeMoq.It.isAny()), TypeMoq.Times.once());
}).then(() => done(), (err) => done(err));
});
test('DisconnectConnectionAction - test if disconnect is called when profile is connected', (done) => {
let isConnectedReturnValue: boolean = true;
let connectionManagementService = createConnectionManagementService(isConnectedReturnValue);
let objectExplorerService = createObjectExplorerService(connectionManagementService.object);
let changeConnectionAction: DisconnectConnectionAction = new DisconnectConnectionAction(DisconnectConnectionAction.ID, DisconnectConnectionAction.LABEL, connectionManagementService.object, objectExplorerService.object, errorMessageService.object);
let connection: ConnectionProfile = new ConnectionProfile(undefined, {
savePassword: false,
groupFullName: 'testGroup',
serverName: 'testServerName',
databaseName: 'testDatabaseName',
authenticationType: 'integrated',
password: 'test',
userName: 'testUsername',
groupId: undefined,
getOptionsKey: undefined,
matches: undefined,
providerName: 'MSSQL',
options: {},
saveProfile: true,
id: 'testId'
});
var actionContext = new ObjectExplorerActionsContext();
actionContext.connectionProfile = connection;
changeConnectionAction.run(actionContext).then((value) => {
connectionManagementService.verify(x => x.isProfileConnected(TypeMoq.It.isAny()), TypeMoq.Times.atLeastOnce());
connectionManagementService.verify(x => x.disconnect(TypeMoq.It.isAny()), TypeMoq.Times.once());
}).then(() => done(), (err) => done(err));
});
test('AddServerAction - test if show connection dialog is called', (done) => {
let connectionManagementService = createConnectionManagementService(true);
let connectionTreeAction: AddServerAction = new AddServerAction(AddServerAction.ID, AddServerAction.LABEL, connectionManagementService.object);
let conProfGroup = new ConnectionProfileGroup('testGroup', undefined, 'testGroup', undefined, undefined);
connectionTreeAction.run(conProfGroup).then((value) => {
connectionManagementService.verify(x => x.showConnectionDialog(undefined, TypeMoq.It.isAny()), TypeMoq.Times.once());
}).then(() => done(), (err) => done(err));
});
test('ActiveConnectionsFilterAction - test if view is called to display filtered results', (done) => {
let connectionManagementService = createConnectionManagementService(true);
let instantiationService = TypeMoq.Mock.ofType(InstantiationService, TypeMoq.MockBehavior.Loose);
instantiationService.setup(x => x.createInstance(TypeMoq.It.isAny())).returns((input) => {
return new TPromise((resolve) => resolve({}));
});
let serverTreeView = TypeMoq.Mock.ofType(ServerTreeView, TypeMoq.MockBehavior.Strict, undefined, instantiationService.object, undefined, undefined, undefined);
serverTreeView.setup(x => x.showFilteredTree(TypeMoq.It.isAnyString()));
serverTreeView.setup(x => x.refreshTree());
let connectionTreeAction: ActiveConnectionsFilterAction = new ActiveConnectionsFilterAction(ActiveConnectionsFilterAction.ID, ActiveConnectionsFilterAction.LABEL, serverTreeView.object, connectionManagementService.object);
connectionTreeAction.run().then((value) => {
serverTreeView.verify(x => x.showFilteredTree('active'), TypeMoq.Times.once());
}).then(() => done(), (err) => done(err));
});
test('ActiveConnectionsFilterAction - test if view is called refresh results if action is toggled', (done) => {
let connectionManagementService = createConnectionManagementService(true);
let instantiationService = TypeMoq.Mock.ofType(InstantiationService, TypeMoq.MockBehavior.Loose);
instantiationService.setup(x => x.createInstance(TypeMoq.It.isAny())).returns((input) => {
return new TPromise((resolve) => resolve({}));
});
let serverTreeView = TypeMoq.Mock.ofType(ServerTreeView, TypeMoq.MockBehavior.Strict, undefined, instantiationService.object, undefined, undefined, undefined);
serverTreeView.setup(x => x.showFilteredTree(TypeMoq.It.isAnyString()));
serverTreeView.setup(x => x.refreshTree());
let connectionTreeAction: ActiveConnectionsFilterAction = new ActiveConnectionsFilterAction(ActiveConnectionsFilterAction.ID, ActiveConnectionsFilterAction.LABEL, serverTreeView.object, connectionManagementService.object);
connectionTreeAction.isSet = true;
connectionTreeAction.run().then((value) => {
serverTreeView.verify(x => x.refreshTree(), TypeMoq.Times.once());
}).then(() => done(), (err) => done(err));
});
test('RecentConnectionsFilterAction - test if view is called to display filtered results', (done) => {
let connectionManagementService = createConnectionManagementService(true);
let instantiationService = TypeMoq.Mock.ofType(InstantiationService, TypeMoq.MockBehavior.Loose);
instantiationService.setup(x => x.createInstance(TypeMoq.It.isAny())).returns((input) => {
return new TPromise((resolve) => resolve({}));
});
let serverTreeView = TypeMoq.Mock.ofType(ServerTreeView, TypeMoq.MockBehavior.Strict, undefined, instantiationService.object, undefined, undefined, undefined);
serverTreeView.setup(x => x.showFilteredTree(TypeMoq.It.isAnyString()));
serverTreeView.setup(x => x.refreshTree());
let connectionTreeAction: RecentConnectionsFilterAction = new RecentConnectionsFilterAction(RecentConnectionsFilterAction.ID, RecentConnectionsFilterAction.LABEL, serverTreeView.object, connectionManagementService.object);
connectionTreeAction.run().then((value) => {
serverTreeView.verify(x => x.showFilteredTree('recent'), TypeMoq.Times.once());
}).then(() => done(), (err) => done(err));
});
test('RecentConnectionsFilterAction - test if view is called refresh results if action is toggled', (done) => {
let connectionManagementService = createConnectionManagementService(true);
let instantiationService = TypeMoq.Mock.ofType(InstantiationService, TypeMoq.MockBehavior.Loose);
instantiationService.setup(x => x.createInstance(TypeMoq.It.isAny())).returns((input) => {
return new TPromise((resolve) => resolve({}));
});
let serverTreeView = TypeMoq.Mock.ofType(ServerTreeView, TypeMoq.MockBehavior.Strict, undefined, instantiationService.object, undefined, undefined, undefined);
serverTreeView.setup(x => x.showFilteredTree(TypeMoq.It.isAnyString()));
serverTreeView.setup(x => x.refreshTree());
let connectionTreeAction: RecentConnectionsFilterAction = new RecentConnectionsFilterAction(RecentConnectionsFilterAction.ID, RecentConnectionsFilterAction.LABEL, serverTreeView.object, connectionManagementService.object);
connectionTreeAction.isSet = true;
connectionTreeAction.run().then((value) => {
serverTreeView.verify(x => x.refreshTree(), TypeMoq.Times.once());
}).then(() => done(), (err) => done(err));
});
test('DeleteConnectionAction - test delete connection', (done) => {
let connectionManagementService = createConnectionManagementService(true);
let connection: ConnectionProfile = new ConnectionProfile(undefined, {
savePassword: false,
groupFullName: 'testGroup',
serverName: 'testServerName',
databaseName: 'testDatabaseName',
authenticationType: 'integrated',
password: 'test',
userName: 'testUsername',
groupId: undefined,
getOptionsKey: undefined,
matches: undefined,
providerName: 'MSSQL',
options: {},
saveProfile: true,
id: 'testId'
});
let connectionAction: DeleteConnectionAction = new DeleteConnectionAction(DeleteConnectionAction.ID,
DeleteConnectionAction.DELETE_CONNECTION_LABEL,
connection,
connectionManagementService.object);
connectionAction.run().then((value) => {
connectionManagementService.verify(x => x.deleteConnection(TypeMoq.It.isAny()), TypeMoq.Times.atLeastOnce());
}).then(() => done(), (err) => done(err));
});
test('DeleteConnectionAction - test delete connection group', (done) => {
let isConnectedReturnValue: boolean = false;
let connectionManagementService = createConnectionManagementService(isConnectedReturnValue);
let conProfGroup = new ConnectionProfileGroup('testGroup', undefined, 'testGroup', undefined, undefined);
let connectionAction: DeleteConnectionAction = new DeleteConnectionAction(DeleteConnectionAction.ID,
DeleteConnectionAction.DELETE_CONNECTION_LABEL,
conProfGroup,
connectionManagementService.object);
connectionAction.run().then((value) => {
connectionManagementService.verify(x => x.deleteConnectionGroup(TypeMoq.It.isAny()), TypeMoq.Times.atLeastOnce());
}).then(() => done(), (err) => done(err));
});
test('DeleteConnectionAction - delete should not be called if connect is an unsaved connection', (done) => {
let isConnectedReturnValue: boolean = false;
let connectionManagementService = createConnectionManagementService(isConnectedReturnValue);
let connection: ConnectionProfile = new ConnectionProfile(undefined, {
savePassword: false,
groupFullName: 'testGroup',
serverName: 'testServerName',
databaseName: 'testDatabaseName',
authenticationType: 'integrated',
password: 'test',
userName: 'testUsername',
groupId: undefined,
getOptionsKey: undefined,
matches: undefined,
providerName: 'MSSQL',
options: {},
saveProfile: true,
id: 'testId'
});
connection.parent = new ConnectionProfileGroup(LocalizedConstants.unsavedGroupLabel, undefined, Constants.unsavedGroupId, undefined, undefined);
let connectionAction: DeleteConnectionAction = new DeleteConnectionAction(DeleteConnectionAction.ID,
DeleteConnectionAction.DELETE_CONNECTION_LABEL,
connection,
connectionManagementService.object);
assert.equal(connectionAction.enabled, false, 'delete action should be disabled.');
done();
});
test('RefreshConnectionAction - refresh should be called if connection status is connect', (done) => {
let isConnectedReturnValue: boolean = true;
let sqlProvider = {
protocolVersion: '1',
providerName: 'MSSQL',
providerDisplayName: 'MSSQL',
connectionProvider: { options: [] },
adminServicesProvider: { databaseInfoOptions: [], databaseFileInfoOptions: [], fileGroupInfoOptions: [] },
features: undefined
};
var connection = new ConnectionProfile(sqlProvider, {
savePassword: false,
groupFullName: 'testGroup',
serverName: 'testServerName',
databaseName: 'testDatabaseName',
authenticationType: 'inetgrated',
password: 'test',
userName: 'testUsername',
groupId: undefined,
getOptionsKey: undefined,
matches: undefined,
providerName: 'MSSQL',
options: {},
saveProfile: true,
id: 'testID'
});
var conProfGroup = new ConnectionProfileGroup('testGroup', undefined, 'testGroup', undefined, undefined);
conProfGroup.connections = [connection];
var connectionManagementService = TypeMoq.Mock.ofType(TestConnectionManagementService, TypeMoq.MockBehavior.Strict);
connectionManagementService.callBase = true;
connectionManagementService.setup(x => x.getConnectionGroups()).returns(() => [conProfGroup]);
connectionManagementService.setup(x => x.getActiveConnections()).returns(() => [connection]);
connectionManagementService.setup(x => x.addSavedPassword(TypeMoq.It.isAny())).returns(() => new Promise<ConnectionProfile>((resolve) => {
resolve(connection);
}));
connectionManagementService.setup(x => x.isConnected(undefined, TypeMoq.It.isAny())).returns(() => isConnectedReturnValue);
var objectExplorerSession = {
success: true,
sessionId: '1234',
rootNode: {
nodePath: 'testServerName\tables',
nodeType: NodeType.Folder,
label: 'Tables',
isLeaf: false,
metadata: null,
nodeSubType: '',
nodeStatus: '',
errorMessage: ''
},
errorMessage: ''
};
var tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName\Db1\tables', '', '', null, null);
tablesNode.connection = connection;
tablesNode.session = objectExplorerSession;
var table1Node = new TreeNode(NodeType.Table, 'dbo.Table1', false, 'testServerName\tables\dbo.Table1', '', '', tablesNode, null);
var table2Node = new TreeNode(NodeType.Table, 'dbo.Table1', false, 'testServerName\tables\dbo.Table1', '', '', tablesNode, null);
tablesNode.children = [table1Node, table2Node];
let objectExplorerService = TypeMoq.Mock.ofType(ObjectExplorerService, TypeMoq.MockBehavior.Loose, connectionManagementService.object);
objectExplorerService.callBase = true;
objectExplorerService.setup(x => x.getObjectExplorerNode(TypeMoq.It.isAny())).returns(() => tablesNode);
objectExplorerService.setup(x => x.refreshTreeNode(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => TPromise.as([table1Node, table2Node]));
let builder: Builder = $().div();
var dataSource = new ServerTreeDataSource(objectExplorerService.object, connectionManagementService.object, undefined);
let tree = TypeMoq.Mock.ofType(Tree, TypeMoq.MockBehavior.Loose, builder.getHTMLElement(), { dataSource });
tree.callBase = true;
tree.setup(x => x.refresh(TypeMoq.It.isAny())).returns(() => WinJS.TPromise.as(null));
tree.setup(x => x.expand(TypeMoq.It.isAny())).returns(() => WinJS.TPromise.as(null));
tree.setup(x => x.collapse(TypeMoq.It.isAny())).returns(() => WinJS.TPromise.as(null));
let connectionAction: RefreshAction = new RefreshAction(RefreshAction.ID,
RefreshAction.LABEL,
tree.object,
connection,
connectionManagementService.object,
objectExplorerService.object,
undefined);
connectionAction.run().then((value) => {
connectionManagementService.verify(x => x.isConnected(undefined, TypeMoq.It.isAny()), TypeMoq.Times.atLeastOnce());
objectExplorerService.verify(x => x.getObjectExplorerNode(TypeMoq.It.isAny()), TypeMoq.Times.atLeastOnce());
objectExplorerService.verify(x => x.refreshTreeNode(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.atLeastOnce());
tree.verify(x => x.refresh(TypeMoq.It.isAny()), TypeMoq.Times.atLeastOnce());
tree.verify(x => x.expand(TypeMoq.It.isAny()), TypeMoq.Times.atLeastOnce());
}).then(() => done(), (err) => done(err));
});
test('RefreshConnectionAction - refresh should not be called if connection status is not connect', (done) => {
let isConnectedReturnValue: boolean = false;
let sqlProvider = {
protocolVersion: '1',
providerName: 'MSSQL',
providerDisplayName: 'MSSQL',
connectionProvider: { options: [] },
adminServicesProvider: { databaseInfoOptions: [], databaseFileInfoOptions: [], fileGroupInfoOptions: [] },
features: undefined
};
var connection = new ConnectionProfile(sqlProvider, {
savePassword: false,
groupFullName: 'testGroup',
serverName: 'testServerName',
databaseName: 'testDatabaseName',
authenticationType: 'inetgrated',
password: 'test',
userName: 'testUsername',
groupId: undefined,
getOptionsKey: undefined,
matches: undefined,
providerName: 'MSSQL',
options: {},
saveProfile: true,
id: 'testID'
});
var conProfGroup = new ConnectionProfileGroup('testGroup', undefined, 'testGroup', undefined, undefined);
conProfGroup.connections = [connection];
var connectionManagementService = TypeMoq.Mock.ofType(TestConnectionManagementService, TypeMoq.MockBehavior.Strict);
connectionManagementService.callBase = true;
connectionManagementService.setup(x => x.getConnectionGroups()).returns(() => [conProfGroup]);
connectionManagementService.setup(x => x.getActiveConnections()).returns(() => [connection]);
connectionManagementService.setup(x => x.addSavedPassword(TypeMoq.It.isAny())).returns(() => new Promise<ConnectionProfile>((resolve) => {
resolve(connection);
}));
connectionManagementService.setup(x => x.isConnected(undefined, TypeMoq.It.isAny())).returns(() => isConnectedReturnValue);
var objectExplorerSession = {
success: true,
sessionId: '1234',
rootNode: {
nodePath: 'testServerName\tables',
nodeType: NodeType.Folder,
label: 'Tables',
isLeaf: false,
metadata: null,
nodeSubType: '',
nodeStatus: '',
errorMessage: ''
},
errorMessage: ''
};
var tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName\Db1\tables', '', '', null, null);
tablesNode.connection = connection;
tablesNode.session = objectExplorerSession;
var table1Node = new TreeNode(NodeType.Table, 'dbo.Table1', false, 'testServerName\tables\dbo.Table1', '', '', tablesNode, null);
var table2Node = new TreeNode(NodeType.Table, 'dbo.Table1', false, 'testServerName\tables\dbo.Table1', '', '', tablesNode, null);
tablesNode.children = [table1Node, table2Node];
let objectExplorerService = TypeMoq.Mock.ofType(ObjectExplorerService, TypeMoq.MockBehavior.Loose, connectionManagementService.object);
objectExplorerService.callBase = true;
objectExplorerService.setup(x => x.getObjectExplorerNode(TypeMoq.It.isAny())).returns(() => tablesNode);
objectExplorerService.setup(x => x.refreshTreeNode(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => TPromise.as([table1Node, table2Node]));
let builder: Builder = $().div();
var dataSource = new ServerTreeDataSource(objectExplorerService.object, connectionManagementService.object, undefined);
let tree = TypeMoq.Mock.ofType(Tree, TypeMoq.MockBehavior.Loose, builder.getHTMLElement(), { dataSource });
tree.callBase = true;
tree.setup(x => x.refresh(TypeMoq.It.isAny())).returns(() => WinJS.TPromise.as(null));
tree.setup(x => x.expand(TypeMoq.It.isAny())).returns(() => WinJS.TPromise.as(null));
let connectionAction: RefreshAction = new RefreshAction(RefreshAction.ID,
RefreshAction.LABEL,
tree.object,
connection,
connectionManagementService.object,
objectExplorerService.object,
undefined);
connectionAction.run().then((value) => {
connectionManagementService.verify(x => x.isConnected(undefined, TypeMoq.It.isAny()), TypeMoq.Times.atLeastOnce());
objectExplorerService.verify(x => x.getObjectExplorerNode(TypeMoq.It.isAny()), TypeMoq.Times.exactly(0));
objectExplorerService.verify(x => x.refreshTreeNode(TypeMoq.It.isAny(), TypeMoq.It.isAny()), TypeMoq.Times.exactly(0));
tree.verify(x => x.refresh(TypeMoq.It.isAny()), TypeMoq.Times.exactly(0));
tree.verify(x => x.expand(TypeMoq.It.isAny()), TypeMoq.Times.exactly(0));
}).then(() => done(), (err) => done(err));
});
});

View File

@@ -0,0 +1,450 @@
/*---------------------------------------------------------------------------------------------
* 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 { ObjectExplorerProviderTestService } from 'sqltest/stubs/objectExplorerProviderTestService';
import { TestConnectionManagementService } from 'sqltest/stubs/connectionManagementService.test';
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
import { ConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup';
import { ObjectExplorerService } from 'sql/parts/registeredServer/common/objectExplorerService';
import { NodeType } from 'sql/parts/registeredServer/common/nodeType';
import { TreeNode } from 'sql/parts/registeredServer/common/treeNode';
import { TPromise } from 'vs/base/common/winjs.base';
import * as data from 'data';
import * as TypeMoq from 'typemoq';
import * as assert from 'assert';
suite('SQL Object Explorer Service tests', () => {
var sqlOEProvider: TypeMoq.Mock<ObjectExplorerProviderTestService>;
let connectionManagementService: TypeMoq.Mock<TestConnectionManagementService>;
let connection: ConnectionProfile;
let connectionToFail: ConnectionProfile;
let conProfGroup: ConnectionProfileGroup;
let objectExplorerService: ObjectExplorerService;
let objectExplorerSession: data.ObjectExplorerSession;
let objectExplorerFailedSession: data.ObjectExplorerSession;
let objectExplorerCloseSessionResponse: data.ObjectExplorerCloseSessionResponse;
let objectExplorerExpandInfo: data.ObjectExplorerExpandInfo;
let objectExplorerExpandInfoRefresh: data.ObjectExplorerExpandInfo;
let sessionId = '1234';
let failedSessionId = '12345';
let numberOfFailedSession: number = 0;
setup(() => {
let NodeInfoTable1 = {
nodePath: 'testServerName\tables\dbo.Table1',
nodeType: NodeType.Table,
label: 'dbo.Table1',
isLeaf: false,
metadata: null,
nodeSubType: '',
nodeStatus: '',
errorMessage: ''
};
let NodeInfoTable2 = {
nodePath: 'testServerName\tables\dbo.Table2',
nodeType: NodeType.Table,
label: 'dbo.Table2',
isLeaf: false,
metadata: null,
nodeSubType: '',
nodeStatus: '',
errorMessage: ''
};
let NodeInfoTable3 = {
nodePath: 'testServerName\tables\dbo.Table3',
nodeType: NodeType.Table,
label: 'dbo.Table3',
isLeaf: false,
metadata: null,
nodeSubType: '',
nodeStatus: '',
errorMessage: ''
};
objectExplorerSession = {
success: true,
sessionId: sessionId,
rootNode: {
nodePath: 'testServerName\tables',
nodeType: NodeType.Folder,
label: 'Tables',
isLeaf: false,
metadata: null,
nodeSubType: '',
nodeStatus: '',
errorMessage: ''
},
errorMessage: ''
};
objectExplorerFailedSession = {
success: false,
sessionId: failedSessionId,
rootNode: undefined,
errorMessage: 'Connection Failed'
};
objectExplorerCloseSessionResponse = {
success: true,
sessionId: sessionId,
};
objectExplorerExpandInfo = {
sessionId: sessionId,
nodes: [NodeInfoTable1, NodeInfoTable2],
errorMessage: '',
nodePath: objectExplorerSession.rootNode.nodePath
};
objectExplorerExpandInfoRefresh = {
sessionId: sessionId,
nodes: [NodeInfoTable1, NodeInfoTable3],
errorMessage: '',
nodePath: objectExplorerSession.rootNode.nodePath
};
let response: data.ObjectExplorerSessionResponse = {
sessionId: objectExplorerSession.sessionId
};
let failedResponse: data.ObjectExplorerSessionResponse = {
sessionId: failedSessionId
};
sqlOEProvider = TypeMoq.Mock.ofType(ObjectExplorerProviderTestService, TypeMoq.MockBehavior.Loose);
sqlOEProvider.callBase = true;
let sqlProvider = {
protocolVersion: '1',
providerName: 'MSSQL',
providerDisplayName: 'MSSQL',
connectionProvider: {
options: [
{
name: 'serverName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 0,
valueType: 0
},
{
name: 'databaseName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 1,
valueType: 0
},
{
name: 'userName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 3,
valueType: 0
},
{
name: 'authenticationType',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 2,
valueType: 0
},
{
name: 'password',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 4,
valueType: 0
},
{
name: 'encrypt',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: false,
isRequired: false,
specialValueType: undefined,
valueType: 0
}]
},
adminServicesProvider: { databaseInfoOptions: [], databaseFileInfoOptions: [], fileGroupInfoOptions: [] },
features: undefined
};
connection = new ConnectionProfile(sqlProvider, {
savePassword: false,
groupFullName: 'testGroup',
serverName: 'testServerName',
databaseName: 'testDatabaseName',
authenticationType: 'inetgrated',
password: 'test',
userName: 'testUsername',
groupId: undefined,
getOptionsKey: undefined,
matches: undefined,
providerName: 'MSSQL',
options: {},
saveProfile: true,
id: 'testID'
});
conProfGroup = new ConnectionProfileGroup('testGroup', undefined, 'testGroup', undefined, undefined);
connectionToFail = new ConnectionProfile(sqlProvider, {
savePassword: false,
groupFullName: 'testGroup',
serverName: 'testServerName2',
databaseName: 'testDatabaseName2',
authenticationType: 'inetgrated',
password: 'test',
userName: 'testUsername',
groupId: undefined,
getOptionsKey: undefined,
matches: undefined,
providerName: 'MSSQL',
options: {},
saveProfile: true,
id: 'testID2'
});
conProfGroup = new ConnectionProfileGroup('testGroup', undefined, 'testGroup', undefined, undefined);
conProfGroup.connections = [connection];
connectionManagementService = TypeMoq.Mock.ofType(TestConnectionManagementService, TypeMoq.MockBehavior.Strict);
connectionManagementService.setup(x => x.getConnectionGroups()).returns(() => [conProfGroup]);
connectionManagementService.setup(x => x.getActiveConnections()).returns(() => [connection]);
connectionManagementService.setup(x => x.addSavedPassword(TypeMoq.It.isAny())).returns(() => new Promise<ConnectionProfile>((resolve) => {
resolve(connection);
}));
connectionManagementService.setup(x => x.getCapabilities('MSSQL')).returns(() => undefined);
objectExplorerService = new ObjectExplorerService(connectionManagementService.object, undefined);
objectExplorerService.registerProvider('MSSQL', sqlOEProvider.object);
sqlOEProvider.setup(x => x.createNewSession(TypeMoq.It.is<data.ConnectionInfo>(x => x.options['serverName'] === connection.serverName))).returns(() => new Promise<any>((resolve) => {
resolve(response);
}));
sqlOEProvider.setup(x => x.createNewSession(TypeMoq.It.is<data.ConnectionInfo>(x => x.options['serverName'] === connectionToFail.serverName))).returns(() => new Promise<any>((resolve) => {
resolve(failedResponse);
}));
sqlOEProvider.setup(x => x.expandNode(TypeMoq.It.isAny())).callback(() => {
objectExplorerService.onNodeExpanded(1, objectExplorerExpandInfo);
}).returns(() => TPromise.as(true));
sqlOEProvider.setup(x => x.refreshNode(TypeMoq.It.isAny())).callback(() => {
objectExplorerService.onNodeExpanded(1, objectExplorerExpandInfoRefresh);
}).returns(() => TPromise.as(true));
sqlOEProvider.setup(x => x.closeSession(TypeMoq.It.isAny())).returns(() => TPromise.as(objectExplorerCloseSessionResponse));
objectExplorerService.onUpdateObjectExplorerNodes(args => {
if (args && args.errorMessage !== undefined) {
numberOfFailedSession++;
}
});
});
test('create new session should create session successfully', (done) => {
objectExplorerService.createNewSession('MSSQL', connection).then(session => {
assert.equal(session !== null || session !== undefined, true);
assert.equal(session.sessionId, '1234');
objectExplorerService.onSessionCreated(1, objectExplorerSession);
let node = objectExplorerService.getObjectExplorerNode(connection);
assert.notEqual(node, undefined);
assert.equal(node.session.success, true);
done();
}, err => {
// Must call done here so test indicates it's finished if errors occur
done(err);
});
});
test('create new session should raise failed event for failed session', (done) => {
objectExplorerService.createNewSession('MSSQL', connectionToFail).then(session => {
assert.equal(session !== null || session !== undefined, true);
assert.equal(session.sessionId, failedSessionId);
let currentNumberOfFailedSession = numberOfFailedSession;
objectExplorerService.onSessionCreated(1, objectExplorerFailedSession);
let node = objectExplorerService.getObjectExplorerNode(connection);
assert.equal(node, undefined);
assert.equal(currentNumberOfFailedSession + 1, numberOfFailedSession);
done();
}, err => {
// Must call done here so test indicates it's finished if errors occur
done(err);
});
});
test('close session should close session successfully', (done) => {
objectExplorerService.closeSession('MSSQL', objectExplorerSession).then(session => {
assert.equal(session !== null || session !== undefined, true);
assert.equal(session.success, true);
assert.equal(session.sessionId, '1234');
done();
}, err => {
// Must call done here so test indicates it's finished if errors occur
done(err);
});
});
test('expand node should expand node correctly', (done) => {
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
objectExplorerService.onSessionCreated(1, objectExplorerSession);
objectExplorerService.expandNode('MSSQL', objectExplorerSession, 'testServerName\tables').then(expandInfo => {
assert.equal(expandInfo !== null || expandInfo !== undefined, true);
assert.equal(expandInfo.sessionId, '1234');
assert.equal(expandInfo.nodes.length, 2);
var children = expandInfo.nodes;
assert.equal(children[0].label, 'dbo.Table1');
assert.equal(children[1].label, 'dbo.Table2');
done();
}, err => {
// Must call done here so test indicates it's finished if errors occur
done(err);
});
});
});
test('refresh node should refresh node correctly', (done) => {
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
objectExplorerService.onSessionCreated(1, objectExplorerSession);
objectExplorerService.refreshNode('MSSQL', objectExplorerSession, 'testServerName\tables').then(expandInfo => {
assert.equal(expandInfo !== null || expandInfo !== undefined, true);
assert.equal(expandInfo.sessionId, '1234');
assert.equal(expandInfo.nodes.length, 2);
var children = expandInfo.nodes;
assert.equal(children[0].label, 'dbo.Table1');
assert.equal(children[1].label, 'dbo.Table3');
done();
}, err => {
// Must call done here so test indicates it's finished if errors occur
done(err);
});
});
});
test('expand tree node should children correctly', (done) => {
var tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName\tables', '', '', null, null);
tablesNode.connection = connection;
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
objectExplorerService.onSessionCreated(1, objectExplorerSession);
objectExplorerService.expandTreeNode(objectExplorerSession, tablesNode).then(children => {
assert.equal(children !== null || children !== undefined, true);
assert.equal(children[0].label, 'dbo.Table1');
assert.equal(children[0].parent, tablesNode);
assert.equal(children[0].nodePath, 'testServerName\tables\dbo.Table1');
assert.equal(children[1].label, 'dbo.Table2');
assert.equal(children[1].parent, tablesNode);
assert.equal(children[1].nodePath, 'testServerName\tables\dbo.Table2');
done();
}, err => {
// Must call done here so test indicates it's finished if errors occur
done(err);
});
});
});
test('refresh tree node should children correctly', (done) => {
var tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName\tables', '', '', null, null);
tablesNode.connection = connection;
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
objectExplorerService.onSessionCreated(1, objectExplorerSession);
objectExplorerService.refreshTreeNode(objectExplorerSession, tablesNode).then(children => {
assert.equal(children !== null || children !== undefined, true);
assert.equal(children[0].label, 'dbo.Table1');
assert.equal(children[0].parent, tablesNode);
assert.equal(children[0].nodePath, 'testServerName\tables\dbo.Table1');
assert.equal(children[1].label, 'dbo.Table3');
assert.equal(children[1].parent, tablesNode);
assert.equal(children[1].nodePath, 'testServerName\tables\dbo.Table3');
done();
}, err => {
// Must call done here so test indicates it's finished if errors occur
done(err);
});
});
});
test('update object explorer nodes should get active connection, create session, add to the active OE nodes successfully', (done) => {
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
objectExplorerService.onSessionCreated(1, objectExplorerSession);
objectExplorerService.updateObjectExplorerNodes(connection).then(() => {
var treeNode = objectExplorerService.getObjectExplorerNode(connection);
assert.equal(treeNode !== null || treeNode !== undefined, true);
assert.equal(treeNode.getSession(), objectExplorerSession);
assert.equal(treeNode.getConnectionProfile(), connection);
assert.equal(treeNode.label, 'Tables');
assert.equal(treeNode.nodePath, 'testServerName\tables');
done();
}, err => {
// Must call done here so test indicates it's finished if errors occur
done(err);
});
});
});
test('delete object explorerNode nodes should delete session, delete the root node to the active OE node', (done) => {
objectExplorerService.createNewSession('MSSQL', connection).then(result => {
objectExplorerService.onSessionCreated(1, objectExplorerSession);
objectExplorerService.updateObjectExplorerNodes(connection).then(() => {
var treeNode = objectExplorerService.getObjectExplorerNode(connection);
assert.equal(treeNode !== null && treeNode !== undefined, true);
objectExplorerService.deleteObjectExplorerNode(connection);
treeNode = objectExplorerService.getObjectExplorerNode(connection);
assert.equal(treeNode === null || treeNode === undefined, true);
done();
}, err => {
// Must call done here so test indicates it's finished if errors occur
done(err);
});
});
});
test('children tree nodes should return correct object explorer session, connection profile and database name', () => {
var databaseMetaData = {
metadataType: 0,
metadataTypeName: 'Database',
urn: '//server/db1/',
name: 'Db1',
schema: null
};
var databaseNode = new TreeNode(NodeType.Database, 'Db1', false, 'testServerName\Db1', '', '', null, databaseMetaData);
databaseNode.connection = connection;
databaseNode.session = objectExplorerSession;
var tablesNode = new TreeNode(NodeType.Folder, 'Tables', false, 'testServerName\Db1\tables', '', '', databaseNode, null);
databaseNode.children = [tablesNode];
var table1Node = new TreeNode(NodeType.Table, 'dbo.Table1', false, 'testServerName\Db1\tables\dbo.Table1', '', '', tablesNode, null);
var table2Node = new TreeNode(NodeType.Table, 'dbo.Table2', false, 'testServerName\Db1\tables\dbo.Table2', '', '', tablesNode, null);
tablesNode.children = [table1Node, table2Node];
assert.equal(table1Node.getSession(), objectExplorerSession);
assert.equal(table1Node.getConnectionProfile(), connection);
assert.equal(table1Node.getDatabaseName(), 'Db1');
});
});

View File

@@ -0,0 +1,248 @@
/*---------------------------------------------------------------------------------------------
* 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 { ProviderConnectionInfo } from 'sql/parts/connection/common/providerConnectionInfo';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import data = require('data');
import * as assert from 'assert';
suite('SQL ProviderConnectionInfo tests', () => {
let msSQLCapabilities: data.DataProtocolServerCapabilities;
let connectionProfile: 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: undefined,
saveProfile: true,
id: undefined
};
setup(() => {
let capabilities: data.DataProtocolServerCapabilities[] = [];
let connectionProvider: data.ConnectionProviderOptions = {
options: [
{
name: 'serverName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 0,
valueType: 0
},
{
name: 'databaseName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 1,
valueType: 0
},
{
name: 'userName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 3,
valueType: 0
},
{
name: 'authenticationType',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 2,
valueType: 0
},
{
name: 'password',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 4,
valueType: 0
},
{
name: 'encrypt',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: false,
isRequired: false,
specialValueType: undefined,
valueType: 0
}
]
};
msSQLCapabilities = {
protocolVersion: '1',
providerName: 'MSSQL',
providerDisplayName: 'MSSQL',
connectionProvider: connectionProvider,
adminServicesProvider: undefined,
features: undefined
};
capabilities.push(msSQLCapabilities);
});
test('constructor should accept undefined parameters', () => {
let conn = new ProviderConnectionInfo(undefined, undefined);
assert.equal(conn.serverName, undefined);
});
test('set properties should set the values correctly', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, undefined);
assert.equal(conn.serverName, undefined);
conn.serverName = connectionProfile.serverName;
conn.databaseName = connectionProfile.databaseName;
conn.authenticationType = connectionProfile.authenticationType;
conn.password = connectionProfile.password;
conn.userName = connectionProfile.userName;
assert.equal(conn.serverName, connectionProfile.serverName);
assert.equal(conn.databaseName, connectionProfile.databaseName);
assert.equal(conn.authenticationType, connectionProfile.authenticationType);
assert.equal(conn.password, connectionProfile.password);
assert.equal(conn.userName, connectionProfile.userName);
});
test('set properties should store the values in the options', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, undefined);
assert.equal(conn.serverName, undefined);
conn.serverName = connectionProfile.serverName;
conn.databaseName = connectionProfile.databaseName;
conn.authenticationType = connectionProfile.authenticationType;
conn.password = connectionProfile.password;
conn.userName = connectionProfile.userName;
assert.equal(conn.getOptionValue('serverName'), connectionProfile.serverName);
assert.equal(conn.getOptionValue('databaseName'), connectionProfile.databaseName);
assert.equal(conn.getOptionValue('authenticationType'), connectionProfile.authenticationType);
assert.equal(conn.getOptionValue('password'), connectionProfile.password);
assert.equal(conn.getOptionValue('userName'), connectionProfile.userName);
});
test('constructor should initialize the options given a valid model', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, connectionProfile);
assert.equal(conn.serverName, connectionProfile.serverName);
assert.equal(conn.databaseName, connectionProfile.databaseName);
assert.equal(conn.authenticationType, connectionProfile.authenticationType);
assert.equal(conn.password, connectionProfile.password);
assert.equal(conn.userName, connectionProfile.userName);
});
test('clone should create a new instance that equals the old one', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, connectionProfile);
let conn2 = conn.clone();
assert.equal(conn.serverName, conn2.serverName);
assert.equal(conn.databaseName, conn2.databaseName);
assert.equal(conn.authenticationType, conn2.authenticationType);
assert.equal(conn.password, conn2.password);
assert.equal(conn.userName, conn2.userName);
});
test('Changing the cloned object should not change the original one', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, connectionProfile);
let conn2 = conn.clone();
conn2.serverName = conn.serverName + '1';
assert.notEqual(conn.serverName, conn2.serverName);
});
test('constructor should initialize the options given a valid model with options', () => {
let options = {};
options['encrypt'] = 'test value';
let conn2 = Object.assign({}, connectionProfile, { options: options });
let conn = new ProviderConnectionInfo(msSQLCapabilities, conn2);
assert.equal(conn.serverName, conn2.serverName);
assert.equal(conn.databaseName, conn2.databaseName);
assert.equal(conn.authenticationType, conn2.authenticationType);
assert.equal(conn.password, conn2.password);
assert.equal(conn.userName, conn2.userName);
assert.equal(conn.options['encrypt'], 'test value');
});
test('getOptionsKey should create a valid unique id', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, connectionProfile);
let expectedId = 'providerName:MSSQL|authenticationType:|databaseName:database|serverName:new server|userName:user';
let id = conn.getOptionsKey();
assert.equal(id, expectedId);
});
test('getOptionsKey should create different id for different server names', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, connectionProfile);
let conn2 = new ProviderConnectionInfo(msSQLCapabilities, Object.assign({}, connectionProfile, { serverName: connectionProfile.serverName + '1' }));
assert.notEqual(conn.getOptionsKey(), conn2.getOptionsKey());
});
test('titleParts should return server, database and auth type as first items', () => {
let conn = new ProviderConnectionInfo(msSQLCapabilities, connectionProfile);
let titleParts = conn.titleParts;
assert.equal(titleParts.length, 4);
assert.equal(titleParts[0], connectionProfile.serverName);
assert.equal(titleParts[1], connectionProfile.databaseName);
assert.equal(titleParts[2], connectionProfile.authenticationType);
assert.equal(titleParts[3], connectionProfile.userName);
});
test('getProviderFromOptionsKey should return the provider name from the options key successfully', () => {
let optionsKey = 'providerName:MSSQL|authenticationType:|databaseName:database|serverName:new server|userName:user';
let expectedProviderId: string = 'MSSQL';
let actual = ProviderConnectionInfo.getProviderFromOptionsKey(optionsKey);
assert.equal(expectedProviderId, actual);
});
test('getProviderFromOptionsKey should return empty string give null', () => {
let optionsKey = undefined;
let expectedProviderId: string = '';
let actual = ProviderConnectionInfo.getProviderFromOptionsKey(optionsKey);
assert.equal(expectedProviderId, actual);
});
test('getProviderFromOptionsKey should return empty string give key without provider name', () => {
let optionsKey = 'providerName2:MSSQL|authenticationType:|databaseName:database|serverName:new server|userName:user';
let expectedProviderId: string = '';
let actual = ProviderConnectionInfo.getProviderFromOptionsKey(optionsKey);
assert.equal(expectedProviderId, actual);
});
});

View File

@@ -0,0 +1,59 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ObjectMetadataWrapper } from 'sql/parts/dashboard/widgets/explorer/explorerWidget.component';
import { MetadataType } from 'sql/parts/connection/common/connectionManagement';
import * as assert from 'assert';
suite('Explorer Widget Tests', () => {
test('Sorting dashboard search objects works correctly', () => {
let testMetadata = ObjectMetadataWrapper.createFromObjectMetadata(
[
{
metadataType: MetadataType.View,
metadataTypeName: undefined,
urn: undefined,
name: 'testView',
schema: undefined
},
{
metadataType: MetadataType.Table,
metadataTypeName: undefined,
urn: undefined,
name: 'testTable',
schema: undefined
},
{
metadataType: MetadataType.SProc,
metadataTypeName: undefined,
urn: undefined,
name: 'testSProc',
schema: undefined
},
{
metadataType: MetadataType.Function,
metadataTypeName: undefined,
urn: undefined,
name: 'testFunction',
schema: undefined
},
{
metadataType: MetadataType.View,
metadataTypeName: undefined,
urn: undefined,
name: 'firstView',
schema: undefined
}
]);
// If I sort the object metadata wrapper list using ExplorerWidget's sort function
let sortedMetadata = testMetadata.slice().sort(ObjectMetadataWrapper.sort);
// Then the resulting list is sorted by type, with Table > View > Stored Procedures > Function, then by name
let expectedList = [testMetadata[1], testMetadata[4], testMetadata[0], testMetadata[2], testMetadata[3]];
expectedList.forEach((expectedWrapper, index) => assert.equal(sortedMetadata[index], expectedWrapper));
});
});

View File

@@ -0,0 +1,108 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ChangeDetectorRef } from '@angular/core';
import { Observable } from 'rxjs/Observable';
// of is not on Observable by default, need to import it
import 'rxjs/add/observable/of';
import { WidgetConfig } from 'sql/parts/dashboard/common/dashboardWidget';
import { DashboardServiceInterface, SingleAdminService, SingleConnectionManagementService } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
import { PropertiesWidgetComponent } from 'sql/parts/dashboard/widgets/properties/propertiesWidget.component';
import { ConnectionManagementInfo } from 'sql/parts/connection/common/connectionManagementInfo';
import * as TypeMoq from 'typemoq';
import * as assert from 'assert';
class TestChangeDetectorRef extends ChangeDetectorRef {
reattach(): void {
return;
}
checkNoChanges(): void {
return;
}
detectChanges(): void {
return;
}
detach(): void {
return;
}
markForCheck(): void {
return;
}
}
suite('Dashboard Properties Widget Tests', () => {
test('Parses good config', (done) => {
let propertiesConfig = {
properties: [
{
displayName: 'Test',
value: 'testProperty'
}
]
};
let serverInfo = {
isCloud: false,
testProperty: 'Test Property',
serverMajorVersion: undefined,
serverMinorVersion: undefined,
serverReleaseVersion: undefined,
engineEditionId: undefined,
serverVersion: undefined,
serverLevel: undefined,
serverEdition: undefined,
azureVersion: undefined,
osVersion: undefined,
};
let databaseInfo = {
options: {
testProperty: 'Test Property'
}
};
let widgetConfig: WidgetConfig = {
widget: {
'properties-widget': propertiesConfig
},
context: 'server',
provider: 'MSSQL',
edition: 0
};
let dashboardService = TypeMoq.Mock.ofType(DashboardServiceInterface, TypeMoq.MockBehavior.Loose, [{}]);
let singleAdminService = TypeMoq.Mock.ofType(SingleAdminService);
singleAdminService.setup(x => x.databaseInfo).returns(() => Observable.of(databaseInfo));
dashboardService.setup(x => x.adminService).returns(() => singleAdminService.object);
let connectionManagementinfo = TypeMoq.Mock.ofType(ConnectionManagementInfo);
connectionManagementinfo.object.serverInfo = serverInfo;
let singleConnectionService = TypeMoq.Mock.ofType(SingleConnectionManagementService);
singleConnectionService.setup(x => x.connectionInfo).returns(() => connectionManagementinfo.object);
dashboardService.setup(x => x.connectionManagementService).returns(() => singleConnectionService.object);
let consoleError = (message?: any, ...optionalParams: any[]): void => {
assert.fail('Called console Error unexpectedly');
};
let testComponent = new PropertiesWidgetComponent(dashboardService.object, new TestChangeDetectorRef(), undefined, widgetConfig, consoleError);
// because config parsing is done async we need to put our asserts on the thread stack
setTimeout(() => {
// because properties is private we need to do some work arounds to access it.
assert.equal((<any>testComponent).properties.length, 1);
assert.equal((<any>testComponent).properties[0].displayName, 'Test');
assert.equal((<any>testComponent).properties[0].value, 'Test Property');
done();
});
// for some reason mocha thinks this test takes 26 seconds even though it doesn't, so it says this failed because it took longer than 2 seconds
}).timeout(30000);
});

View File

@@ -0,0 +1,266 @@
/*---------------------------------------------------------------------------------------------
* 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 data = require('data');
import * as assert from 'assert';
import { ServiceOptionType } from 'sql/parts/connection/common/connectionManagement';
import { RestoreViewModel } from 'sql/parts/disasterRecovery/restore/restoreViewModel';
suite('Restore Dialog view model tests', () => {
let option1String = 'option1';
let option2Category = 'option2';
let option3Boolean = 'option3';
let options: { [name: string]: any };
let stringServiceOption: data.ServiceOption;
let categoryServiceOption: data.ServiceOption;
let booleanServiceOption: data.ServiceOption;
let viewModel: RestoreViewModel;
let planDetails: { [key: string]: data.RestorePlanDetailInfo };
let backupSets: data.DatabaseFileInfo[];
setup(() => {
options = {};
planDetails = {};
backupSets = [];
planDetails['lastBackupTaken'] = {
name: 'lastBackupTaken',
currentValue: '8/16/2017',
isReadOnly: true,
isVisible: true,
defaultValue: null
};
planDetails['targetDatabaseName'] = {
name: 'targetDatabaseName',
currentValue: 'db1',
isReadOnly: true,
isVisible: true,
defaultValue: 'db1'
};
planDetails['sourceDatabaseName'] = {
name: 'sourceDatabaseName',
currentValue: 'dbSource',
isReadOnly: true,
isVisible: true,
defaultValue: 'dbSource'
};
planDetails[option1String] = {
name: option1String,
currentValue: 'newOptionValue',
isReadOnly: true,
isVisible: true,
defaultValue: 'newDefault'
};
backupSets.push(
{
properties: [],
id: 'file1',
isSelected: false
},
{
properties: [],
id: 'file2',
isSelected: true
});
stringServiceOption = {
name: option1String,
displayName: 'Option 1',
description: null,
groupName: null,
valueType: ServiceOptionType.string,
defaultValue: 'default',
objectType: null,
categoryValues: null,
isRequired: false,
isArray: false
};
categoryServiceOption = {
name: option2Category,
displayName: 'Option 2',
description: null,
groupName: null,
valueType: ServiceOptionType.category,
defaultValue: 'catagory1',
objectType: null,
categoryValues: [{
displayName: 'Catagory 1',
name: 'catagory1'
},
{
displayName: 'Catagory 2',
name: 'catagory2'
}],
isRequired: false,
isArray: false
};
booleanServiceOption = {
name: option3Boolean,
displayName: 'Option 3',
description: null,
groupName: null,
valueType: ServiceOptionType.boolean,
defaultValue: 'true',
objectType: null,
categoryValues: null,
isRequired: false,
isArray: false
};
viewModel = new RestoreViewModel([booleanServiceOption, categoryServiceOption, stringServiceOption]);
});
test('get boolean option type should return correct display value', () => {
let falseStringOptionValue = 'False';
assert.equal(false, viewModel.getDisplayValue(booleanServiceOption, falseStringOptionValue));
let falseBooleanOptionValue = false;
assert.equal(false, viewModel.getDisplayValue(booleanServiceOption, falseBooleanOptionValue));
let trueStringOptionValue = 'true';
assert.equal(true, viewModel.getDisplayValue(booleanServiceOption, trueStringOptionValue));
let undefinedOptionValue = undefined;
assert.equal(false, viewModel.getDisplayValue(booleanServiceOption, undefinedOptionValue));
});
test('get category option type should return correct display value', () => {
let categoryOptionValue = 'catagory2';
assert.equal('Catagory 2', viewModel.getDisplayValue(categoryServiceOption, categoryOptionValue));
let undefinedOptionValue = undefined;
assert.equal('Catagory 1', viewModel.getDisplayValue(categoryServiceOption, undefinedOptionValue));
});
test('get string option type should return correct display value', () => {
let stringOptionValue = 'string1';
assert.equal(stringOptionValue, viewModel.getDisplayValue(stringServiceOption, stringOptionValue));
let undefinedOptionValue = undefined;
assert.equal('', viewModel.getDisplayValue(stringServiceOption, undefinedOptionValue));
});
test('get option meta data should return the correct one', () => {
assert.equal(stringServiceOption, viewModel.getOptionMetadata(option1String));
assert.equal(categoryServiceOption, viewModel.getOptionMetadata(option2Category));
assert.equal(booleanServiceOption, viewModel.getOptionMetadata(option3Boolean));
assert.equal(undefined, viewModel.getOptionMetadata('option4'));
});
test('get restore advanced option should return the only the options that have been changed and are different from the default value', () => {
viewModel.setOptionValue(option1String, 'default');
viewModel.setOptionValue(option2Category, 'Catagory 2');
viewModel.setOptionValue(option3Boolean, false);
options = {};
viewModel.getRestoreAdvancedOptions(options);
assert.equal(undefined, options[option1String]);
assert.equal('catagory2', options[option2Category]);
assert.equal(false, options[option3Boolean]);
});
test('on restore plan response should update all options from restore plan response correctly', () => {
let restorePlanResponse: data.RestorePlanResponse = {
sessionId: '123',
backupSetsToRestore: backupSets,
canRestore: true,
errorMessage: null,
dbFiles: [],
databaseNamesFromBackupSets: ['dbSource', 'dbSource2'],
planDetails: planDetails
};
viewModel.onRestorePlanResponse(restorePlanResponse);
// verify that source database, target databasem and last backup get set correctly
assert.equal('dbSource', viewModel.sourceDatabaseName);
assert.equal('db1', viewModel.targetDatabaseName);
assert.equal('8/16/2017', viewModel.lastBackupTaken);
// verify that advanced options get set correctly
options = {};
viewModel.getRestoreAdvancedOptions(options);
assert.equal('newOptionValue', options[option1String]);
// verify that selected backup sets get set correctly
let selectedBackupSets = viewModel.selectedBackupSets;
assert.equal(1, selectedBackupSets.length);
assert.equal('file2', selectedBackupSets[0]);
});
test('on reset restore options should reset all options', () => {
let restorePlanResponse: data.RestorePlanResponse = {
sessionId: '123',
backupSetsToRestore: backupSets,
canRestore: true,
errorMessage: null,
dbFiles: [],
databaseNamesFromBackupSets: ['dbSource', 'dbSource2'],
planDetails: planDetails
};
viewModel.filePath = 'filepath1';
viewModel.onRestorePlanResponse(restorePlanResponse);
//reset restore options
viewModel.resetRestoreOptions('db2');
// verify that file path, source database, target databasem and last backup get set correctly
assert.equal('', viewModel.lastBackupTaken);
assert.equal('db2', viewModel.sourceDatabaseName);
assert.equal('db2', viewModel.targetDatabaseName);
assert.equal('', viewModel.lastBackupTaken);
assert.equal(0, viewModel.databaseList.length);
// verify that advanced options get set correctly
options = {};
viewModel.getRestoreAdvancedOptions(options);
assert.equal(undefined, options[option1String]);
// verify that selected backup sets get set correctly
let selectedBackupSets = viewModel.selectedBackupSets;
assert.equal(undefined, selectedBackupSets);
});
test('update options with config info should update option correctly', () => {
let databaseList = ['db1', 'db2'];
let configInfo: { [key: string]: any } = {};
configInfo['sourceDatabaseNamesWithBackupSets'] = databaseList;
configInfo[option1String] = 'option1 from config info';
viewModel.updateOptionWithConfigInfo(configInfo);
assert.equal(3, viewModel.databaseList.length);
assert.equal('', viewModel.databaseList[0]);
assert.equal(databaseList[1], viewModel.databaseList[1]);
assert.equal(databaseList[2], viewModel.databaseList[2]);
assert.equal('option1 from config info', viewModel.getOptionValue(option1String));
// verify that the options from get restore advanced options doesn't contain option1String
options = {};
viewModel.getRestoreAdvancedOptions(options);
assert.equal(undefined, options[option1String]);
});
test('on restore from changed should set readHeaderFromMedia and reset the source database names and selected database name correctly', () => {
viewModel.databaseList = ['', 'db1', 'db2'];
viewModel.sourceDatabaseName = 'sourceDatabase';
viewModel.filePath = 'filepath';
viewModel.readHeaderFromMedia = false;
viewModel.onRestoreFromChanged(true);
assert.equal(true, viewModel.readHeaderFromMedia);
assert.equal('', viewModel.sourceDatabaseName);
assert.equal('', viewModel.filePath);
viewModel.sourceDatabaseName = 'sourceDatabase2';
viewModel.onRestoreFromChanged(false);
assert.equal(false, viewModel.readHeaderFromMedia);
assert.equal('', viewModel.sourceDatabaseName);
});
});

View File

@@ -0,0 +1,132 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { InsightsDialogController } from 'sql/parts/insights/node/insightsDialogController';
import { InsightsDialogModel } from 'sql/parts/insights/common/insightsDialogModel';
import QueryRunner from 'sql/parts/query/execution/queryRunner';
import { ConnectionManagementService } from 'sql/parts/connection/common/connectionManagementService';
import { IInsightsConfigDetails } from 'sql/parts/dashboard/widgets/insights/interfaces';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IDbColumn, BatchSummary, QueryExecuteSubsetResult, ResultSetSubset } from 'data';
import { EventEmitter } from 'events';
import { equal } from 'assert';
import { Mock, MockBehavior, It } from 'typemoq';
const testData: string[][] = [
['1', '2', '3', '4'],
['5', '6', '7', '8']
];
const testColumns: string[] = [
'col1',
'col2'
];
suite('Insights Dialog Controller Tests', () => {
test('updates correctly with good input', done => {
let model = new InsightsDialogModel();
let { runner, complete } = getPrimedQueryRunner(testData, testColumns);
let instMoq = Mock.ofType(InstantiationService, MockBehavior.Strict);
instMoq.setup(x => x.createInstance<QueryRunner>(It.isValue(QueryRunner), It.isAny(), undefined))
.returns(() => runner);
let connMoq = Mock.ofType(ConnectionManagementService, MockBehavior.Strict, {}, {});
connMoq.setup(x => x.connect(It.isAny(), It.isAny()))
.returns(() => Promise.resolve(undefined));
let controller = new InsightsDialogController(
model,
undefined,
undefined,
instMoq.object,
connMoq.object
);
let profile: IConnectionProfile = {
serverName: 'server',
databaseName: 'database',
userName: 'user',
password: '',
authenticationType: '',
savePassword: true,
groupFullName: '',
groupId: '',
getOptionsKey: () => '',
matches: undefined,
providerName: '',
saveProfile: true,
id: '',
options: {}
};
controller.update(<IInsightsConfigDetails>{ query: 'query' }, profile).then(() => {
// Once we update the controller, listen on when it changes the model and verify the data it
// puts in is correct
model.onDataChange(() => {
for (let i = 0; i < testData.length; i++) {
for (let j = 0; j < testData[i].length; j++) {
equal(testData[i][j], model.rows[i][j]);
}
}
done();
});
// Fake the query Runner telling the controller the query is complete
complete();
});
});
});
interface IPrimedQueryRunner {
runner: QueryRunner;
complete: () => void;
}
/**
* Returns a mock of query runner than will recreate what a query runner does to return data
*/
function getPrimedQueryRunner(data: string[][], columns: string[]): IPrimedQueryRunner {
let eventEmitter = new EventEmitter();
let querymock = Mock.ofType(QueryRunner, MockBehavior.Strict);
querymock.setup(x => x.eventEmitter).returns(x => eventEmitter);
querymock.setup(x => x.batchSets).returns(x => {
return <Array<BatchSummary>>[
{
id: 0,
resultSetSummaries: [
{
columnInfo: <Array<IDbColumn>>columns.map(c => { return { columnName: c }; }),
id: 0,
rowCount: data.length
}
]
}
];
});
querymock.setup(x => x.getQueryRows(It.isAnyNumber(), It.isAnyNumber(), It.isAnyNumber(), It.isAnyNumber()))
.returns(x => Promise.resolve(<QueryExecuteSubsetResult>{
resultSubset: <ResultSetSubset>{
rowCount: data.length,
rows: data.map(r => r.map(c => { return { displayValue: c }; }))
}
}));
querymock.setup(x => x.runQuery(It.isAnyString())).returns(x => Promise.resolve());
let complete = () => {
eventEmitter.emit('complete');
};
return {
runner: querymock.object,
complete
};
}

View File

@@ -0,0 +1,253 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IInsightsLabel, IInsightsConfigDetails } from 'sql/parts/dashboard/widgets/insights/interfaces';
import { InsightsDialogModel } from 'sql/parts/insights/common/insightsDialogModel';
import { isUndefinedOrNull } from 'vs/base/common/types';
import * as assert from 'assert';
suite('Insights Dialog Model Tests', () => {
test('does parse condition right', () => {
let insightsDialogModel = new InsightsDialogModel();
let label: IInsightsLabel = {
column: undefined,
state: [
{
condition: {
if: 'always'
},
color: 'green'
}
]
} as IInsightsLabel;
insightsDialogModel.insight = { label } as IInsightsConfigDetails;
insightsDialogModel.rows = [
['label1', 'value1'],
['label2', 'value2'],
['label3', 'value3']
];
let result = insightsDialogModel.getListResources(0, 1);
for (let resource of result) {
assert.equal(resource.stateColor, 'green', 'always Condition did not return val as expected');
}
label.state = [
{
condition: {
if: 'equals',
equals: 'specific value'
},
color: 'green'
}
];
insightsDialogModel.insight = { label } as IInsightsConfigDetails;
insightsDialogModel.rows = [
['label1', 'specific value'],
['label2', 'value2'],
['label3', 'value3']
];
result = insightsDialogModel.getListResources(0, 1);
assert.equal(result[0].stateColor, 'green', 'always Condition did not return val as expected');
assert.equal(isUndefinedOrNull(result[1].stateColor), true, 'always Condition did not return val as expected');
assert.equal(isUndefinedOrNull(result[2].stateColor), true, 'always Condition did not return val as expected');
label.state = [
{
condition: {
if: 'equals',
equals: 'specific value'
},
color: 'green'
},
{
condition: {
if: 'equals',
equals: 'specific value2'
},
color: 'red'
}
];
insightsDialogModel.insight = { label } as IInsightsConfigDetails;
insightsDialogModel.rows = [
['label1', 'specific value'],
['label2', 'specific value2'],
['label3', 'value3']
];
result = insightsDialogModel.getListResources(0, 1);
assert.equal(result[0].stateColor, 'green', 'always Condition did not return val as expected');
assert.equal(result[1].stateColor, 'red', 'always Condition did not return val as expected');
assert.equal(isUndefinedOrNull(result[2].stateColor), true, 'always Condition did not return val as expected');
label.state = [
{
condition: {
if: 'greaterThan',
equals: '2'
},
color: 'green'
},
{
condition: {
if: 'equals',
equals: 'specific value2'
},
color: 'red'
}
];
insightsDialogModel.insight = { label } as IInsightsConfigDetails;
insightsDialogModel.rows = [
['label1', '3'],
['label2', 'specific value2'],
['label3', 'value3']
];
result = insightsDialogModel.getListResources(0, 1);
assert.equal(result[0].stateColor, 'green', 'always Condition did not return val as expected');
assert.equal(result[1].stateColor, 'red', 'always Condition did not return val as expected');
assert.equal(isUndefinedOrNull(result[2].stateColor), true, 'always Condition did not return val as expected');
label.state = [
{
condition: {
if: 'greaterThanOrEquals',
equals: '2'
},
color: 'green'
},
{
condition: {
if: 'equals',
equals: 'specific value2'
},
color: 'red'
}
];
insightsDialogModel.insight = { label } as IInsightsConfigDetails;
insightsDialogModel.rows = [
['label1', '2'],
['label2', 'specific value2'],
['label3', 'value3']
];
result = insightsDialogModel.getListResources(0, 1);
assert.equal(result[0].stateColor, 'green', 'always Condition did not return val as expected');
assert.equal(result[1].stateColor, 'red', 'always Condition did not return val as expected');
assert.equal(isUndefinedOrNull(result[2].stateColor), true, 'always Condition did not return val as expected');
label.state = [
{
condition: {
if: 'lessThan',
equals: '8'
},
color: 'green'
},
{
condition: {
if: 'equals',
equals: 'specific value2'
},
color: 'red'
}
];
insightsDialogModel.insight = { label } as IInsightsConfigDetails;
insightsDialogModel.rows = [
['label1', '5'],
['label2', 'specific value2'],
['label3', 'value3']
];
result = insightsDialogModel.getListResources(0, 1);
assert.equal(result[0].stateColor, 'green', 'always Condition did not return val as expected');
assert.equal(result[1].stateColor, 'red', 'always Condition did not return val as expected');
assert.equal(isUndefinedOrNull(result[2].stateColor), true, 'always Condition did not return val as expected');
label.state = [
{
condition: {
if: 'lessThanOrEquals',
equals: '8'
},
color: 'green'
},
{
condition: {
if: 'equals',
equals: 'specific value2'
},
color: 'red'
}
];
insightsDialogModel.insight = { label } as IInsightsConfigDetails;
insightsDialogModel.rows = [
['label1', '8'],
['label2', 'specific value2'],
['label3', 'value3']
];
result = insightsDialogModel.getListResources(0, 1);
assert.equal(result[0].stateColor, 'green', 'always Condition did not return val as expected');
assert.equal(result[1].stateColor, 'red', 'always Condition did not return val as expected');
assert.equal(isUndefinedOrNull(result[2].stateColor), true, 'always Condition did not return val as expected');
label.state = [
{
condition: {
if: 'notEquals',
equals: '9'
},
color: 'green'
},
{
condition: {
if: 'equals',
equals: 'specific value2'
},
color: 'red'
}
];
insightsDialogModel.insight = { label } as IInsightsConfigDetails;
insightsDialogModel.rows = [
['label1', '8'],
['label2', '9'],
['label3', 'value3']
];
result = insightsDialogModel.getListResources(0, 1);
assert.equal(result[0].stateColor, 'green', 'always Condition did not return val as expected');
assert.equal(isUndefinedOrNull(result[1].stateColor), true, 'always Condition did not return val as expected');
assert.equal(result[2].stateColor, 'green', 'always Condition did not return val as expected');
label.state = [
{
condition: {
if: 'notEquals',
equals: '9'
},
color: 'green'
},
{
condition: {
if: 'always'
},
color: 'red'
}
];
insightsDialogModel.insight = { label } as IInsightsConfigDetails;
insightsDialogModel.rows = [
['label1', '8'],
['label2', 'specific value2'],
['label3', 'value3']
];
result = insightsDialogModel.getListResources(0, 1);
assert.equal(result[0].stateColor, 'green', 'always Condition did not return val as expected');
assert.equal(result[1].stateColor, 'green', 'always Condition did not return val as expected');
assert.equal(result[2].stateColor, 'green', 'always Condition did not return val as expected');
});
});

View File

@@ -0,0 +1,567 @@
/*---------------------------------------------------------------------------------------------
* 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 { Emitter } from 'vs/base/common/event';
import { TPromise } from 'vs/base/common/winjs.base';
import { ISelectionData } from 'data';
import {
IConnectionManagementService,
IConnectionParams,
INewConnectionParams,
ConnectionType,
RunQueryOnConnectionMode
} from 'sql/parts/connection/common/connectionManagement';
import { ConnectionDialogService } from 'sql/parts/connection/connectionDialog/connectionDialogService';
import {
RunQueryAction, CancelQueryAction, ListDatabasesActionItem,
DisconnectDatabaseAction, ConnectDatabaseAction, QueryTaskbarAction
} from 'sql/parts/query/execution/queryActions';
import { QueryInput } from 'sql/parts/query/common/queryInput';
import { QueryEditor } from 'sql/parts/query/editor/queryEditor';
import { QueryModelService } from 'sql/parts/query/execution/queryModelService';
import { ConnectionManagementService } from 'sql/parts/connection/common/connectionManagementService';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { TestThemeService } from 'sqltest/stubs/themeTestService';
import * as TypeMoq from 'typemoq';
import * as assert from 'assert';
let none: void;
suite('SQL QueryAction Tests', () => {
let testUri: string = 'testURI';
let editor: TypeMoq.Mock<QueryEditor>;
let calledRunQueryOnInput: boolean = undefined;
let testQueryInput: TypeMoq.Mock<QueryInput>;
setup(() => {
// Setup a reusable mock QueryInput
testQueryInput = TypeMoq.Mock.ofType(QueryInput, TypeMoq.MockBehavior.Strict);
testQueryInput.setup(x => x.uri).returns(() => testUri);
testQueryInput.setup(x => x.runQuery(undefined)).callback(() => { calledRunQueryOnInput = true; });
// Setup a reusable mock QueryEditor
editor = TypeMoq.Mock.ofType(QueryEditor, TypeMoq.MockBehavior.Strict, undefined, new TestThemeService());
editor.setup(x => x.connectedUri).returns(() => testUri);
editor.setup(x => x.currentQueryInput).returns(() => testQueryInput.object);
editor.setup(x => x.uri).returns(() => testUri);
editor.setup(x => x.getSelection()).returns(() => undefined);
editor.setup(x => x.getSelection(false)).returns(() => undefined);
editor.setup(x => x.isSelectionEmpty()).returns(() => false);
});
test('setClass sets child CSS class correctly', (done) => {
// If I create a RunQueryAction
let queryAction: QueryTaskbarAction = new RunQueryAction(undefined, undefined, undefined);
// "class should automatically get set to include the base class and the RunQueryAction class
let className = RunQueryAction.EnabledClass;
assert.equal(queryAction.class, className, 'CSS class not properly set');
done();
});
test('getConnectedQueryEditorUri returns connected URI only if connected', (done) => {
// ... Create assert variables
let isConnectedReturnValue: boolean = false;
// ... Mock "isConnected in ConnectionManagementService
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, {});
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnectedReturnValue);
// ... Create an editor
let editor = TypeMoq.Mock.ofType(QueryEditor, TypeMoq.MockBehavior.Loose, undefined, new TestThemeService());
editor.setup(x => x.currentQueryInput).returns(() => testQueryInput.object);
// If I create a QueryTaskbarAction and I pass a non-connected editor to _getConnectedQueryEditorUri
let queryAction: QueryTaskbarAction = new RunQueryAction(undefined, undefined, connectionManagementService.object);
let connected: boolean = queryAction.isConnected(editor.object);
// I should get an unconnected state
assert(!connected, 'Non-connected editor should get back an undefined URI');
// If I run with a connected URI
isConnectedReturnValue = true;
connected = queryAction.isConnected(editor.object);
// I should get a connected state
assert(connected, 'Connected editor should get back a non-undefined URI');
done();
});
test('RunQueryAction calls runQuery() only if URI is connected', (done) => {
// ... Create assert variables
let isConnected: boolean = undefined;
let connectionParams: INewConnectionParams = undefined;
let calledRunQuery: boolean = false;
let countCalledShowDialog: number = 0;
// ... Mock "showDialog" ConnectionDialogService
let connectionDialogService = TypeMoq.Mock.ofType(ConnectionDialogService, TypeMoq.MockBehavior.Loose);
connectionDialogService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), undefined, undefined))
.callback((service: IConnectionManagementService, params: INewConnectionParams) => {
connectionParams = params;
countCalledShowDialog++;
})
.returns(() => TPromise.as(none));
// ... Mock "isConnected" in ConnectionManagementService
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, {}, connectionDialogService.object);
connectionManagementService.callBase = true;
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
// ... Mock QueryModelService
let queryModelService = TypeMoq.Mock.ofType(QueryModelService, TypeMoq.MockBehavior.Loose);
queryModelService.setup(x => x.runQuery(TypeMoq.It.isAny(), undefined, TypeMoq.It.isAny(), TypeMoq.It.isAny())).callback(() => {
calledRunQuery = true;
});
// If I call run on RunQueryAction when I am not connected
let queryAction: RunQueryAction = new RunQueryAction(editor.object, queryModelService.object, connectionManagementService.object);
isConnected = false;
calledRunQueryOnInput = false;
queryAction.run();
// runQuery should not be run
assert.equal(calledRunQueryOnInput, false, 'run should not call runQuery');
testQueryInput.verify(x => x.runQuery(undefined), TypeMoq.Times.never());
// and the conneciton dialog should open with the correct parameter details
assert.equal(countCalledShowDialog, 1, 'run should call showDialog');
assert.equal(connectionParams.connectionType, ConnectionType.editor, 'connectionType should be queryEditor');
assert.equal(connectionParams.runQueryOnCompletion, RunQueryOnConnectionMode.executeQuery, 'runQueryOnCompletion should be true`');
assert.equal(connectionParams.input.uri, testUri, 'URI should be set to the test URI');
assert.equal(connectionParams.input, editor.object.currentQueryInput, 'Editor should be set to the mock editor');
// If I call run on RunQueryAction when I am connected
isConnected = true;
queryAction.run();
//runQuery should be run, and the conneciton dialog should not open
assert.equal(calledRunQueryOnInput, true, 'run should call runQuery');
testQueryInput.verify(x => x.runQuery(undefined), TypeMoq.Times.once());
assert.equal(countCalledShowDialog, 1, 'run should not call showDialog');
done();
});
test('Queries are only run if the QueryEditor selection is not empty', (done) => {
// ... Create assert variables
let isSelectionEmpty: boolean = undefined;
let countCalledRunQuery: number = 0;
// ... Mock "isSelectionEmpty" in QueryEditor
let queryInput: TypeMoq.Mock<QueryInput> = TypeMoq.Mock.ofType(QueryInput, TypeMoq.MockBehavior.Strict);
queryInput = TypeMoq.Mock.ofType(QueryInput, TypeMoq.MockBehavior.Strict);
queryInput.setup(x => x.uri).returns(() => testUri);
queryInput.setup(x => x.runQuery(undefined)).callback(() => {
countCalledRunQuery++;
});
let queryEditor: TypeMoq.Mock<QueryEditor> = TypeMoq.Mock.ofType(QueryEditor, TypeMoq.MockBehavior.Strict, undefined, new TestThemeService());
queryEditor.setup(x => x.currentQueryInput).returns(() => queryInput.object);
queryEditor.setup(x => x.getSelection()).returns(() => undefined);
queryEditor.setup(x => x.getSelection(false)).returns(() => undefined);
queryEditor.setup(x => x.isSelectionEmpty()).returns(() => isSelectionEmpty);
// ... Mock "isConnected" in ConnectionManagementService
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, {});
connectionManagementService.callBase = true;
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => true);
// ... Mock QueryModelService
let queryModelService = TypeMoq.Mock.ofType(QueryModelService, TypeMoq.MockBehavior.Loose);
// If I call run on RunQueryAction when I have a non empty selection
let queryAction: RunQueryAction = new RunQueryAction(queryEditor.object, queryModelService.object, connectionManagementService.object);
isSelectionEmpty = false;
queryAction.run();
//runQuery should be run
assert.equal(countCalledRunQuery, 1, 'runQuery should be called');
// If I call run on RunQueryAction when I have an empty selection
isSelectionEmpty = true;
queryAction.run();
//runQuery should not be run again
assert.equal(countCalledRunQuery, 1, 'runQuery should not be called again');
done();
});
test('ISelectionData is properly passed when queries are run', (done) => {
/// Setup Test ///
// ... Create assert variables
let isConnected: boolean = undefined;
let countCalledShowDialog: number = 0;
let countCalledRunQuery: number = 0;
let showDialogConnectionParams: INewConnectionParams = undefined;
let runQuerySelection: ISelectionData = undefined;
let selectionToReturnInGetSelection: ISelectionData = undefined;
let predefinedSelection: ISelectionData = { startLine: 1, startColumn: 2, endLine: 3, endColumn: 4 };
// ... Mock "showDialog" ConnectionDialogService
let connectionDialogService = TypeMoq.Mock.ofType(ConnectionDialogService, TypeMoq.MockBehavior.Loose);
connectionDialogService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), undefined, undefined))
.callback((service: IConnectionManagementService, params: INewConnectionParams) => {
showDialogConnectionParams = params;
countCalledShowDialog++;
})
.returns(() => TPromise.as(none));
// ... Mock "getSelection" in QueryEditor
let queryInput = TypeMoq.Mock.ofType(QueryInput, TypeMoq.MockBehavior.Loose);
queryInput.setup(x => x.uri).returns(() => testUri);
queryInput.setup(x => x.runQuery(TypeMoq.It.isAny())).callback((selection: ISelectionData) => {
runQuerySelection = selection;
countCalledRunQuery++;
});
queryInput.setup(x => x.runQuery(undefined)).callback((selection: ISelectionData) => {
runQuerySelection = selection;
countCalledRunQuery++;
});
// ... Mock "getSelection" in QueryEditor
let queryEditor: TypeMoq.Mock<QueryEditor> = TypeMoq.Mock.ofType(QueryEditor, TypeMoq.MockBehavior.Loose, undefined, new TestThemeService());
queryEditor.setup(x => x.currentQueryInput).returns(() => queryInput.object);
queryEditor.setup(x => x.getSelection()).returns(() => {
return selectionToReturnInGetSelection;
});
// ... Mock "isConnected" in ConnectionManagementService
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, {}, connectionDialogService.object);
connectionManagementService.callBase = true;
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
/// End Setup Test ///
////// If I call run on RunQueryAction while disconnected and with an undefined selection
let queryAction: RunQueryAction = new RunQueryAction(queryEditor.object, undefined, connectionManagementService.object);
isConnected = false;
selectionToReturnInGetSelection = undefined;
queryAction.run();
// The conneciton dialog should open with an undefined seleciton
assert.equal(countCalledShowDialog, 1, 'run should call showDialog');
assert.equal(countCalledRunQuery, 0, 'run should not call runQuery');
assert.equal(showDialogConnectionParams.connectionType, ConnectionType.editor, 'connectionType should be queryEditor');
assert.equal(showDialogConnectionParams.querySelection, undefined, 'querySelection should be undefined');
////// If I call run on RunQueryAction while disconnected and with a defined selection
isConnected = false;
selectionToReturnInGetSelection = predefinedSelection;
queryAction.run();
// The conneciton dialog should open with the correct seleciton
assert.equal(countCalledShowDialog, 2, 'run should call showDialog again');
assert.equal(countCalledRunQuery, 0, 'run should not call runQuery');
assert.equal(showDialogConnectionParams.connectionType, ConnectionType.editor, 'connectionType should be queryEditor');
assert.notEqual(showDialogConnectionParams.querySelection, undefined, 'There should not be an undefined selection in runQuery');
assert.equal(showDialogConnectionParams.querySelection.startLine, selectionToReturnInGetSelection.startLine, 'startLine should match');
assert.equal(showDialogConnectionParams.querySelection.startColumn, selectionToReturnInGetSelection.startColumn, 'startColumn should match');
assert.equal(showDialogConnectionParams.querySelection.endLine, selectionToReturnInGetSelection.endLine, 'endLine should match');
assert.equal(showDialogConnectionParams.querySelection.endColumn, selectionToReturnInGetSelection.endColumn, 'endColumn should match');
////// If I call run on RunQueryAction while connected and with an undefined selection
isConnected = true;
selectionToReturnInGetSelection = undefined;
queryAction.run();
// The query should run with an undefined selection
assert.equal(countCalledShowDialog, 2, 'run should not call showDialog');
assert.equal(countCalledRunQuery, 1, 'run should call runQuery');
assert.equal(runQuerySelection, undefined, 'There should be an undefined selection in runQuery');
////// If I call run on RunQueryAction while connected and with a defined selection
isConnected = true;
selectionToReturnInGetSelection = predefinedSelection;
queryAction.run();
// The query should run with the given seleciton
assert.equal(countCalledShowDialog, 2, 'run should not call showDialog');
assert.equal(countCalledRunQuery, 2, 'run should call runQuery again');
assert.notEqual(runQuerySelection, undefined, 'There should not be an undefined selection in runQuery');
assert.equal(runQuerySelection.startLine, selectionToReturnInGetSelection.startLine, 'startLine should match');
assert.equal(runQuerySelection.startColumn, selectionToReturnInGetSelection.startColumn, 'startColumn should match');
assert.equal(runQuerySelection.endLine, selectionToReturnInGetSelection.endLine, 'endLine should match');
assert.equal(runQuerySelection.endColumn, selectionToReturnInGetSelection.endColumn, 'endColumn should match');
done();
});
test('CancelQueryAction calls cancelQuery() only if URI is connected', (done) => {
// ... Create assert variables
let isConnected: boolean = undefined;
let calledCancelQuery: boolean = false;
// ... Mock "isConnected" in ConnectionManagementService
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, {});
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
// ... Mock QueryModelService
let queryModelService = TypeMoq.Mock.ofType(QueryModelService, TypeMoq.MockBehavior.Loose);
queryModelService.setup(x => x.cancelQuery(TypeMoq.It.isAny())).callback(() => {
calledCancelQuery = true;
});
// If I call run on CancelQueryAction when I am not connected
let queryAction: CancelQueryAction = new CancelQueryAction(editor.object, queryModelService.object, connectionManagementService.object);
isConnected = false;
queryAction.run();
// cancelQuery should not be run
assert.equal(calledCancelQuery, false, 'run should not call cancelQuery');
// If I call run on CancelQueryAction when I am connected
isConnected = true;
queryAction.run();
// cancelQuery should be run
assert.equal(calledCancelQuery, true, 'run should call cancelQuery');
done();
});
// We want to call disconnectEditor regardless of connection to be able to cancel in-progress connections
test('DisconnectDatabaseAction calls disconnectEditor regardless of URI being connected', (done) => {
// ... Create assert variables
let isConnected: boolean = undefined;
let countCalledDisconnectEditor: number = 0;
// ... Mock "isConnected" and "disconnectEditor" in ConnectionManagementService
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, {});
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
connectionManagementService.setup(x => x.disconnectEditor(TypeMoq.It.isAny())).callback(() => {
countCalledDisconnectEditor++;
});
// If I call run on DisconnectDatabaseAction when I am not connected
let queryAction: DisconnectDatabaseAction = new DisconnectDatabaseAction(editor.object, connectionManagementService.object);
isConnected = false;
queryAction.run();
// disconnectEditor should be run
assert.equal(countCalledDisconnectEditor, 1, 'disconnectEditor should be called when URI is not connected');
// If I call run on DisconnectDatabaseAction when I am connected
isConnected = true;
queryAction.run();
// disconnectEditor should be run again
assert.equal(countCalledDisconnectEditor, 2, 'disconnectEditor should be called when URI is connected');
done();
});
test('ConnectDatabaseAction opens dialog regardless of URI connection state', (done) => {
// ... Create assert variables
let isConnected: boolean = undefined;
let connectionParams: INewConnectionParams = undefined;
let countCalledShowDialog: number = 0;
// ... Mock "showDialog" ConnectionDialogService
let connectionDialogService = TypeMoq.Mock.ofType(ConnectionDialogService, TypeMoq.MockBehavior.Loose);
connectionDialogService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), undefined, undefined))
.callback((service: IConnectionManagementService, params: INewConnectionParams) => {
connectionParams = params;
countCalledShowDialog++;
})
.returns(() => TPromise.as(none));
// ... Mock "isConnected" in ConnectionManagementService
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, {}, connectionDialogService.object);
connectionManagementService.callBase = true;
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
// If I call run on ConnectDatabaseAction when I am not connected
let queryAction: ConnectDatabaseAction = new ConnectDatabaseAction(editor.object, false, connectionManagementService.object);
isConnected = false;
queryAction.run();
// The conneciton dialog should open with the correct parameter details
assert.equal(countCalledShowDialog, 1, 'run should call showDialog');
assert.equal(connectionParams.connectionType, ConnectionType.editor, 'connectionType should be queryEditor');
assert.equal(connectionParams.runQueryOnCompletion, false, 'runQueryOnCompletion should be false`');
assert.equal(connectionParams.input.uri, testUri, 'URI should be set to the test URI');
assert.equal(connectionParams.input, editor.object.currentQueryInput, 'Editor should be set to the mock editor');
// If I call run on ConnectDatabaseAction when I am connected
isConnected = true;
queryAction.run();
// The conneciton dialog should open again with the correct parameter details
assert.equal(countCalledShowDialog, 2, 'run should call showDialog');
assert.equal(connectionParams.connectionType, ConnectionType.editor, 'connectionType should be queryEditor');
assert.equal(connectionParams.runQueryOnCompletion, false, 'runQueryOnCompletion should be false`');
assert.equal(connectionParams.input.uri, testUri, 'URI should be set to the test URI');
assert.equal(connectionParams.input, editor.object.currentQueryInput, 'Editor should be set to the mock editor');
done();
});
test('ChangeConnectionAction connects regardless of URI being connected', (done) => {
// ... Create assert variables
let queryAction: ConnectDatabaseAction = undefined;
let isConnected: boolean = undefined;
let connectionParams: INewConnectionParams = undefined;
let calledShowDialog: number = 0;
// ... Mock "showDialog" ConnectionDialogService
let connectionDialogService = TypeMoq.Mock.ofType(ConnectionDialogService, TypeMoq.MockBehavior.Loose);
connectionDialogService.setup(x => x.showDialog(TypeMoq.It.isAny(), TypeMoq.It.isAny(), undefined, undefined))
.callback((service: IConnectionManagementService, params: INewConnectionParams) => {
calledShowDialog++;
connectionParams = params;
})
.returns(() => TPromise.as(none));
// ... Mock "isConnected" in ConnectionManagementService
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, {}, connectionDialogService.object);
connectionManagementService.callBase = true;
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
// If I call run on ChangeConnectionAction when I am not connected
queryAction = new ConnectDatabaseAction(editor.object, false, connectionManagementService.object);
isConnected = false;
queryAction.run();
// The conneciton dialog should open with the params set as below
assert.equal(calledShowDialog, 1, 'showDialog should be called when URI is connected');
assert.equal(connectionParams.connectionType, ConnectionType.editor, 'connectionType should be queryEditor');
assert.equal(connectionParams.runQueryOnCompletion, false, 'runQueryOnCompletion should be false`');
assert.equal(connectionParams.input.uri, testUri, 'URI should be set to the test URI');
assert.equal(connectionParams.input, editor.object.currentQueryInput, 'Editor should be set to the mock editor');
// Then if I call run on ChangeConnectionAction when I am connected
isConnected = true;
queryAction.run();
// The conneciton dialog should open with the params set as below
assert.equal(calledShowDialog, 2, 'showDialog should be called when URI is connected');
assert.equal(connectionParams.connectionType, ConnectionType.editor, 'connectionType should be queryEditor');
assert.equal(connectionParams.runQueryOnCompletion, false, 'runQueryOnCompletion should be false`');
assert.equal(connectionParams.input.uri, testUri, 'URI should be set to the test URI');
assert.equal(connectionParams.input, editor.object.currentQueryInput, 'Editor should be set to the mock editor');
done();
});
test('ListDatabaseItem shows items as expected', (done) => {
// ... Create assert variables
let listItem: ListDatabasesActionItem = undefined;
let isConnected: boolean = undefined;
let databaseName: string = undefined;
// ... Mock "isConnected" in ConnectionManagementService
let connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, {});
connectionManagementService.callBase = true;
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAnyString())).returns(() => isConnected);
connectionManagementService.setup(x => x.getConnectionProfile(TypeMoq.It.isAny())).returns(() => <IConnectionProfile>{
databaseName: databaseName
});
// If I query without having initialized anything, state should be clear
listItem = new ListDatabasesActionItem(editor.object, undefined, connectionManagementService.object, undefined, undefined, undefined);
assert.equal(listItem.isEnabled(), false, 'do not expect dropdown enabled unless connected');
assert.equal(listItem.currentDatabaseName, undefined, 'do not expect dropdown to have entries unless connected');
// When I connect, database name should be returned in the dropdown and this should be enabled
isConnected = true;
databaseName = 'master';
listItem.onConnected();
assert.equal(listItem.isEnabled(), true, 'expect dropdown enabled when connected');
assert.equal(listItem.currentDatabaseName, 'master', 'expect dropdown to have current DB name when connected');
// When I disconnect, state should return to default
isConnected = false;
databaseName = undefined;
listItem.onDisconnect();
assert.equal(listItem.isEnabled(), false, 'do not expect dropdown enabled unless connected');
assert.equal(listItem.currentDatabaseName, undefined, 'do not expect dropdown to have entries unless connected');
done();
});
test('ListDatabaseItem - null event params', () => {
// Setup:
// ... Create event emitter we can use to trigger db changed event
let dbChangedEmitter = new Emitter<IConnectionParams>();
// ... Create mock connection management service
let databaseName = 'foobar';
let cms = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, {});
cms.callBase = true;
cms.setup(x => x.onConnectionChanged).returns(() => dbChangedEmitter.event);
cms.setup(x => x.getConnectionProfile(TypeMoq.It.isAny())).returns(() => <IConnectionProfile>{ databaseName: databaseName });
// ... Create a database dropdown that has been connected
let listItem = new ListDatabasesActionItem(editor.object, undefined, cms.object, null, null, null);
listItem.onConnected();
// If: I raise a connection changed event
let eventParams = null;
dbChangedEmitter.fire(eventParams);
// Then: The selected database should not have changed
assert.equal(listItem.currentDatabaseName, databaseName);
});
test('ListDatabaseItem - wrong uri', () => {
// Setup:
// ... Create event emitter we can use to trigger db changed event
let dbChangedEmitter = new Emitter<IConnectionParams>();
// ... Create mock connection management service that will not claim it's connected
let databaseName = 'foobar';
let cms = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, {});
cms.callBase = true;
cms.setup(x => x.onConnectionChanged).returns(() => dbChangedEmitter.event);
cms.setup(x => x.getConnectionProfile(TypeMoq.It.isAny())).returns(() => <IConnectionProfile>{ databaseName: databaseName });
// ... Create a database dropdown that has been connected
let listItem = new ListDatabasesActionItem(editor.object, undefined, cms.object, null, null, null);
listItem.onConnected();
// If: I raise a connection changed event for the 'wrong' URI
let eventParams = <IConnectionParams> {
connectionProfile: {
databaseName: 'foobarbaz'
},
connectionUri: 'foobarUri'
};
dbChangedEmitter.fire(eventParams);
// Then: The selected database should not have changed
assert.equal(listItem.currentDatabaseName, databaseName);
});
test('ListDatabaseItem - updates when connected and uri matches', () => {
// Setup:
// ... Create event emitter we can use to trigger db changed event
let dbChangedEmitter = new Emitter<IConnectionParams>();
// ... Create mock connection management service
let cms = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, {}, {});
cms.callBase = true;
cms.setup(x => x.onConnectionChanged).returns(() => dbChangedEmitter.event);
// ... Create a database dropdown
let listItem = new ListDatabasesActionItem(editor.object, undefined, cms.object, null, null, null);
// If: I raise a connection changed event
let eventParams = <IConnectionParams> {
connectionProfile: {
databaseName: 'foobarbaz'
},
connectionUri: editor.object.uri
};
dbChangedEmitter.fire(eventParams);
// Then:
// ... The connection should have changed to the provided database
assert.equal(listItem.currentDatabaseName, eventParams.connectionProfile.databaseName);
});
});

View File

@@ -0,0 +1,391 @@
/*---------------------------------------------------------------------------------------------
* 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 { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
import { IMessageService } from 'vs/platform/message/common/message';
import { TestMessageService, TestEditorGroupService } from 'vs/workbench/test/workbenchTestServices';
import { IEditorDescriptor, EditorInput } from 'vs/workbench/common/editor';
import { TPromise } from 'vs/base/common/winjs.base';
import URI from 'vs/base/common/uri';
import * as DOM from 'vs/base/browser/dom';
import { Memento } from 'vs/workbench/common/memento';
import { Builder } from 'vs/base/browser/builder';
import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput';
import { QueryResultsInput } from 'sql/parts/query/common/queryResultsInput';
import { QueryEditor } from 'sql/parts/query/editor/queryEditor';
import { QueryModelService } from 'sql/parts/query/execution/queryModelService';
import { QueryInput } from 'sql/parts/query/common/queryInput';
import { INewConnectionParams, ConnectionType, RunQueryOnConnectionMode } from 'sql/parts/connection/common/connectionManagement';
import { ConnectionManagementService } from 'sql/parts/connection/common/connectionManagementService';
import { RunQueryAction, ListDatabasesActionItem } from 'sql/parts/query/execution/queryActions';
import { EditorDescriptorService } from 'sql/parts/query/editor/editorDescriptorService';
import { TestThemeService } from 'sqltest/stubs/themeTestService';
import * as TypeMoq from 'typemoq';
import * as assert from 'assert';
suite('SQL QueryEditor Tests', () => {
let queryModelService: QueryModelService;
let instantiationService: TypeMoq.Mock<InstantiationService>;
let themeService: TestThemeService = new TestThemeService();
let messageService: TypeMoq.Mock<IMessageService>;
let editorDescriptorService: TypeMoq.Mock<EditorDescriptorService>;
let connectionManagementService: TypeMoq.Mock<ConnectionManagementService>;
let memento: TypeMoq.Mock<Memento>;
let queryInput: QueryInput;
let queryInput2: QueryInput;
let parentBuilder: Builder;
let mockEditor: any;
let getQueryEditor = function (): QueryEditor {
return new QueryEditor(
undefined,
themeService,
instantiationService.object,
undefined,
undefined,
undefined,
editorDescriptorService.object,
undefined,
undefined,
undefined,
undefined);
};
setup(() => {
// Setup DOM elements
let element = DOM.$('queryEditorParent');
parentBuilder = new Builder(element);
// Create object to mock the Editor classes
// QueryResultsEditor fails at runtime due to the way we are importing Angualar,
// so a {} mock is used here. This mock simply needs to have empty method stubs
// for all called runtime methods
mockEditor = {
_bootstrapAngular: function () { },
setInput: function () { },
createEditor: function () { },
create: function () { },
setVisible: function () { },
layout: function () { },
dispose: function () { }
};
// Mock InstantiationService to give us our mockEditor
instantiationService = TypeMoq.Mock.ofType(InstantiationService, TypeMoq.MockBehavior.Loose);
instantiationService.setup(x => x.createInstance(TypeMoq.It.isAny())).returns((input) => {
return new TPromise((resolve) => resolve(mockEditor));
});
instantiationService.setup(x => x.createInstance(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns((input) => {
return new TPromise((resolve) => resolve(new RunQueryAction(undefined, undefined, undefined)));
});
// Setup hook to capture calls to create the listDatabase action
instantiationService.setup(x => x.createInstance(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns((classDef, editor, action) => {
if (classDef.ID) {
if (classDef.ID === 'listDatabaseQueryActionItem') {
return new ListDatabasesActionItem(editor, action, connectionManagementService.object, undefined, undefined, undefined);
}
}
// Default
return new RunQueryAction(undefined, undefined, undefined);
});
// Mock EditorDescriptorService to give us a mock editor description
let descriptor: IEditorDescriptor = {
getId: function (): string { return 'id'; },
getName: function (): string { return 'name'; },
describes: function (obj: any): boolean { return true; }
};
editorDescriptorService = TypeMoq.Mock.ofType(EditorDescriptorService, TypeMoq.MockBehavior.Loose);
editorDescriptorService.setup(x => x.getEditor(TypeMoq.It.isAny())).returns(() => descriptor);
// Create a QueryInput
let filePath = 'someFile.sql';
let uri: URI = URI.parse(filePath);
let fileInput = new UntitledEditorInput(uri, false, '', '', '', instantiationService.object, undefined, undefined, undefined);
let queryResultsInput: QueryResultsInput = new QueryResultsInput(uri.fsPath);
queryInput = new QueryInput('first', 'first', fileInput, queryResultsInput, undefined, undefined, undefined, undefined);
// Create a QueryInput to compare to the previous one
let filePath2 = 'someFile2.sql';
let uri2: URI = URI.parse(filePath2);
let fileInput2 = new UntitledEditorInput(uri2, false, '', '', '', instantiationService.object, undefined, undefined, undefined);
let queryResultsInput2: QueryResultsInput = new QueryResultsInput(uri2.fsPath);
queryInput2 = new QueryInput('second', 'second', fileInput2, queryResultsInput2, undefined, undefined, undefined, undefined);
// Mock IMessageService
messageService = TypeMoq.Mock.ofType(TestMessageService, TypeMoq.MockBehavior.Loose);
// Mock ConnectionManagementService
memento = TypeMoq.Mock.ofType(Memento, TypeMoq.MockBehavior.Loose, '');
memento.setup(x => x.getMemento(TypeMoq.It.isAny())).returns(() => void 0);
connectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, memento.object, undefined);
connectionManagementService.callBase = true;
connectionManagementService.setup(x => x.isConnected(TypeMoq.It.isAny())).returns(() => false);
// Create a QueryModelService
queryModelService = new QueryModelService(instantiationService.object, messageService.object);
});
test('createEditor creates only the taskbar', (done) => {
// If I call createEditor
let editor: QueryEditor = getQueryEditor();
editor.createEditor(parentBuilder);
// The taskbar should be created
assert.equal(!!editor.taskbar, true);
assert.equal(!!editor.taskbarContainer, true);
// But Nothing else should be created
assert.equal(!!editor.getContainer(), false);
assert.equal(!!editor.sqlEditor, false);
assert.equal(!!editor.sqlEditorContainer, false);
assert.equal(!!editor.resultsEditor, false);
assert.equal(!!editor.resultsEditorContainer, false);
assert.equal(!!editor.sash, false);
assert.equal(!!editor._isResultsEditorVisible(), false);
done();
});
test('setInput creates SQL components', (done) => {
let assertInput = function () {
// The taskbar SQL, and parent should be created
assert.equal(!!editor.taskbar, true);
assert.equal(!!editor.taskbarContainer, true);
assert.equal(!!editor.getContainer(), true);
assert.equal(!!editor.sqlEditor, true);
assert.equal(!!editor.sqlEditorContainer, true);
// But the results componenets should not
assert.equal(!!editor.resultsEditor, false);
assert.equal(!!editor.resultsEditorContainer, false);
assert.equal(!!editor.sash, false);
assert.equal(!!editor._isResultsEditorVisible(), false);
};
// If I call create a QueryEditor
let editor: QueryEditor = getQueryEditor();
editor.create(parentBuilder);
return editor.setInput(queryInput) // Then I set the input
.then(assertInput) // Only the taskbar SQL, and parent should be created
.then(() => done(), (err) => done(err));
});
test('showQueryResultsEditor creates all components and pins editor', (done) => {
// Mock EditorGroupService to get call count of pinEditor
let editorGroupService = TypeMoq.Mock.ofType(TestEditorGroupService, TypeMoq.MockBehavior.Loose);
// Make the call to showQueryResultsEditor thenable
let showQueryResultsEditor = function () {
return editor._showQueryResultsEditor();
};
// Make the asserts thenable
let assertInput = function () {
assert.equal(!!editor.taskbar, true);
assert.equal(!!editor.taskbarContainer, true);
assert.equal(!!editor.getContainer(), true);
assert.equal(!!editor.sqlEditor, true);
assert.equal(!!editor.sqlEditorContainer, true);
assert.equal(!!editor.resultsEditor, true);
assert.equal(!!editor.resultsEditorContainer, true);
assert.equal(!!editor.sash, true);
assert.equal(!!editor._isResultsEditorVisible(), true);
editorGroupService.verify(x => x.pinEditor(undefined, TypeMoq.It.isAny()), TypeMoq.Times.once());
};
// If I create a QueryEditor
let editor: QueryEditor = new QueryEditor(
undefined,
themeService,
instantiationService.object,
undefined,
undefined,
undefined,
editorDescriptorService.object,
editorGroupService.object,
undefined,
undefined,
undefined,
undefined);
editor.create(parentBuilder);
return editor.setInput(queryInput) // Then I set the input
.then(showQueryResultsEditor) // Then call showQueryResultsEditor
.then(assertInput) // Both editor windows should be created, and the editor should be pinned
.then(() => done(), (err) => done(err));
});
test('Can switch between different input files', (done) => {
// Setup
let firstInput: EditorInput;
let firstContainer: HTMLElement;
let secondInput: EditorInput;
let secondContainer: HTMLElement;
const firstContainerId = 'firstContainerId';
const secondContainerId = 'secondContainerId';
let recordFirstInput = function () {
let input = <QueryInput>editor.input;
firstInput = input.sql;
firstContainer = editor.sqlEditorContainer;
firstContainer.id = firstContainerId;
};
let assertFirstInputIsSet = function () {
assert.notEqual(firstContainer.parentElement, undefined);
};
let setSecondInput = function () {
return editor.setInput(queryInput2);
};
let assertFirstInputIsRemoved = function () {
let input = <QueryInput>editor.input;
secondInput = input.sql;
secondContainer = editor.sqlEditorContainer;
secondContainer.id = secondContainerId;
// The inputs should not match
assert.notEqual(firstInput.getName(), secondInput.getName());
assert.notEqual(firstContainer.id, secondContainer.id);
assert.equal(firstContainer.id, firstContainerId);
// The first input should be disposed
assert.notEqual(firstContainer.parentElement, secondContainer.parentElement);
assert.equal(firstContainer.parentElement, undefined);
// The second input should be added into the DOM
assert.notEqual(secondContainer.parentElement, undefined);
};
let setFirstInputAgain = function () {
return editor.setInput(queryInput);
};
let assertFirstInputIsAddedBack = function () {
let input = <QueryInput>editor.input;
firstInput = input.sql;
firstContainer = editor.sqlEditorContainer;
// The inputs should not match
assert.notEqual(firstInput.getName(), secondInput.getName());
assert.notEqual(firstContainer.id, secondContainer.id);
assert.equal(secondContainer.id, secondContainerId);
// The first input should be added into the DOM
assert.equal(secondContainer.parentElement, undefined);
// The second input should be disposed
assert.notEqual(firstContainer.parentElement, secondContainer.parentElement);
assert.notEqual(firstContainer.parentElement, undefined);
};
// If I create a QueryEditor
let editor: QueryEditor = getQueryEditor();
editor.create(parentBuilder);
return editor.setInput(queryInput) // and I set the input
.then(recordFirstInput) // then I record what the input is
.then(assertFirstInputIsSet) // the input should be set
.then(setSecondInput) // then if I set the input to a new file
.then(assertFirstInputIsRemoved) // the inputs should not match, and the first input should be removed from the DOM
.then(setFirstInputAgain) // then if I set the input back to the original
.then(assertFirstInputIsAddedBack) // the inputs should not match, and the second input should be removed from the DOM
.then(() => done(), (err) => done(err));
});
suite('Action Tests', () => {
let queryActionInstantiationService: TypeMoq.Mock<InstantiationService>;
let queryConnectionService: TypeMoq.Mock<ConnectionManagementService>;
let queryModelService: TypeMoq.Mock<QueryModelService>;
let queryInput: QueryInput;
setup(() => {
// Mock ConnectionManagementService but don't set connected state
memento = TypeMoq.Mock.ofType(Memento, TypeMoq.MockBehavior.Loose, '');
memento.setup(x => x.getMemento(TypeMoq.It.isAny())).returns(() => void 0);
queryConnectionService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Loose, memento.object, undefined);
queryConnectionService.callBase = true;
// Mock InstantiationService to give us the actions
queryActionInstantiationService = TypeMoq.Mock.ofType(InstantiationService, TypeMoq.MockBehavior.Loose);
queryActionInstantiationService.setup(x => x.createInstance(TypeMoq.It.isAny())).returns((input) => {
return new TPromise((resolve) => resolve(mockEditor));
});
queryActionInstantiationService.setup(x => x.createInstance(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns((input) => {
// Default
return new RunQueryAction(undefined, undefined, undefined);
});
// Setup hook to capture calls to create the listDatabase action
queryActionInstantiationService.setup(x => x.createInstance(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()))
.returns((definition, editor, action, selectBox) => {
if (definition.ID === 'listDatabaseQueryActionItem') {
let item = new ListDatabasesActionItem(editor, action, queryConnectionService.object, undefined, undefined, undefined);
return item;
}
// Default
return new RunQueryAction(undefined, undefined, undefined);
});
let fileInput = new UntitledEditorInput(URI.parse('testUri'), false, '', '', '', instantiationService.object, undefined, undefined, undefined);
queryModelService = TypeMoq.Mock.ofType(QueryModelService, TypeMoq.MockBehavior.Loose, undefined, undefined);
queryModelService.callBase = true;
queryInput = new QueryInput(
'testUri',
'',
fileInput,
undefined,
undefined,
undefined,
queryModelService.object,
undefined
);
});
test('Taskbar buttons are set correctly upon standard load', (done) => {
queryConnectionService.setup(x => x.isConnected(TypeMoq.It.isAny())).returns(() => false);
queryModelService.setup(x => x.isRunningQuery(TypeMoq.It.isAny())).returns(() => false);
// If I use the created QueryEditor with no changes since creation
// Buttons should be set as if disconnected
assert.equal(queryInput.runQueryEnabled, true, 'runQueryAction button should be enabled');
assert.equal(queryInput.cancelQueryEnabled, false, 'cancelQueryAction button should not be enabled');
assert.equal(queryInput.connectEnabled, true, 'connectDatabaseAction button should be enabled');
assert.equal(queryInput.disconnectEnabled, false, 'disconnectDatabaseAction button should not be enabled');
assert.equal(queryInput.changeConnectionEnabled, false, 'changeConnectionAction button should not be enabled');
assert.equal(queryInput.listDatabasesConnected, false);
done();
});
test('Taskbar buttons are set correctly upon connect', (done) => {
let params: INewConnectionParams = { connectionType: ConnectionType.editor, runQueryOnCompletion: RunQueryOnConnectionMode.none };
queryInput.onConnectSuccess(params);
queryModelService.setup(x => x.isRunningQuery(TypeMoq.It.isAny())).returns(() => false);
assert.equal(queryInput.runQueryEnabled, true, 'runQueryAction button should be enabled');
assert.equal(queryInput.cancelQueryEnabled, false, 'cancelQueryAction button should not be enabled');
assert.equal(queryInput.connectEnabled, false, 'connectDatabaseAction button should not be enabled');
assert.equal(queryInput.disconnectEnabled, true, 'disconnectDatabaseAction button should be enabled');
assert.equal(queryInput.changeConnectionEnabled, true, 'changeConnectionAction button should be enabled');
assert.equal(queryInput.listDatabasesConnected, true);
done();
});
test('Test that we attempt to dispose query when the queryInput is disposed', (done) => {
let queryResultsInput = new QueryResultsInput('testUri');
queryInput['_results'] = queryResultsInput;
queryInput.dispose();
queryModelService.verify(x => x.disposeQuery(TypeMoq.It.isAnyString()), TypeMoq.Times.once());
done();
});
});
});

View File

@@ -0,0 +1,93 @@
/*---------------------------------------------------------------------------------------------
* 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 { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { ServerTreeView } from 'sql/parts/registeredServer/viewlet/serverTreeView';
import { ConnectionManagementService } from 'sql/parts/connection/common/connectionManagementService';
import { Tree } from 'vs/base/parts/tree/browser/treeImpl';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import * as TypeMoq from 'typemoq';
suite('ServerTreeView onAddConnectionProfile handler tests', () => {
let serverTreeView: ServerTreeView;
let mockTree: TypeMoq.Mock<Tree>;
let mockRefreshTreeMethod: TypeMoq.Mock<Function>;
setup(() => {
let instantiationService = new TestInstantiationService();
let mockConnectionManagementService = TypeMoq.Mock.ofType(ConnectionManagementService, TypeMoq.MockBehavior.Strict, {}, {});
mockConnectionManagementService.setup(x => x.getConnectionGroups()).returns(x => []);
serverTreeView = new ServerTreeView(mockConnectionManagementService.object, instantiationService, undefined, undefined, undefined);
let tree = <Tree>{
clearSelection() { },
getSelection() { },
select(selection) { },
reveal(reveal) { }
};
mockTree = TypeMoq.Mock.ofInstance(tree);
(serverTreeView as any)._tree = mockTree.object;
mockRefreshTreeMethod = TypeMoq.Mock.ofType(Function);
(serverTreeView as any).refreshTree = mockRefreshTreeMethod.object;
mockTree.setup(x => x.clearSelection());
mockTree.setup(x => x.select(TypeMoq.It.isAny()));
});
function runAddConnectionProfileHandler(oldSelection, newProfile) {
mockTree.setup(x => x.getSelection()).returns(() => [oldSelection] || []);
(serverTreeView as any).handleAddConnectionProfile(newProfile);
}
test('onAddConnectionProfile handler selects the new profile when no profile is already selected', () => {
let newProfile = <IConnectionProfile>{
id: 'test_connection'
};
runAddConnectionProfileHandler(undefined, newProfile);
mockRefreshTreeMethod.verify(x => x(), TypeMoq.Times.once());
mockTree.verify(x => x.clearSelection(), TypeMoq.Times.never());
mockTree.verify(x => x.select(TypeMoq.It.is(profile => profile === newProfile)), TypeMoq.Times.once());
});
test('onAddConnectionProfile handler selects the new profile when a different profile is already selected', () => {
let oldProfile = <IConnectionProfile>{
id: 'old_connection'
};
let newProfile = <IConnectionProfile>{
id: 'test_connection'
};
runAddConnectionProfileHandler(oldProfile, newProfile);
mockRefreshTreeMethod.verify(x => x(), TypeMoq.Times.once());
mockTree.verify(x => x.clearSelection(), TypeMoq.Times.once());
mockTree.verify(x => x.select(TypeMoq.It.is(profile => profile === newProfile)), TypeMoq.Times.once());
});
test('onAddConnectionProfile handler does not clear the selection when the new profile is already selected', () => {
let selectionId = 'test_connection';
let oldProfile = <IConnectionProfile>{
id: selectionId
};
let newProfile = <IConnectionProfile>{
id: selectionId
};
runAddConnectionProfileHandler(oldProfile, newProfile);
mockRefreshTreeMethod.verify(x => x(), TypeMoq.Times.once());
mockTree.verify(x => x.clearSelection(), TypeMoq.Times.never());
mockTree.verify(x => x.select(TypeMoq.It.isAny()), TypeMoq.Times.never());
});
test('onAddConnectionProfile handler does not clear the previously selected profile if there is no new one', () => {
let oldProfile = <IConnectionProfile>{
id: 'test_connection'
};
runAddConnectionProfileHandler(oldProfile, undefined);
mockRefreshTreeMethod.verify(x => x(), TypeMoq.Times.once());
mockTree.verify(x => x.clearSelection(), TypeMoq.Times.never());
mockTree.verify(x => x.select(TypeMoq.It.isAny()), TypeMoq.Times.never());
});
});

View File

@@ -0,0 +1,508 @@
/*---------------------------------------------------------------------------------------------
* 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 assert from 'assert';
import * as data from 'data';
import * as TypeMoq from 'typemoq';
import AccountStore from 'sql/services/accountManagement/accountStore';
import { SqlOAuthTestService } from 'sqltest/stubs/sqlOauthServiceStub';
import { AccountDialogController } from 'sql/parts/accountManagement/accountDialog/accountDialogController';
import { AccountManagementService } from 'sql/services/accountManagement/accountManagementService';
import { AccountAdditionResult, AccountProviderAddedEventParams, UpdateAccountListEventParams } from 'sql/services/accountManagement/eventTypes';
import { IAccountStore } from 'sql/services/accountManagement/interfaces';
import { AccountProviderStub } from 'sqltest/stubs/accountManagementStubs';
import { EventVerifierSingle } from 'sqltest/utils/eventVerifier';
import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService';
// SUITE CONSTANTS /////////////////////////////////////////////////////////
const hasAccountProvider: data.AccountProviderMetadata = {
id: 'hasAccounts',
displayName: 'Provider with Accounts'
};
const noAccountProvider: data.AccountProviderMetadata = {
id: 'noAccounts',
displayName: 'Provider without Accounts'
};
const account: data.Account = {
key: {
providerId: hasAccountProvider.id,
accountId: 'testAccount1'
},
displayInfo: {
displayName: 'Test Account 1',
contextualLogo: {light: '', dark: ''},
contextualDisplayName: 'Azure Account'
},
isStale: false,
properties: {}
};
const accountList: data.Account[] = [account];
suite('Account Management Service Tests:', () => {
test('Constructor', () => {
// If: I construct an account management service
let ams = getTestState().accountManagementService;
// Then:
// ... It should be created successfully
// ... Events should be available to register
assert.ok(ams.addAccountProviderEvent);
assert.ok(ams.removeAccountProviderEvent);
assert.ok(ams.updateAccountListEvent);
});
test('Add account - provider exists, account does not exist', done => {
// Setup:
// ... Create account management service with a provider
let state = getTestState();
let mockProvider = getMockAccountProvider();
state.accountManagementService._providers[hasAccountProvider.id] = {
accounts: [],
provider: mockProvider.object,
metadata: hasAccountProvider
};
// ... Add add/update handler to the account store that says account was new
state.mockAccountStore.setup(x => x.addOrUpdate(TypeMoq.It.isValue(account)))
.returns(() => Promise.resolve(<AccountAdditionResult>{
accountModified: false,
accountAdded: true,
changedAccount: account
}));
// If: I ask to add an account
return state.accountManagementService.addAccount(hasAccountProvider.id)
.then(result => {
// Then:
// ... The provider should have been prompted
mockProvider.verify(x => x.prompt(), TypeMoq.Times.once());
// ... The account store should have added/updated
state.mockAccountStore.verify(x => x.addOrUpdate(TypeMoq.It.isValue(account)), TypeMoq.Times.once());
// ... The account list change should have been fired
state.eventVerifierUpdate.assertFiredWithVerify(param => {
assert.equal(param.providerId, hasAccountProvider.id);
assert.ok(Array.isArray(param.accountList));
assert.equal(param.accountList.length, 1);
assert.equal(param.accountList[0], account);
});
// ... The returned account should be the new one
assert.equal(result, account);
})
.then(
() => done(),
err => done(err)
);
});
test('Add account - provider exists, account exists', done => {
// Setup:
// ... Create account management service with a provider
let state = getTestState();
let mockProvider = getMockAccountProvider();
state.accountManagementService._providers[hasAccountProvider.id] = {
accounts: [account],
provider: mockProvider.object,
metadata: hasAccountProvider
};
// ... Add add/update handler to the account store that says account was not new
state.mockAccountStore.setup(x => x.addOrUpdate(TypeMoq.It.isValue(account)))
.returns(() => Promise.resolve(<AccountAdditionResult>{
accountModified: true,
accountAdded: false,
changedAccount: account
}));
// If: I ask to add an account
return state.accountManagementService.addAccount(hasAccountProvider.id)
.then(result => {
// Then:
// ... The provider should have been prompted
mockProvider.verify(x => x.prompt(), TypeMoq.Times.once());
// ... The account store should have added/updated
state.mockAccountStore.verify(x => x.addOrUpdate(TypeMoq.It.isValue(account)), TypeMoq.Times.once());
// ... The account list change should have been fired
state.eventVerifierUpdate.assertFiredWithVerify(param => {
assert.equal(param.providerId, hasAccountProvider.id);
assert.ok(Array.isArray(param.accountList));
assert.equal(param.accountList.length, 1);
assert.equal(param.accountList[0], account);
});
// ... The returned account should be the new one
assert.equal(result, account);
})
.then(
() => done(),
err => done(err)
);
});
test('Add account - provider doesn\'t exist', done => {
// Setup: Create account management service
let ams = getTestState().accountManagementService;
// If: I add an account when the provider doesn't exist
// Then: It should be rejected
ams.addAccount('doesNotExist')
.then(
() => done('Promise resolved when it should have rejected'),
() => done()
);
});
test('Get account provider metadata - providers exist', done => {
// Setup: Create account management service with a provider
let state = getTestState();
state.accountManagementService._providers[noAccountProvider.id] = {
accounts: [],
provider: null, // Doesn't matter
metadata: noAccountProvider
};
// If: I ask for all the account provider metadata
return state.accountManagementService.getAccountProviderMetadata()
.then(result => {
// Then: The list should have the one account provider in it
assert.ok(Array.isArray(result));
assert.equal(result.length, 1);
assert.equal(result[0], noAccountProvider);
})
.then(
() => done(),
err => done(err)
);
});
test('Get account provider metadata - no providers', done => {
// Setup: Create account management service
let ams = getTestState().accountManagementService;
// If: I ask for account provider metadata when there isn't any providers
ams.getAccountProviderMetadata()
.then(result => {
// Then: The results should be an empty array
assert.ok(Array.isArray(result));
assert.equal(result.length, 0);
})
.then(
() => done(),
err => done(err)
);
});
test('Get accounts by provider - provider does not exist', done => {
// Setup: Create account management service
let ams = getTestState().accountManagementService;
// If: I get accounts when the provider doesn't exist
// Then: It should be rejected
ams.getAccountsForProvider('doesNotExist')
.then(
() => done('Promise resolved when it should have rejected'),
() => done()
);
});
test('Get accounts by provider - provider exists, no accounts', done => {
// Setup: Create account management service
let ams = getTestState().accountManagementService;
ams._providers[noAccountProvider.id] = {
accounts: [],
provider: null, // Doesn't matter
metadata: noAccountProvider
};
// If: I ask for the accounts for a provider with no accounts
ams.getAccountsForProvider(noAccountProvider.id)
.then(result => {
// Then: I should get back an empty array
assert.ok(Array.isArray(result));
assert.equal(result.length, 0);
})
.then(
() => done(),
err => done(err)
);
});
test('Get accounts by provider - provider exists, has accounts', done => {
// Setup: Create account management service
let ams = getTestState().accountManagementService;
ams._providers[hasAccountProvider.id] = {
accounts: [account],
provider: null, // Doesn't matter
metadata: hasAccountProvider
};
// If: I ask for the accounts for a provider with accounts
ams.getAccountsForProvider(hasAccountProvider.id)
.then(result => {
// Then: I should get back the list of accounts
assert.equal(result, accountList);
})
.then(
() => done(),
err => done(err)
);
});
test('Remove account - account exists', done => {
// Setup:
// ... Create account management service and to fake removing an account that exists
let state = getTestState();
state.mockAccountStore.setup(x => x.remove(TypeMoq.It.isAny()))
.returns(() => Promise.resolve(true));
// ... Register a account provider with the management service
let mockProvider = TypeMoq.Mock.ofType<data.AccountProvider>(AccountProviderStub);
mockProvider.setup(x => x.clear(TypeMoq.It.isAny())).returns(() => Promise.resolve());
state.accountManagementService._providers[hasAccountProvider.id] = {
accounts: [account],
provider: mockProvider.object,
metadata: hasAccountProvider
};
// If: I remove an account that exists
state.accountManagementService.removeAccount(account.key)
.then( result => {
// Then:
// ... I should have gotten true back
assert.ok(result);
// ... The account store should have had remove called
state.mockAccountStore.verify(x => x.remove(TypeMoq.It.isValue(account.key)), TypeMoq.Times.once());
// ... The provider should have had clear called
mockProvider.verify(x => x.clear(TypeMoq.It.isValue(account.key)), TypeMoq.Times.once());
// ... The updated account list event should have fired
state.eventVerifierUpdate.assertFiredWithVerify((params: UpdateAccountListEventParams) => {
assert.equal(params.providerId, hasAccountProvider.id);
assert.ok(Array.isArray(params.accountList));
assert.equal(params.accountList.length, 0);
});
})
.then(
() => done(),
err => done(err)
);
});
test('Remove account - account doesn\'t exist', done => {
// Setup:
// ... Create account management service and to fake removing an account that doesn't exist
let state = getTestState();
state.mockAccountStore.setup(x => x.remove(TypeMoq.It.isAny()))
.returns(() => Promise.resolve(false));
// ... Register a account provider with the management service
let mockProvider = getMockAccountProvider();
mockProvider.setup(x => x.clear(TypeMoq.It.isAny())).returns(() => Promise.resolve());
state.accountManagementService._providers[noAccountProvider.id] = {
accounts: [],
provider: mockProvider.object,
metadata: noAccountProvider
};
// If: I remove an account that doesn't exist
let accountKey = {providerId: noAccountProvider.id, accountId: 'foobar'};
state.accountManagementService.removeAccount(accountKey)
.then(result => {
// Then:
// ... I should have gotten false back
assert.ok(!result);
// ... The account store should have had remove called
state.mockAccountStore.verify(x => x.remove(TypeMoq.It.isValue(accountKey)), TypeMoq.Times.once());
// ... The provider should have had clear called
mockProvider.verify(x => x.clear(TypeMoq.It.isValue(accountKey)), TypeMoq.Times.once());
// ... The updated account list event should not have fired
state.eventVerifierUpdate.assertNotFired();
})
.then(
() => done(),
err => done(err)
);
});
test('Open account dialog - first call', done => {
// Setup:
// ... Create account management ervice
let state = getTestState();
// ... Add mocking for instantiating an account dialog controller
let mockDialogController = TypeMoq.Mock.ofType(AccountDialogController);
mockDialogController.setup(x => x.openAccountDialog());
state.instantiationService.setup(x => x.createInstance<AccountDialogController>(TypeMoq.It.isValue(AccountDialogController)))
.returns(() => mockDialogController.object);
// If: I open the account dialog when it doesn't exist
state.accountManagementService.openAccountListDialog()
.then(() => {
// Then:
// ... The instantiation service should have been called once
state.instantiationService.verify(x => x.createInstance<AccountDialogController>(TypeMoq.It.isValue(AccountDialogController)), TypeMoq.Times.once());
// ... The dialog should have been opened
mockDialogController.verify(x => x.openAccountDialog(), TypeMoq.Times.once());
})
.then(
() => done(),
err => done(err)
);
});
test('Open account dialog - subsequent calls', done => {
// Setup:
// ... Create account management ervice
let state = getTestState();
// ... Add mocking for instantiating an account dialog controller
let mockDialogController = TypeMoq.Mock.ofType(AccountDialogController);
mockDialogController.setup(x => x.openAccountDialog());
state.instantiationService.setup(x => x.createInstance<AccountDialogController>(TypeMoq.It.isValue(AccountDialogController)))
.returns(() => mockDialogController.object);
// If: I open the account dialog for a second time
state.accountManagementService.openAccountListDialog()
.then(() => state.accountManagementService.openAccountListDialog())
.then(() => {
// Then:
// ... The instantiation service should have only been called once
state.instantiationService.verify(x => x.createInstance<AccountDialogController>(TypeMoq.It.isValue(AccountDialogController)), TypeMoq.Times.once());
// ... The dialog should have been opened twice
mockDialogController.verify(x => x.openAccountDialog(), TypeMoq.Times.exactly(2));
})
.then(
() => done(),
err => done(err)
);
});
// test('Perform oauth - success', done => {
// TODO: implement this test properly once we remove direct IPC calls
// });
test('Register provider - success', done => {
// Setup:
// ... Create ams, account store that will accept account add/update
let mocks = getTestState();
mocks.mockAccountStore.setup(x => x.addOrUpdate(TypeMoq.It.isAny()))
.returns(() => Promise.resolve(undefined));
// ... Create mock account provider
let mockProvider = getMockAccountProvider();
// If: I register a new provider
mocks.accountManagementService.registerProvider(noAccountProvider, mockProvider.object)
.then(() => {
// Then:
// ... Account store should have been called to get dehydrated accounts
mocks.mockAccountStore.verify(x => x.getAccountsByProvider(TypeMoq.It.isValue(noAccountProvider.id)), TypeMoq.Times.once());
// ... The provider should have been initialized
mockProvider.verify(x => x.initialize(TypeMoq.It.isAny()), TypeMoq.Times.once());
// ... The provider added event should have fired
mocks.eventVerifierProviderAdded.assertFiredWithVerify((param: AccountProviderAddedEventParams) => {
assert.equal(param.addedProvider, noAccountProvider);
assert.ok(Array.isArray(param.initialAccounts));
assert.equal(param.initialAccounts.length, 0);
});
})
.then(
() => done(),
err => done(err)
);
});
test('Unregister provider - success', done => {
// Setup:
// ... Create ams
let mocks = getTestState();
// ... Register a provider to remove
let mockProvider = getMockAccountProvider();
mocks.accountManagementService.registerProvider(noAccountProvider, mockProvider.object)
.then((success) => {
// If: I remove an account provider
mocks.accountManagementService.unregisterProvider(noAccountProvider);
// Then: The provider removed event should have fired
mocks.eventVerifierProviderRemoved.assertFired(noAccountProvider);
}, error => {
}).then(() => done(), err => done(err));
});
});
function getTestState(): AccountManagementState {
// Create mock account store
let mockAccountStore = TypeMoq.Mock.ofType<IAccountStore>(AccountStore);
mockAccountStore.setup(x => x.getAccountsByProvider(TypeMoq.It.isValue(noAccountProvider.id)))
.returns(() => Promise.resolve([]));
mockAccountStore.setup(x => x.getAccountsByProvider(TypeMoq.It.isValue(hasAccountProvider.id)))
.returns(() => Promise.resolve(accountList));
// Create instantiation service
let mockInstantiationService = TypeMoq.Mock.ofType(InstantiationService, TypeMoq.MockBehavior.Strict);
mockInstantiationService.setup(x => x.createInstance<AccountStore>(TypeMoq.It.isValue(AccountStore), TypeMoq.It.isAny()))
.returns(() => mockAccountStore.object);
// Create mock memento
let mockMemento = {};
// Create the account management service
let ams = new AccountManagementService(mockMemento, mockInstantiationService.object, null, new SqlOAuthTestService());
// Wire up event handlers
let evUpdate = new EventVerifierSingle<UpdateAccountListEventParams>();
let evAddProvider = new EventVerifierSingle<AccountProviderAddedEventParams>();
let evRemoveProvider = new EventVerifierSingle<data.AccountProviderMetadata>();
ams.updateAccountListEvent(evUpdate.eventHandler);
ams.addAccountProviderEvent(evAddProvider.eventHandler);
ams.removeAccountProviderEvent(evRemoveProvider.eventHandler);
// Create the account management service
return {
accountManagementService: ams,
instantiationService: mockInstantiationService,
mockAccountStore: mockAccountStore,
eventVerifierUpdate: evUpdate,
eventVerifierProviderAdded: evAddProvider,
eventVerifierProviderRemoved: evRemoveProvider
};
}
function getMockAccountProvider(): TypeMoq.Mock<data.AccountProvider> {
let mockProvider = TypeMoq.Mock.ofType<data.AccountProvider>(AccountProviderStub);
mockProvider.setup(x => x.clear(TypeMoq.It.isAny())).returns(() => Promise.resolve());
mockProvider.setup(x => x.initialize(TypeMoq.It.isAny())).returns(param => Promise.resolve(param));
mockProvider.setup(x => x.prompt()).returns(() => Promise.resolve(account));
return mockProvider;
}
interface AccountManagementState {
accountManagementService: AccountManagementService;
instantiationService: TypeMoq.Mock<InstantiationService>;
mockAccountStore: TypeMoq.Mock<IAccountStore>;
eventVerifierUpdate: EventVerifierSingle<UpdateAccountListEventParams>;
eventVerifierProviderAdded: EventVerifierSingle<AccountProviderAddedEventParams>;
eventVerifierProviderRemoved: EventVerifierSingle<data.AccountProviderMetadata>;
}

View File

@@ -0,0 +1,442 @@
/*---------------------------------------------------------------------------------------------
* 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 assert from 'assert';
import * as data from 'data';
import AccountStore from 'sql/services/accountManagement/accountStore';
import {EventVerifierSingle} from 'sqltest/utils/eventVerifier';
suite('Account Store Tests', () => {
test('AddOrUpdate - Uninitialized memento', done => {
// Setup: Create account store w/o initialized memento
let memento = {};
let as = new AccountStore(memento);
// If: I add an account to the store
as.addOrUpdate(account1)
.then(result => {
// Then:
// ... I should have gotten back a result indicating the account was added
assert.ok(result.accountAdded);
assert.ok(!result.accountModified);
assertAccountEqual(result.changedAccount, account1);
// ... The memento should have been initialized and account added
assert.ok(Array.isArray(memento[AccountStore.MEMENTO_KEY]));
assert.equal(memento[AccountStore.MEMENTO_KEY].length, 1);
assertAccountEqual(memento[AccountStore.MEMENTO_KEY][0], account1);
})
.then(
() => done(),
e => done(e)
);
});
test('AddOrUpdate - Adds to accounts', done => {
// Setup: Create account store with initialized memento with accounts
let memento = {};
memento[AccountStore.MEMENTO_KEY] = [];
let as = new AccountStore(memento);
// If: I add an account to the store
as.addOrUpdate(account1)
.then(result => {
// Then:
// ... I should have gotten back a result indicating the account was added
assert.ok(result.accountAdded);
assert.ok(!result.accountModified);
assertAccountEqual(result.changedAccount, account1);
// ... The memento should have the account added
assert.ok(Array.isArray(memento[AccountStore.MEMENTO_KEY]));
assert.equal(memento[AccountStore.MEMENTO_KEY].length, 1);
assertAccountEqual(memento[AccountStore.MEMENTO_KEY][0], account1);
})
.then(
() => done(),
e => done(e)
);
});
test('AddOrUpdate - Updates account', done => {
// Setup: Create account store with initialized memento with accounts
let memento = getTestMemento();
let as = new AccountStore(memento);
// If: I add an account to the store that already exists
let param = <data.Account>{
key: account2.key,
displayInfo: account1.displayInfo,
isStale: account1.isStale
};
as.addOrUpdate(param)
.then(result => {
// Then:
// ... I should have gotten back a result indicating the account was updated
assert.ok(result.accountModified);
assert.ok(!result.accountAdded);
assertAccountEqual(result.changedAccount, param);
// ... The memento should have been initialized and account updated
assert.ok(Array.isArray(memento[AccountStore.MEMENTO_KEY]));
assert.equal(memento[AccountStore.MEMENTO_KEY].length, 2);
assertAccountEqual(memento[AccountStore.MEMENTO_KEY][0], account1);
assertAccountEqual(memento[AccountStore.MEMENTO_KEY][1], param);
})
.then(
() => done(),
e => done(e)
);
});
test('GetAccountsByProvider - Uninitialized memento', done => {
// Setup: Create account store w/o initialized memento
let memento = {};
let as = new AccountStore(memento);
// If: I get accounts by provider
as.getAccountsByProvider('azure')
.then(result => {
// Then:
// ... I should get back an empty array
assert.ok(Array.isArray(result));
assert.equal(result.length, 0);
// ... Memento should not have been written
assert.equal(Object.keys(memento).length, 0);
})
.then(
() => done(),
e => done(e)
);
});
test('GetAccountsByProvider - No accounts', done => {
// Setup: Create account store with initialized memento with accounts
let memento = {};
memento[AccountStore.MEMENTO_KEY] = [];
let as = new AccountStore(memento);
// If: I get accounts when there aren't any accounts
as.getAccountsByProvider('azure')
.then(result => {
// Then: I should get back an empty array
assert.ok(Array.isArray(result));
assert.equal(result.length, 0);
})
.then(
() => done(),
e => done(e)
);
});
test('GetAccountsByProvider - Accounts, but no accounts for provider', done => {
// Setup: Create account store with initialized memento with accounts
let memento = getTestMemento();
let as = new AccountStore(memento);
// If: I get accounts by provider that doesn't have accounts
as.getAccountsByProvider('cloudycloud')
.then(result => {
// Then: I should get back an empty array
assert.ok(Array.isArray(result));
assert.equal(result.length, 0);
})
.then(
() => done(),
e => done(e)
);
});
test('GetAccountsByProvider - Accounts for provider', done => {
// Setup: Create account store with initialized memento with accounts
let memento = getTestMemento();
let as = new AccountStore(memento);
// If: I get accounts by provider that has accounts
as.getAccountsByProvider('azure')
.then(result => {
// Then: I should get the accounts
assert.ok(Array.isArray(result));
assert.equal(result.length, 2);
assertAccountEqual(result[0], memento[AccountStore.MEMENTO_KEY][0]);
assertAccountEqual(result[1], memento[AccountStore.MEMENTO_KEY][1]);
})
.then(
() => done(),
e => done(e)
);
});
test('GetAllAccounts - Uninitialized memento', done => {
// Setup: Create account store w/o initialized memento
let memento = {};
let as = new AccountStore(memento);
// If: I get accounts
as.getAllAccounts()
.then(result => {
// Then:
// ... I should get back an empty array
assert.ok(Array.isArray(result));
assert.equal(result.length, 0);
// ... Memento should not have been written
assert.equal(Object.keys(memento).length, 0);
})
.then(
() => done(),
e => done(e)
);
});
test('GetAllAccounts - No accounts', done => {
// Setup: Create account store with initialized memento with accounts
let memento = {};
memento[AccountStore.MEMENTO_KEY] = [];
let as = new AccountStore(memento);
// If: I get accounts when there aren't any accounts
as.getAllAccounts()
.then(result => {
// Then: I should get back an empty array
assert.ok(Array.isArray(result));
assert.equal(result.length, 0);
})
.then(
() => done(),
e => done(e)
);
});
test('GetAllAccounts - Accounts', done => {
// Setup: Create account store with initialized memento with accounts
let memento = getTestMemento();
let as = new AccountStore(memento);
// If: I get accounts
as.getAllAccounts()
.then(result => {
// Then: I should get the accounts
assert.ok(Array.isArray(result));
assert.equal(result.length, 2);
assertAccountEqual(result[0], memento[AccountStore.MEMENTO_KEY][0]);
assertAccountEqual(result[1], memento[AccountStore.MEMENTO_KEY][1]);
})
.then(
() => done(),
e => done(e)
);
});
test('Remove - Uninitialized menento', done => {
// Setup: Create account store w/o initialized memento
let memento = {};
let as = new AccountStore(memento);
// If: I remove an account when there's an uninitialized memento
as.remove(account1.key)
.then(result => {
// Then:
// ... I should get back false (no account removed)
assert.ok(!result);
// ... The memento should have been initialized
assert.ok(Array.isArray(memento[AccountStore.MEMENTO_KEY]));
assert.equal(memento[AccountStore.MEMENTO_KEY].length, 0);
})
.then(
() => done(),
e => done(e)
);
});
test('Remove - Account does not exist', done => {
// Setup: Create account store with initialized memento with accounts
let memento = {};
memento[AccountStore.MEMENTO_KEY] = [];
let as = new AccountStore(memento);
// If: I remove an account that doesn't exist
as.remove({providerId: 'cloudyCloud', accountId: 'testyTest'})
.then(result => {
// Then:
// ... I should get back false (no account removed)
assert.ok(!result);
// ... The memento should still be empty
assert.ok(Array.isArray(memento[AccountStore.MEMENTO_KEY]));
assert.equal(memento[AccountStore.MEMENTO_KEY].length, 0);
})
.then(
() => done(),
e => done(e)
);
});
test('Remove - Account exists', done => {
// Setup: Create account store with initialized memento with accounts
let memento = getTestMemento();
let as = new AccountStore(memento);
// If: I remove an account that does exist
as.remove(account1.key)
.then(result => {
// Then:
// ... I should get back true (account removed)
assert.ok(result);
// ... The memento should have removed the first account
assert.ok(Array.isArray(memento[AccountStore.MEMENTO_KEY]));
assert.equal(memento[AccountStore.MEMENTO_KEY].length, 1);
assertAccountEqual(memento[AccountStore.MEMENTO_KEY][0], account2);
})
.then(
() => done(),
e => done(e)
);
});
test('Update - Uninitialized menento', done => {
// Setup:
// ... Create account store w/o initialized memento
let memento = {};
let as = new AccountStore(memento);
// ... Create a callback that we can verify was called
let updateCallback = new EventVerifierSingle<data.Account>();
// If: I update an account
as.update(account1.key, updateCallback.eventHandler)
.then(result => {
// Then:
// ... I should get back false (account did not change)
assert.ok(!result);
// ... The memento should have been initialized
assert.ok(Array.isArray(memento[AccountStore.MEMENTO_KEY]));
assert.equal(memento[AccountStore.MEMENTO_KEY].length, 0);
// ... The callback shouldn't have been called
updateCallback.assertNotFired();
})
.then(
() => done(),
e => done(e)
);
});
test('Update - Account does not exist', done => {
// Setup: Create account store with initialized memento with accounts
let memento = {};
memento[AccountStore.MEMENTO_KEY] = [];
let as = new AccountStore(memento);
// ... Create a callback that we can verify was called
let updateCallback = new EventVerifierSingle<data.Account>();
// If: I update an account that doesn't exist
as.update({accountId: 'testyTest', providerId: 'cloudyCloud'}, updateCallback.eventHandler)
.then(result => {
// Then:
// ... I should get back false (account did not change)
assert.ok(!result);
// ... The memento should still be empty
assert.ok(Array.isArray(memento[AccountStore.MEMENTO_KEY]));
assert.equal(memento[AccountStore.MEMENTO_KEY].length, 0);
// ... The callback shouldn't have been called
updateCallback.assertNotFired();
})
.then(
() => done(),
e => done(e)
);
});
test('Update - Account exists', done => {
// Setup: Create account store with initialized memento with accounts
let memento = getTestMemento();
let as = new AccountStore(memento);
// ... Create a callback to update the account
let newDisplayName = 'Display Name Changed!';
let updateCallback = (arg: data.Account) => {
arg.displayInfo.displayName = newDisplayName;
};
// If: I update an account that exists
as.update(account1.key, updateCallback)
.then(result => {
// Then:
// ... I should get back true (account did change)
assert.ok(result);
// ... The memento still contains two accounts
assert.ok(Array.isArray(memento[AccountStore.MEMENTO_KEY]));
assert.equal(memento[AccountStore.MEMENTO_KEY].length, 2);
// ... Account 1 should have been updated
assert.equal(memento[AccountStore.MEMENTO_KEY][0].displayInfo.displayName, newDisplayName);
// ... Account 2 should have stayed the same
assertAccountEqual(memento[AccountStore.MEMENTO_KEY][1], account2);
})
.then(
() => done(),
e => done(e)
);
});
// TODO: Test to make sure operations occur sequentially
});
// TODO: Reinstate contextual logo once UI changes are checked in
const account1 = <data.Account>{
key: {
providerId: 'azure',
accountId: 'testAccount1'
},
displayInfo: {
displayName: 'Test Account 1',
//contextualLogo: {light: '', dark: ''},
contextualDisplayName: 'Azure Account'
},
isStale: false
};
const account2 = <data.Account>{
key: {
providerId: 'azure',
accountId: 'testAccount2'
},
displayInfo: {
displayName: 'Test Account 2',
//contextualLogo: {light: '', dark: ''},
contextualDisplayName: 'Azure Account'
},
isStale: false
};
function getTestMemento() {
let memento = {};
memento[AccountStore.MEMENTO_KEY] = [account1, account2];
return memento;
}
function assertAccountEqual(a: data.Account, b: data.Account) {
assert.equal(a.key.providerId, b.key.providerId);
assert.equal(a.key.accountId, b.key.accountId);
assert.equal(a.displayInfo.contextualDisplayName, b.displayInfo.contextualDisplayName);
//assert.equal(a.displayInfo.contextualLogo, b.displayInfo.contextualLogo);
assert.equal(a.displayInfo.displayName, b.displayInfo.displayName);
assert.equal(a.isStale, b.isStale);
}

View File

@@ -0,0 +1,82 @@
/*---------------------------------------------------------------------------------------------
* 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 data from 'data';
import Event from 'vs/base/common/event';
import { IAccountManagementService } from 'sql/services/accountManagement/interfaces';
import { AccountProviderAddedEventParams, UpdateAccountListEventParams } from 'sql/services/accountManagement/eventTypes';
import { TPromise } from 'vs/base/common/winjs.base';
export class AccountManagementTestService implements IAccountManagementService {
_serviceBrand: any;
public get addAccountProviderEvent(): Event<AccountProviderAddedEventParams> {return () => {return undefined;};}
public get removeAccountProviderEvent(): Event<data.AccountProviderMetadata> {return () => {return undefined;};}
public get updateAccountListEvent(): Event<UpdateAccountListEventParams> {return () => {return undefined;};}
addAccount(providerId: string): Thenable<data.Account> {
return undefined;
}
getAccountProviderMetadata(): Thenable<data.AccountProviderMetadata[]> {
return undefined;
}
getAccountsForProvider(providerId: string): Thenable<data.Account[]> {
return undefined;
}
getSecurityToken(account: data.Account): Thenable<{}> {
return undefined;
}
removeAccount(accountKey: data.AccountKey): Thenable<boolean> {
return undefined;
}
openAccountListDialog(): TPromise<any> {
return undefined;
}
performOAuthAuthorization(url: string, silent: boolean): Thenable<string> {
return undefined;
}
registerProvider(providerMetadata: data.AccountProviderMetadata, provider: data.AccountProvider): void {
return undefined;
}
shutdown(): void {
return undefined;
}
unregisterProvider(providerMetadata: data.AccountProviderMetadata): void {
return undefined;
}
}
export class AccountProviderStub implements data.AccountProvider {
clear(account: data.AccountKey): Thenable<void> {
return Promise.resolve();
}
getSecurityToken(account: data.Account): Thenable<{}> {
return Promise.resolve({});
}
initialize(storedAccounts: data.Account[]): Thenable<data.Account[]> {
return Promise.resolve(storedAccounts);
}
prompt(): Thenable<data.Account> {
return Promise.resolve(undefined);
}
refresh(account: data.Account): Thenable<data.Account> {
return Promise.resolve(account);
}
}

View File

@@ -0,0 +1,128 @@
/*---------------------------------------------------------------------------------------------
* 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 data = require('data');
import { ConnectionManagementInfo } from 'sql/parts/connection/common/connectionManagementInfo';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
import Event from 'vs/base/common/event';
import { Action } from 'vs/base/common/actions';
export class CapabilitiesTestService implements ICapabilitiesService {
public _serviceBrand: any;
private _providers: data.CapabilitiesProvider[] = [];
private _capabilities: data.DataProtocolServerCapabilities[] = [];
constructor() {
let connectionProvider: data.ConnectionProviderOptions = {
options: [
{
name: 'serverName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 0,
valueType: 0
},
{
name: 'databaseName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 1,
valueType: 0
},
{
name: 'userName',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 3,
valueType: 0
},
{
name: 'authenticationType',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 2,
valueType: 0
},
{
name: 'password',
displayName: undefined,
description: undefined,
groupName: undefined,
categoryValues: undefined,
defaultValue: undefined,
isIdentity: true,
isRequired: true,
specialValueType: 4,
valueType: 0
}
]
};
let msSQLCapabilities = {
protocolVersion: '1',
providerName: 'MSSQL',
providerDisplayName: 'MSSQL',
connectionProvider: connectionProvider,
adminServicesProvider: undefined,
features: undefined
};
this._capabilities.push(msSQLCapabilities);
}
/**
* Retrieve a list of registered server capabilities
*/
public getCapabilities(): data.DataProtocolServerCapabilities[] {
return this._capabilities;
}
/**
* Register the capabilities provider and query the provider for its capabilities
* @param provider
*/
public registerProvider(provider: data.CapabilitiesProvider): void {
}
// Event Emitters
public get onProviderRegisteredEvent(): Event<data.DataProtocolServerCapabilities> {
return undefined;
}
public isFeatureAvailable(featureName: Action, connectionManagementInfo: ConnectionManagementInfo): boolean {
return true;
}
public onCapabilitiesReady(): Promise<void> {
return Promise.resolve(null);
}
}

View File

@@ -0,0 +1,22 @@
/*---------------------------------------------------------------------------------------------
* 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 {
IConnectionDialogService, IConnectionManagementService, INewConnectionParams
} from 'sql/parts/connection/common/connectionManagement';
import { TPromise } from 'vs/base/common/winjs.base';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
export class ConnectionDialogTestService implements IConnectionDialogService {
_serviceBrand: any;
public showDialog(connectionManagementService: IConnectionManagementService,
params: INewConnectionParams, model: IConnectionProfile, error?: string): TPromise<void> {
let none: void;
return TPromise.as(none);
}
}

View File

@@ -0,0 +1,236 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IConnectionManagementService, IConnectableInput, IConnectionCompletionOptions, IConnectionCallbacks, IConnectionResult, INewConnectionParams }
from 'sql/parts/connection/common/connectionManagement';
import { IConnectionProfileGroup, ConnectionProfileGroup } from 'sql/parts/connection/common/connectionProfileGroup';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { ConnectionProfile } from 'sql/parts/connection/common/connectionProfile';
import { ConnectionManagementInfo } from 'sql/parts/connection/common/connectionManagementInfo';
import data = require('data');
import Event, { Emitter } from 'vs/base/common/event';
// Test stubs for commonly used objects
export class TestConnectionManagementService implements IConnectionManagementService {
_serviceBrand: any;
onAddConnectionProfile = undefined;
onDeleteConnectionProfile = undefined;
onConnectionChanged = undefined;
onLanguageFlavorChanged = undefined;
public get onConnect(): Event<any> {
let conEvent = new Emitter<any>();
return conEvent.event;
}
public get onDisconnect(): Event<any> {
let conEvent = new Emitter<any>();
return conEvent.event;
}
registerProvider(providerId: string, provider: data.ConnectionProvider): void {
}
showConnectionDialog(params?: INewConnectionParams, model?: IConnectionProfile, error?: string): Promise<void> {
return undefined;
}
showCreateServerGroupDialog(): Promise<void> {
return undefined;
}
showEditServerGroupDialog(group: ConnectionProfileGroup): Promise<void> {
return undefined;
}
onConnectionComplete(handle: number, connectionInfoSummary: data.ConnectionInfoSummary): void {
}
onIntelliSenseCacheComplete(handle: number, connectionUri: string): void {
}
public onConnectionChangedNotification(handle: number, changedConnInfo: data.ChangedConnectionInfo): void {
}
getCurrentConnectionSummary(): data.ConnectionSummary {
return undefined;
}
getConnectionGroups(): ConnectionProfileGroup[] {
return [];
}
getActiveConnections(): ConnectionProfile[] {
return [];
}
saveProfileGroup(profile: IConnectionProfileGroup): Promise<string> {
return undefined;
}
getRecentConnections(): ConnectionProfile[] {
return [];
}
public clearRecentConnectionsList(): void {
return;
}
getUnsavedConnections(): ConnectionProfile[] {
return [];
}
changeGroupIdForConnectionGroup(source: IConnectionProfileGroup, target: IConnectionProfileGroup): Promise<void> {
return Promise.resolve();
}
changeGroupIdForConnection(source: ConnectionProfile, targetGroupId: string): Promise<void> {
return Promise.resolve();
}
deleteConnection(connection: ConnectionProfile): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
resolve(true);
});
}
deleteConnectionGroup(group: ConnectionProfileGroup): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
resolve(true);
});
}
getAdvancedProperties(): data.ConnectionOption[] {
return [];
}
getConnectionId(connectionProfile: ConnectionProfile): string {
return undefined;
}
getFormattedUri(uri: string, connectionProfile: ConnectionProfile): string {
return undefined;
}
isConnected(fileUri: string, connectionProfile?: ConnectionProfile): boolean {
return false;
}
isRecent(connectionProfile: ConnectionProfile): boolean {
return false;
}
isProfileConnected(connectionProfile: IConnectionProfile): boolean {
return false;
}
isProfileConnecting(connectionProfile: IConnectionProfile): boolean {
return false;
}
findExistingConnection(connection: IConnectionProfile, purpose?: 'dashboard' | 'insights' | 'connection'): ConnectionProfile {
return undefined;
}
connect(connection: IConnectionProfile, uri: string, options?: IConnectionCompletionOptions, callbacks?: IConnectionCallbacks): Promise<IConnectionResult> {
return new Promise<IConnectionResult>((resolve, reject) => {
resolve({ connected: true, errorMessage: undefined, errorCode: undefined });
});
}
connectAndSaveProfile(connection: IConnectionProfile, uri: string, options?: IConnectionCompletionOptions, callbacks?: IConnectionCallbacks): Promise<IConnectionResult> {
return new Promise<IConnectionResult>(() => true);
}
disconnectEditor(owner: IConnectableInput): Promise<boolean> {
return new Promise<boolean>(() => true);
}
disconnect(connection: IConnectionProfile);
disconnect(uri: string);
disconnect(input: any): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
resolve(true);
});
}
getConnectionProfile(fileUri: string): IConnectionProfile {
return undefined;
}
getConnectionInfo(fileUri: string): ConnectionManagementInfo {
return undefined;
}
addSavedPassword(connectionProfile: IConnectionProfile): Promise<IConnectionProfile> {
return new Promise<IConnectionProfile>(() => connectionProfile);
}
public listDatabases(connectionUri: string): Thenable<data.ListDatabasesResult> {
return Promise.resolve(undefined);
}
cancelConnection(connection: IConnectionProfile): Thenable<boolean> {
return undefined;
}
cancelEditorConnection(owner: IConnectableInput): Thenable<boolean> {
return undefined;
}
showDashboard(connection: ConnectionProfile): Promise<boolean> {
return new Promise(() => true);
}
closeDashboard(uri: string): void {
}
changeDatabase(connectionUri: string, databaseName: string): Thenable<boolean> {
return new Promise(() => true);
}
editGroup(group: ConnectionProfileGroup): Promise<void> {
return Promise.resolve();
}
getProviderIdFromUri(ownerUri: string): string {
return undefined;
}
hasRegisteredServers(): boolean {
return true;
}
getCapabilities(providerName: string): data.DataProtocolServerCapabilities {
return undefined;
}
canChangeConnectionConfig(profile: ConnectionProfile, newGroupID: string): boolean {
return true;
}
doChangeLanguageFlavor(uri: string, language: string, flavor: string): void {
}
ensureDefaultLanguageFlavor(uri: string): void {
}
public getProviderNames(): string[] {
return [];
}
connectIfNotConnected(connection: IConnectionProfile, purpose?: 'dashboard' | 'insights' | 'connection'): Promise<string> {
return undefined;
}
rebuildIntelliSenseCache(uri: string): Thenable<void> {
return undefined;
}
}

View File

@@ -0,0 +1,46 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import data = require('data');
export class ConnectionProviderStub implements data.ConnectionProvider {
handle: number = 1;
connect(connectionUri: string, connectionInfo: data.ConnectionInfo): Thenable<boolean> {
return undefined;
}
disconnect(connectionUri: string): Thenable<boolean> {
return undefined;
}
cancelConnect(connectionUri: string): Thenable<boolean> {
return undefined;
}
listDatabases(connectionUri: string): Thenable<data.ListDatabasesResult> {
return undefined;
}
changeDatabase(connectionUri: string, newDatabase: string): Thenable<boolean> {
return undefined;
}
rebuildIntelliSenseCache(connectionUri: string): Thenable<void> {
return undefined;
}
registerOnConnectionComplete(handler: (connSummary: data.ConnectionInfoSummary) => any) {
return undefined;
}
registerOnIntelliSenseCacheComplete(handler: (connectionUri: string) => any) {
return undefined;
}
registerOnConnectionChanged(handler: (changedConnInfo: data.ChangedConnectionInfo) => any) {
return undefined;
}
}

View File

@@ -0,0 +1,38 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IContextKeyService, IContextKeyServiceTarget, IContextKey, ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey';
import Event from 'vs/base/common/event';
export class ContextKeyServiceStub implements IContextKeyService {
_serviceBrand: any;
dispose(): void {
//
}
onDidChangeContext: Event<string[]>;
createKey<T>(key: string, defaultValue: T): IContextKey<T> {
return undefined;
}
contextMatchesRules(rules: ContextKeyExpr): boolean {
return undefined;
}
getContextKeyValue<T>(key: string): T {
return undefined;
}
createScoped(target?: IContextKeyServiceTarget): IContextKeyService {
return undefined;
}
getContext(target: IContextKeyServiceTarget): IContext {
return undefined;
}
}

View File

@@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------------------------
* 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 data from 'data';
import { TPromise } from 'vs/base/common/winjs.base';
import {CredentialManagementEvents, ICredentialsService} from "sql/services/credentials/credentialsService";
import {IDisposable} from "vs/base/common/lifecycle";
export class CredentialsTestProvider implements data.CredentialProvider {
handle: number;
public storedCredentials: {[K: string]: data.Credential} = {};
saveCredential(credentialId: string, password: string): Thenable<boolean> {
this.storedCredentials[credentialId] = {
credentialId: credentialId,
password: password
};
return TPromise.as(true);
}
readCredential(credentialId: string): Thenable<data.Credential> {
return TPromise.as(this.storedCredentials[credentialId]);
}
deleteCredential(credentialId: string): Thenable<boolean> {
let exists = this.storedCredentials[credentialId] !== undefined;
delete this.storedCredentials[credentialId];
return TPromise.as(exists);
}
}
export class CredentialsTestService implements ICredentialsService {
_serviceBrand: any;
saveCredential(credentialId: string, password: string): Thenable<boolean> {
return undefined;
}
readCredential(credentialId: string): Thenable<data.Credential> {
return undefined;
}
deleteCredential(credentialId: string): Thenable<boolean> {
return undefined;
}
addEventListener(handle: number, events: CredentialManagementEvents): IDisposable {
return undefined;
}
}

View File

@@ -0,0 +1,134 @@
/*---------------------------------------------------------------------------------------------
* 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 { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { Position, IEditorInput } from 'vs/platform/editor/common/editor';
import { IEditorStacksModel, IEditorGroup, EditorInput } from 'vs/workbench/common/editor';
import Event from 'vs/base/common/event';
import { ITabOptions, GroupArrangement, GroupOrientation } from 'vs/workbench/services/group/common/groupService';
import { IEditorGroupService, IMoveOptions } from 'vs/workbench/services/group/common/groupService';
import { EditorGroup } from "vs/workbench/common/editor/editorStacksModel";
export class EditorGroupTestService implements IEditorGroupService {
_serviceBrand: ServiceIdentifier<any>;
/**
* Emitted when editors or inputs change. Examples: opening, closing of editors. Active editor change.
*/
onEditorsChanged: Event<void>;
/**
* Emitted when opening an editor fails.
*/
onEditorOpenFail: Event<IEditorInput>;
/**
* Emitted when a editors are moved to another position.
*/
onEditorsMoved: Event<void>;
/**
* Emitted when the editor group orientation was changed.
*/
onGroupOrientationChanged: Event<void>;
/**
* Emitted when tab options changed.
*/
onTabOptionsChanged: Event<ITabOptions>;
/**
* Keyboard focus the editor group at the provided position.
*/
public focusGroup(group: EditorGroup): void;
public focusGroup(position: Position): void;
public focusGroup(arg1: any) {
return;
}
/**
* Activate the editor group at the provided position without moving focus.
*/
public activateGroup(group: EditorGroup): void;
public activateGroup(position: Position): void;
public activateGroup(arg1: any): void {
}
/**
* Allows to move the editor group from one position to another.
*/
public moveGroup(from: EditorGroup, to: EditorGroup): void;
public moveGroup(from: Position, to: Position): void;
public moveGroup(arg1: any, arg2: any): void {
}
/**
* Allows to arrange editor groups according to the GroupArrangement enumeration.
*/
arrangeGroups(arrangement: GroupArrangement): void {
}
/**
* Changes the editor group layout between vertical and horizontal orientation. Only applies
* if more than one editor is opened.
*/
setGroupOrientation(orientation: GroupOrientation): void {
}
/**
* Returns the current editor group layout.
*/
getGroupOrientation(): GroupOrientation {
return undefined;
}
/**
* Moves an editor from one group to another. The index in the group is optional.
*/
moveEditor(input: IEditorInput, from: IEditorGroup, to: IEditorGroup, moveOptions?: IMoveOptions): void;
moveEditor(input: IEditorInput, from: Position, to: Position, moveOptions?: IMoveOptions): void;
moveEditor(input: EditorInput, arg2: any, arg3: any, index?: IMoveOptions): void {
}
/**
* Provides access to the editor stacks model
*/
getStacksModel(): IEditorStacksModel {
return undefined;
}
/**
* Returns true if tabs are shown, false otherwise.
*/
getTabOptions(): ITabOptions {
return undefined;
}
public pinEditor(group: EditorGroup, input: EditorInput): void;
public pinEditor(position: Position, input: EditorInput): void;
public pinEditor(arg1: any, input: EditorInput): void {
}
public unpinEditor(group: EditorGroup, input: EditorInput): void;
public unpinEditor(position: Position, input: EditorInput): void;
public unpinEditor(arg1: any, input: EditorInput): void {
}
/**
* Resize visible editor groups
*/
public resizeGroup(position: Position, groupSizeChange: number): void {
}
}

View File

@@ -0,0 +1,14 @@
/*---------------------------------------------------------------------------------------------
* 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 { IErrorMessageService } from 'sql/parts/connection/common/connectionManagement';
import Severity from 'vs/base/common/severity';
export class ErrorMessageServiceStub implements IErrorMessageService {
_serviceBrand: any;
showDialog(severity: Severity, headerTitle: string, message: string): void {
}
}

View File

@@ -0,0 +1,30 @@
/*---------------------------------------------------------------------------------------------
* 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 Severity from 'vs/base/common/severity';
import { IConfirmation, IMessageService, IMessageWithAction } from 'vs/platform/message/common/message';
export class MessageServiceStub implements IMessageService{
_serviceBrand: any;
show(sev: Severity, message: string): () => void;
show(sev: Severity, message: Error): () => void;
show(sev: Severity, message: string[]): () => void;
show(sev: Severity, message: Error[]): () => void;
show(sev: Severity, message: IMessageWithAction): () => void;
show(sev: Severity, message): () => void {
return undefined;
}
hideAll(): void {
return undefined;
}
confirm(confirmation: IConfirmation): boolean {
return undefined;
}
}

View File

@@ -0,0 +1,34 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import data = require('data');
// Test stubs for commonly used objects
export class ObjectExplorerProviderTestService implements data.ObjectExplorerProvider {
public createNewSession(connInfo: data.ConnectionInfo): Thenable<data.ObjectExplorerCloseSessionResponse> {
return Promise.resolve(undefined);
}
public expandNode(nodeInfo: data.ExpandNodeInfo): Thenable<boolean> {
return Promise.resolve(undefined);
}
public refreshNode(nodeInfo: data.ExpandNodeInfo): Thenable<boolean> {
return Promise.resolve(undefined);
}
public closeSession(closeSessionInfo: data.ObjectExplorerCloseSessionInfo): Thenable<data.ObjectExplorerCloseSessionResponse> {
return Promise.resolve(undefined);
}
public registerOnSessionCreated(handler: (response: data.ObjectExplorerSession) => any): void {
}
public registerOnExpandCompleted(handler: (response: data.ObjectExplorerExpandInfo) => any): void {
}
}

View File

@@ -0,0 +1,18 @@
/*---------------------------------------------------------------------------------------------
* 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 { ISqlOAuthService } from 'sql/common/sqlOAuthService';
export class SqlOAuthTestService implements ISqlOAuthService {
_serviceBrand: any;
performOAuthAuthorization(eventId: string, url: string, silent: boolean): void {
}
registerOAuthCallback(handler: (event, args) => void): void {
}
}

View File

@@ -0,0 +1,72 @@
/*---------------------------------------------------------------------------------------------
* 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 { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
export class StorageTestService implements IStorageService {
_serviceBrand: any;
/**
* Store a string value under the given key to local storage.
*
* The optional scope argument allows to define the scope of the operation.
*/
store(key: string, value: any, scope?: StorageScope): void {
}
/**
* Swap the value of a stored element to one of the two provided
* values and use the defaultValue if no element with the given key
* exists.
*
* The optional scope argument allows to define the scope of the operation.
*/
swap(key: string, valueA: any, valueB: any, scope?: StorageScope, defaultValue?: any): void {
}
/**
* Delete an element stored under the provided key from local storage.
*
* The optional scope argument allows to define the scope of the operation.
*/
remove(key: string, scope?: StorageScope): void {
}
/**
* Retrieve an element stored with the given key from local storage. Use
* the provided defaultValue if the element is null or undefined.
*
* The optional scope argument allows to define the scope of the operation.
*/
get(key: string, scope?: StorageScope, defaultValue?: string): string {
return undefined;
}
/**
* Retrieve an element stored with the given key from local storage. Use
* the provided defaultValue if the element is null or undefined. The element
* will be converted to a number using parseInt with a base of 10.
*
* The optional scope argument allows to define the scope of the operation.
*/
getInteger(key: string, scope?: StorageScope, defaultValue?: number): number {
return 0;
}
/**
* Retrieve an element stored with the given key from local storage. Use
* the provided defaultValue if the element is null or undefined. The element
* will be converted to a boolean.
*
* The optional scope argument allows to define the scope of the operation.
*/
getBoolean(key: string, scope?: StorageScope, defaultValue?: boolean): boolean {
return true;
}
}

View File

@@ -0,0 +1,27 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ITelemetryService, ITelemetryData, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { TPromise } from 'vs/base/common/winjs.base';
// Test stubs for commonly used objects
export class TelemetryServiceStub implements ITelemetryService {
_serviceBrand: any;
/**
* Sends a telemetry event that has been privacy approved.
* Do not call this unless you have been given approval.
*/
publicLog(eventName: string, data?: ITelemetryData): TPromise<void> {
return undefined;
}
getTelemetryInfo(): TPromise<ITelemetryInfo> {
return undefined;
}
isOptedIn: boolean;
}

View File

@@ -0,0 +1,43 @@
/*---------------------------------------------------------------------------------------------
* 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 { IThemeService, ITheme, IThemingParticipant } from 'vs/platform/theme/common/themeService';
import { Color } from 'vs/base/common/color';
import { IDisposable } from 'vs/base/common/lifecycle';
import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry';
export class TestTheme implements ITheme {
selector: string;
type: 'light' | 'dark' | 'hc';
getColor(color: string, useDefault?: boolean): Color {
return Color.white;
}
isDefault(color: string): boolean {
throw new Error('Method not implemented.');
}
defines(color: ColorIdentifier): boolean {
throw new Error('Method not implemented.');
}
}
const testTheme = new TestTheme();
export class TestThemeService implements IThemeService {
_serviceBrand: any;
getTheme(): ITheme {
return testTheme;
}
onThemeChange(participant: IThemingParticipant): IDisposable {
return { dispose: () => { } };
}
}

View File

@@ -0,0 +1,107 @@
/*---------------------------------------------------------------------------------------------
* 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 { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { IEditorService, IEditor, IEditorInput, IEditorOptions, ITextEditorOptions, Position, Direction, IResourceInput, IResourceDiffInput, IResourceSideBySideInput }
from 'vs/platform/editor/common/editor';
import { TPromise } from 'vs/base/common/winjs.base';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { EditorInput, EditorOptions, IFileEditorInput, TextEditorOptions, IEditorRegistry, Extensions, SideBySideEditorInput } from 'vs/workbench/common/editor';
export class WorkbenchEditorTestService implements IWorkbenchEditorService {
_serviceBrand: ServiceIdentifier<any>;
/**
* Returns the currently active editor or null if none.
*/
getActiveEditor(): IEditor {
return undefined;
}
/**
* Returns the currently active editor input or null if none.
*/
getActiveEditorInput(): IEditorInput {
return undefined;
}
/**
* Returns an array of visible editors.
*/
getVisibleEditors(): IEditor[] {
return undefined;
}
/**
* Returns iff the provided input is currently visible.
*
* @param includeDiff iff set to true, will also consider diff editors to find out if the provided
* input is opened either on the left or right hand side of the diff editor.
*/
isVisible(input: IEditorInput, includeDiff: boolean): boolean {
return undefined;
}
protected doOpenEditor(input: IEditorInput, options?: EditorOptions, sideBySide?: boolean): TPromise<IEditor>;
protected doOpenEditor(input: IEditorInput, options?: EditorOptions, position?: Position): TPromise<IEditor>;
protected doOpenEditor(input: IEditorInput, options?: EditorOptions, arg3?: any): TPromise<IEditor> {
return undefined;
}
/**
* Opens an Editor on the given input with the provided options at the given position. If sideBySide parameter
* is provided, causes the editor service to decide in what position to open the input.
*/
public openEditor(input: IEditorInput, options?: IEditorOptions, sideBySide?: boolean): TPromise<IEditor>;
public openEditor(input: IEditorInput, options?: IEditorOptions, position?: Position): TPromise<IEditor>;
public openEditor(input: IResourceInput | IResourceDiffInput | IResourceSideBySideInput, position?: Position): TPromise<IEditor>;
public openEditor(input: IResourceInput | IResourceDiffInput | IResourceSideBySideInput, sideBySide?: boolean): TPromise<IEditor>;
public openEditor(input: any, arg2?: any, arg3?: any): TPromise<IEditor> {
return undefined;
}
public openEditors(editors: { input: IResourceInput | IResourceDiffInput | IResourceSideBySideInput, position: Position }[]): TPromise<IEditor[]>;
public openEditors(editors: { input: IEditorInput, position: Position, options?: IEditorOptions }[]): TPromise<IEditor[]>;
public openEditors(editors: any[]): TPromise<IEditor[]> {
return undefined;
}
public replaceEditors(editors: { toReplace: IResourceInput | IResourceDiffInput | IResourceSideBySideInput, replaceWith: IResourceInput | IResourceDiffInput | IResourceSideBySideInput }[], position?: Position): TPromise<BaseEditor[]>;
public replaceEditors(editors: { toReplace: IEditorInput, replaceWith: IEditorInput, options?: IEditorOptions }[], position?: Position): TPromise<BaseEditor[]>;
public replaceEditors(editors: any[], position?: Position): TPromise<BaseEditor[]> {
return undefined;
}
/**
* Closes the editor at the provided position.
*/
closeEditor(position: Position, input: IEditorInput): TPromise<void> {
return undefined;
}
/**
* Closes editors of a specific group at the provided position. If the optional editor is provided to exclude, it
* will not be closed. The direction can be used in that case to control if all other editors should get closed,
* or towards a specific direction.
*/
closeEditors(position: Position, filter?: { except?: IEditorInput, direction?: Direction, unmodifiedOnly?: boolean }): TPromise<void> {
return undefined;
}
/**
* Closes all editors across all groups. The optional position allows to keep one group alive.
*/
closeAllEditors(except?: Position): TPromise<void> {
return undefined;
}
/**
* Allows to resolve an untyped input to a workbench typed instanceof editor input
*/
createInput(input: IResourceInput | IResourceDiffInput | IResourceSideBySideInput): IEditorInput {
return undefined;
}
}

View File

@@ -0,0 +1,80 @@
/*---------------------------------------------------------------------------------------------
* 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 { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import {
IConfigurationValue, IConfigurationData, IConfigurationKeys,
IConfigurationServiceEvent, IConfigurationValues } from 'vs/platform/configuration/common/configuration';
import { TPromise } from 'vs/base/common/winjs.base';
import Event from 'vs/base/common/event';
export class WorkspaceConfigurationTestService implements IWorkspaceConfigurationService {
_serviceBrand: any;
getConfigurationData<T>(): IConfigurationData<T> {
return undefined;
}
/**
* Returns untrusted configuration keys for the current workspace.
*/
getUnsupportedWorkspaceKeys(): string[] {
return [];
}
/**
* Returns iff the workspace has configuration or not.
*/
hasWorkspaceConfiguration(): boolean {
return true;
}
/**
* Returns untrusted configuration keys for the current workspace.
*/
getUntrustedConfigurations(): string[] {
return [];
}
/**
* Returns if the user explicitly configured to not trust the current workspace.
*/
isExplicitlyUntrusted(): boolean {
return true;
}
/**
* Override for the IConfigurationService#lookup() method that adds information about workspace settings.
*/
lookup<T>(key: string): IConfigurationValue<T> {
return undefined;
}
getConfiguration<T>(section?: string): T {
return undefined;
}
reloadConfiguration<T>(section?: string): TPromise<T> {
return undefined;
}
/**
* Override for the IConfigurationService#keys() method that adds information about workspace settings.
*/
keys(): IConfigurationKeys {
return undefined;
}
/**
* Returns the defined values of configurations in the different scopes.
*/
values(): IConfigurationValues {
return undefined;
}
onDidUpdateConfiguration: Event<IConfigurationServiceEvent>;
}

View File

@@ -0,0 +1,87 @@
/*---------------------------------------------------------------------------------------------
* 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 assert from 'assert';
export class EventVerifierSingle<T> {
private _eventArgument: T;
private _eventFired: boolean;
constructor() {
this._eventFired = false;
}
public get eventArgument(): T {
return this._eventArgument;
}
public get eventFired(): boolean {
return this._eventFired;
}
public assertFired(expectedArgument?: T) {
assert.ok(this._eventFired);
if (expectedArgument) {
assert.equal(this._eventArgument, expectedArgument);
}
}
public assertFiredWithVerify(argumentVerification: (arg: T) => void) {
assert.ok(this._eventFired);
argumentVerification(this._eventArgument);
}
public assertNotFired() {
assert.equal(this._eventFired, false);
}
public get eventHandler(): (arg: T) => void {
let self = this;
return (arg: T) => {
self._eventArgument = arg;
self._eventFired = true;
};
}
}
export class EventVerifierMultiple<T> {
private _eventArguments: T[];
constructor() {
this._eventArguments = [];
}
public get eventArguments(): T[] {
return this._eventArguments;
}
public get eventFired(): boolean {
return this._eventArguments.length > 0;
}
public assertFired(expectedArgument?: T) {
assert.ok(this.eventFired);
if (expectedArgument) {
assert.ok(this._eventArguments.includes(expectedArgument));
}
}
public assertNotFired(expectedArgument?: T) {
if (expectedArgument) {
assert.ok(!this._eventArguments.includes(expectedArgument));
} else {
assert.ok(!this.eventFired);
}
}
public eventHandler(): (arg: T) => void {
let self = this;
return (arg: T) => {
self._eventArguments.push(arg);
};
}
}

View File

@@ -0,0 +1,273 @@
/*---------------------------------------------------------------------------------------------
* 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 assert from 'assert';
import * as data from 'data';
import * as TypeMoq from 'typemoq';
import { AccountProviderStub, AccountManagementTestService } from 'sqltest/stubs/accountManagementStubs';
import { ExtHostAccountManagement } from 'sql/workbench/api/node/extHostAccountManagement';
import { TestThreadService } from 'vs/workbench/test/electron-browser/api/testThreadService';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { SqlMainContext } from 'sql/workbench/api/node/sqlExtHost.protocol';
import { MainThreadAccountManagement } from 'sql/workbench/api/node/mainThreadAccountManagement';
import { IAccountManagementService } from 'sql/services/accountManagement/interfaces';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
const IThreadService = createDecorator<IThreadService>('threadService');
// SUITE STATE /////////////////////////////////////////////////////////////
let instantiationService: TestInstantiationService;
let mockAccountMetadata: data.AccountProviderMetadata;
let mockAccount: data.Account;
let threadService: TestThreadService;
// TESTS ///////////////////////////////////////////////////////////////////
suite('ExtHostAccountManagement', () => {
suiteSetup(() => {
threadService = new TestThreadService();
const accountMgmtStub = new AccountManagementTestService();
instantiationService = new TestInstantiationService();
instantiationService.stub(IThreadService, threadService);
instantiationService.stub(IAccountManagementService, accountMgmtStub);
const accountMgmtService = instantiationService.createInstance(MainThreadAccountManagement);
threadService.setTestInstance(SqlMainContext.MainThreadAccountManagement, accountMgmtService);
mockAccountMetadata = {
args: {},
displayName: 'Test Account Provider',
id: 'test_account_provider',
settings: {}
};
mockAccount = {
key: {
providerId: mockAccountMetadata.id,
providerArgs: {},
accountId: 'test_account'
},
properties: {},
displayInfo: {
displayName: 'Test Account',
contextualDisplayName: 'Test Kind Of Account',
contextualLogo: { light: '', dark: '' }
},
isStale: false
};
});
test('Constructor', () => {
// If: I construct a new extension host account management
let extHost = new ExtHostAccountManagement(threadService);
// Then: There shouldn't be any account providers registered
assert.equal(extHost.getProviderCount(), 0);
});
// REGISTER TESTS //////////////////////////////////////////////////////
test('Register Account Provider - Success', () => {
// Setup: Create an extension host account management
let extHost = new ExtHostAccountManagement(threadService);
let mockProvider = getMockAccountProvider();
// If: I register a mock account provider
extHost.$registerAccountProvider(mockAccountMetadata, mockProvider.object);
// Then: The account provider should be registered
assert.equal(extHost.getProviderCount(), 1);
});
test('Register Account Provider - Account Provider Already Registered', () => {
// Setup: Create an extension host account management and register an account provider
let extHost = new ExtHostAccountManagement(threadService);
let mockProvider = getMockAccountProvider();
extHost.$registerAccountProvider(mockAccountMetadata, mockProvider.object);
// If: I register an account provider again
// Then
// ... It should throw
assert.throws(() => {
extHost.$registerAccountProvider(mockAccountMetadata, mockProvider.object);
});
// ... There should only be one account provider
assert.equal(extHost.getProviderCount(), 1);
});
// TODO: Test for unregistering a provider
// CLEAR TESTS /////////////////////////////////////////////////////////
test('Clear - Success', (done) => {
// Setup: Create ext host account management with registered account provider
let extHost = new ExtHostAccountManagement(threadService);
let mockProvider = getMockAccountProvider();
extHost.$registerAccountProvider(mockAccountMetadata, mockProvider.object);
// If: I clear an account
extHost.$clear(0, mockAccount.key)
.then(() => {
// Then: The call should have been passed to the provider
mockProvider.verify(
(obj) => obj.clear(TypeMoq.It.isValue(mockAccount.key)),
TypeMoq.Times.once()
);
})
.then(() => done(), (err) => done(err));
});
test('Clear - Handle does not exist', (done) => {
// Setup: Create ext host account management with registered account provider
let extHost = new ExtHostAccountManagement(threadService);
let mockProvider = getMockAccountProvider();
extHost.$registerAccountProvider(mockAccountMetadata, mockProvider.object);
// If: I clear an account for a handle that doesn't exist
// Then: It should fail
extHost.$clear(1, mockAccount.key)
.then(() => done('Clear succeeded when it should have failed'))
.then(null, () => {
// The provider's clear should not have been called
mockProvider.verify(
(obj) => obj.clear(TypeMoq.It.isAny()),
TypeMoq.Times.never()
);
})
.then(() => done(), (err) => done(err));
});
// INITIALIZE TESTS ////////////////////////////////////////////////////
test('Initialize - Success', (done) => {
// Setup: Create ext host account management with registered account provider
let extHost = new ExtHostAccountManagement(threadService);
let mockProvider = getMockAccountProvider();
extHost.$registerAccountProvider(mockAccountMetadata, mockProvider.object);
// If: I initialize the provider
extHost.$initialize(0, [mockAccount])
.then(() => {
// Then: The call should have been passed to the provider
mockProvider.verify(
(obj) => obj.initialize(TypeMoq.It.isValue([mockAccount])),
TypeMoq.Times.once()
);
})
.then(() => done(), (err) => done(err));
});
test('Initialize - Handle does not exist', (done) => {
// Setup: Create ext host account management with registered account provider
let extHost = new ExtHostAccountManagement(threadService);
let mockProvider = getMockAccountProvider();
extHost.$registerAccountProvider(mockAccountMetadata, mockProvider.object);
// If: I initialize for a handle that doesn't exist
// Then: It should fail
extHost.$initialize(1, [mockAccount])
.then(() => done('Initialize succeeded when it should have failed'))
.then(null, () => {
// The provider's clear should not have been called
mockProvider.verify(
(obj) => obj.initialize(TypeMoq.It.isAny()),
TypeMoq.Times.never()
);
})
.then(() => done(), (err) => done(err));
});
// PROMPT TESTS ////////////////////////////////////////////////////////
test('Prompt - Success', (done) => {
// Setup: Create ext host account management with registered account provider
let extHost = new ExtHostAccountManagement(threadService);
let mockProvider = getMockAccountProvider();
extHost.$registerAccountProvider(mockAccountMetadata, mockProvider.object);
// If: I prompt for an account
extHost.$prompt(0)
.then(() => {
// Then: The call should have been passed to the provider
mockProvider.verify(
(obj) => obj.prompt(),
TypeMoq.Times.once()
);
})
.then(() => done(), (err) => done(err));
});
test('Prompt - Handle does not exist', (done) => {
// Setup: Create ext host account management with registered account provider
let extHost = new ExtHostAccountManagement(threadService);
let mockProvider = getMockAccountProvider();
extHost.$registerAccountProvider(mockAccountMetadata, mockProvider.object);
// If: I prompt with a handle that doesn't exist
// Then: It should fail
extHost.$prompt(1)
.then(() => done('Prompt succeeded when it should have failed'))
.then(null, () => {
// The provider's clear should not have been called
mockProvider.verify(
(obj) => obj.prompt(),
TypeMoq.Times.never()
);
})
.then(() => done(), (err) => done(err));
});
// REFRESH TESTS ///////////////////////////////////////////////////////
test('Refresh - Success', (done) => {
// Setup: Create ext host account management with registered account provider
let extHost = new ExtHostAccountManagement(threadService);
let mockProvider = getMockAccountProvider();
extHost.$registerAccountProvider(mockAccountMetadata, mockProvider.object);
// If: I refresh an account
extHost.$refresh(0, mockAccount)
.then(() => {
// Then: The call should have been passed to the provider
mockProvider.verify(
(obj) => obj.refresh(TypeMoq.It.isValue(mockAccount)),
TypeMoq.Times.once()
);
})
.then(() => done(), (err) => done(err));
});
test('Refresh - Handle does not exist', (done) => {
// Setup: Create ext host account management with registered account provider
let extHost = new ExtHostAccountManagement(threadService);
let mockProvider = getMockAccountProvider();
extHost.$registerAccountProvider(mockAccountMetadata, mockProvider.object);
// If: I refresh an account for a handle that doesn't exist
// Then: It should fail
extHost.$refresh(1, mockAccount)
.then(() => done('Refresh succeeded when it should have failed'))
.then(null, () => {
// The provider's clear should not have been called
mockProvider.verify(
(obj) => obj.refresh(TypeMoq.It.isAny()),
TypeMoq.Times.never()
);
})
.then(() => done(), (err) => done(err));
});
});
function getMockAccountProvider(): TypeMoq.Mock<data.AccountProvider> {
let mock = TypeMoq.Mock.ofType<data.AccountProvider>(AccountProviderStub);
mock.setup((obj) => obj.clear(TypeMoq.It.isValue(mockAccount.key)))
.returns(() => Promise.resolve(undefined));
mock.setup((obj) => obj.refresh(TypeMoq.It.isValue(mockAccount)))
.returns(() => Promise.resolve(undefined));
mock.setup((obj) => obj.initialize(TypeMoq.It.isValue([mockAccount])))
.returns(() => Promise.resolve(undefined));
mock.setup((obj) => obj.prompt())
.returns(() => Promise.resolve(undefined));
return mock;
}

View File

@@ -0,0 +1,133 @@
/*---------------------------------------------------------------------------------------------
* 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 assert from 'assert';
import {TestThreadService} from 'vs/workbench/test/electron-browser/api/testThreadService';
import {TestInstantiationService} from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import {ExtHostCredentialManagement} from 'sql/workbench/api/node/extHostCredentialManagement';
import {SqlMainContext} from 'sql/workbench/api/node/sqlExtHost.protocol';
import {IThreadService} from 'vs/workbench/services/thread/common/threadService';
import {MainThreadCredentialManagement} from 'sql/workbench/api/node/mainThreadCredentialManagement';
import {CredentialsTestProvider, CredentialsTestService} from 'sqltest/stubs/credentialsTestStubs';
import {ICredentialsService} from 'sql/services/credentials/credentialsService';
import {Credential, CredentialProvider} from 'data';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
const IThreadService = createDecorator<IThreadService>('threadService');
// SUITE STATE /////////////////////////////////////////////////////////////
let credentialServiceStub: CredentialsTestService;
let instantiationService: TestInstantiationService;
let threadService: TestThreadService;
// TESTS ///////////////////////////////////////////////////////////////////
suite('ExtHostCredentialManagement', () => {
suiteSetup(() => {
threadService = new TestThreadService();
credentialServiceStub = new CredentialsTestService();
instantiationService = new TestInstantiationService();
instantiationService.stub(IThreadService, threadService);
instantiationService.stub(ICredentialsService, credentialServiceStub);
const credentialService = instantiationService.createInstance(MainThreadCredentialManagement);
threadService.setTestInstance(SqlMainContext.MainThreadCredentialManagement, credentialService);
});
test('Construct ExtHostCredentialManagement', () => {
// If: I construct an credential management extension host
let extHost = new ExtHostCredentialManagement(threadService);
// Then: The extension host should not have any providers registered
assert.equal(extHost.getProviderCount(), 0);
});
test('Register Credential Provider', () => {
// Setup: Create a mock credential provider
let extHost = new ExtHostCredentialManagement(threadService);
let mockCredentialProvider = new CredentialsTestProvider();
// If: I register the credential provider with the extension host
extHost.$registerCredentialProvider(mockCredentialProvider);
// Then: There should be one provider registered
assert.equal(extHost.getProviderCount(), 1);
});
test('Get Credential Provider - Success', (done) => {
// Setup: Register a mock credential provider
let extHost = new ExtHostCredentialManagement(threadService);
let mockCredentialProvider = new CredentialsTestProvider();
extHost.$registerCredentialProvider(mockCredentialProvider);
// If: I get the credential provider
let namespaceId = 'test_namespace';
let credentialId = 'test_id';
let credential = 'test_credential';
let expectedCredentialId = `${namespaceId}|${credentialId}`;
let credProvider: CredentialProvider;
extHost.$getCredentialProvider(namespaceId)
.then((provider) => {
// Then: There should still only be one provider registered
assert.equal(extHost.getProviderCount(), 1);
credProvider = provider;
})
.then(() => {
// If: I write a credential
return credProvider.saveCredential(credentialId, credential);
})
.then(() => {
// Then: The credential should have been stored with its namespace
assert.notStrictEqual(mockCredentialProvider.storedCredentials[expectedCredentialId], undefined);
assert.equal(mockCredentialProvider.storedCredentials[expectedCredentialId].credentialId, expectedCredentialId);
assert.equal(mockCredentialProvider.storedCredentials[expectedCredentialId].password, credential);
})
.then(() => {
// If: I read a credential
return credProvider.readCredential(credentialId);
})
.then((returnedCredential: Credential) => {
// Then: The credential ID should be namespaced
assert.equal(returnedCredential.credentialId, expectedCredentialId);
assert.equal(returnedCredential.password, credential);
})
.then(() => {
// If: I delete a credential
return credProvider.deleteCredential(credentialId);
})
.then(() => {
// Then: The credential with its namespace should no longer exist
assert.strictEqual(mockCredentialProvider.storedCredentials[expectedCredentialId], undefined);
})
.then(() => done(), (err) => done(err));
});
test('Get Credential Provider - No Namespace', (done) => {
// Setup: Register a mock credential provider
let extHost = new ExtHostCredentialManagement(threadService);
let mockCredentialProvider = new CredentialsTestProvider();
extHost.$registerCredentialProvider(mockCredentialProvider);
// If: I get a credential provider with an invalid namespace ID
// Then: I should get an error
extHost.$getCredentialProvider(undefined)
.then(
() => { done('Provider was returned from undefined'); },
() => { /* Swallow error, this is success path */ }
)
.then(() => { return extHost.$getCredentialProvider(null); })
.then(
() => { done('Provider was returned from null'); },
() => { /* Swallow error, this is success path */ }
)
.then(() => {return extHost.$getCredentialProvider(''); })
.then(
() => { done('Provider was returned from \'\''); },
() => { done(); }
);
});
});

View File

@@ -0,0 +1,129 @@
/*---------------------------------------------------------------------------------------------
* 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 assert from 'assert';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { setUnexpectedErrorHandler, errorHandler } from 'vs/base/common/errors';
import URI from 'vs/base/common/uri';
import * as EditorCommon from 'vs/editor/common/editorCommon';
import { Model as EditorModel } from 'vs/editor/common/model/model';
import { TestThreadService } from 'vs/workbench/test/electron-browser/api/testThreadService';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IMarkerService } from 'vs/platform/markers/common/markers';
import { MarkerService } from 'vs/platform/markers/common/markerService';
import { IThreadService } from 'vs/workbench/services/thread/common/threadService';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { MainThreadCommands } from 'vs/workbench/api/electron-browser/mainThreadCommands';
import { IHeapService } from 'vs/workbench/api/electron-browser/mainThreadHeapService';
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
import { DocumentSymbolProviderRegistry } from 'vs/editor/common/modes';
import { MainContext, ExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
import * as vscode from 'vscode';
import * as data from 'data';
import { ExtHostDataProtocol } from 'sql/workbench/api/node/extHostDataProtocol';
import { SqlExtHostContext } from 'sql/workbench/api/node/sqlExtHost.protocol';
const IThreadService = createDecorator<IThreadService>('threadService');
const model: EditorCommon.IModel = EditorModel.createFromString(
[
'This is the first line',
'This is the second line',
'This is the third line',
].join('\n'),
undefined,
undefined,
URI.parse('far://testing/file.a'));
let extHost: ExtHostDataProtocol;
let disposables: vscode.Disposable[] = [];
let threadService: TestThreadService;
let originalErrorHandler: (e: any) => any;
suite('ExtHostDataProtocol', function () {
suiteSetup(() => {
threadService = new TestThreadService();
let instantiationService = new TestInstantiationService();
instantiationService.stub(IThreadService, threadService);
instantiationService.stub(IMarkerService, MarkerService);
instantiationService.stub(IHeapService, {
_serviceBrand: undefined,
trackRecursive(args) {
// nothing
return args;
}
});
originalErrorHandler = errorHandler.getUnexpectedErrorHandler();
setUnexpectedErrorHandler(() => { });
const extHostDocumentsAndEditors = new ExtHostDocumentsAndEditors(threadService);
extHostDocumentsAndEditors.$acceptDocumentsAndEditorsDelta({
addedDocuments: [{
isDirty: false,
versionId: model.getVersionId(),
modeId: model.getLanguageIdentifier().language,
url: model.uri,
lines: model.getValue().split(model.getEOL()),
EOL: model.getEOL(),
}]
});
const extHostDocuments = new ExtHostDocuments(threadService, extHostDocumentsAndEditors);
threadService.set(ExtHostContext.ExtHostDocuments, extHostDocuments);
const heapService = new ExtHostHeapService();
const commands = new ExtHostCommands(threadService, heapService);
threadService.set(ExtHostContext.ExtHostCommands, commands);
threadService.setTestInstance(MainContext.MainThreadCommands, instantiationService.createInstance(MainThreadCommands));
const diagnostics = new ExtHostDiagnostics(threadService);
threadService.set(ExtHostContext.ExtHostDiagnostics, diagnostics);
extHost = new ExtHostDataProtocol(threadService);
threadService.set(SqlExtHostContext.ExtHostDataProtocol, extHost);
});
suiteTeardown(() => {
setUnexpectedErrorHandler(originalErrorHandler);
model.dispose();
});
teardown(function () {
while (disposables.length) {
disposables.pop().dispose();
}
return threadService.sync();
});
// --- outline
test('DataProvider, language flavor changed', function () {
assert.equal(DocumentSymbolProviderRegistry.all(model).length, 0);
let expectedParams = <data.DidChangeLanguageFlavorParams> {
uri: 'myuri',
language: 'sql'
};
let actualParams: data.DidChangeLanguageFlavorParams = undefined;
extHost.onDidChangeLanguageFlavor((e => {
actualParams = e;
}));
extHost.$languageFlavorChanged(expectedParams);
assert.ok(actualParams !== undefined);
assert.equal(actualParams.uri, expectedParams.uri);
assert.equal(actualParams.flavor, expectedParams.flavor);
assert.equal(actualParams.language, expectedParams.language);
});
});