diff --git a/extensions/arc/src/common/utils.ts b/extensions/arc/src/common/utils.ts index 35985287c5..92bc63db5c 100644 --- a/extensions/arc/src/common/utils.ts +++ b/extensions/arc/src/common/utils.ts @@ -184,6 +184,30 @@ export async function promptAndConfirmPassword(validate: (input: string) => stri return undefined; } +export function generateGuid(): string { + let hexValues: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']; + // c.f. rfc4122 (UUID version 4 = xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx) + let oct: string = ''; + let tmp: number; + /* tslint:disable:no-bitwise */ + for (let a: number = 0; a < 4; a++) { + tmp = (4294967296 * Math.random()) | 0; + oct += hexValues[tmp & 0xF] + + hexValues[tmp >> 4 & 0xF] + + hexValues[tmp >> 8 & 0xF] + + hexValues[tmp >> 12 & 0xF] + + hexValues[tmp >> 16 & 0xF] + + hexValues[tmp >> 20 & 0xF] + + hexValues[tmp >> 24 & 0xF] + + hexValues[tmp >> 28 & 0xF]; + } + + // 'Set the two most significant bits (bits 6 and 7) of the clock_seq_hi_and_reserved to zero and one, respectively' + let clockSequenceHi: string = hexValues[8 + (Math.random() * 4) | 0]; + return oct.substr(0, 8) + '-' + oct.substr(9, 4) + '-4' + oct.substr(13, 3) + '-' + clockSequenceHi + oct.substr(16, 3) + '-' + oct.substr(19, 12); + /* tslint:enable:no-bitwise */ +} + /** * Gets the message to display for a given error object that may be a variety of types. * @param error The error object diff --git a/extensions/arc/src/test/models/postgresModel.test.ts b/extensions/arc/src/test/models/postgresModel.test.ts new file mode 100644 index 0000000000..2445026a1e --- /dev/null +++ b/extensions/arc/src/test/models/postgresModel.test.ts @@ -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. + *--------------------------------------------------------------------------------------------*/ + +import { PGResourceInfo, ResourceType } from 'arc'; +import * as azdataExt from 'azdata-ext'; +import * as azdata from 'azdata'; +import * as should from 'should'; +import * as sinon from 'sinon'; +import * as TypeMoq from 'typemoq'; +import * as vscode from 'vscode'; +import { generateGuid } from '../../common/utils'; +import { UserCancelledError } from '../../common/api'; +import { ControllerModel, Registration } from '../../models/controllerModel'; +import { PostgresModel, EngineSettingsModel } from '../../models/postgresModel'; +import { ConnectToPGSqlDialog } from '../../ui/dialogs/connectPGDialog'; +import { AzureArcTreeDataProvider } from '../../ui/tree/azureArcTreeDataProvider'; +import { FakeControllerModel } from '../mocks/fakeControllerModel'; +import { FakeAzdataApi } from '../mocks/fakeAzdataApi'; +import { assert } from 'sinon'; + +export const FakePostgresServerShowOutput: azdataExt.AzdataOutput = { + logs: [], + stdout: [], + stderr: [], + result: { + apiVersion: 'version', + kind: 'postgresql', + metadata: { + creationTimestamp: '', + generation: 1, + name: 'pgt', + namespace: 'ns', + resourceVersion: '', + selfLink: '', + uid: '', + }, + spec: { + engine: { + extensions: [{ name: '' }], + settings: { + default: { ['']: '' } + } + }, + scale: { + shards: 0, + workers: 0 + }, + scheduling: { + default: { + resources: { + requests: { + cpu: '', + memory: '' + }, + limits: { + cpu: '', + memory: '' + } + } + } + }, + service: { + type: '', + port: 0 + }, + storage: { + data: { + className: '', + size: '' + }, + logs: { + className: '', + size: '' + }, + backups: { + className: '', + size: '' + } + } + }, + status: { + externalEndpoint: '127.0.0.1:5432', + readyPods: '', + state: '', + logSearchDashboard: '', + metricsDashboard: '', + podsStatus: [{ + conditions: [{ + lastTransitionTime: '', + message: '', + reason: '', + status: '', + type: '', + }], + name: '', + role: '', + }] + } + } +}; + +describe('PostgresModel', function (): void { + let controllerModel: ControllerModel; + let postgresModel: PostgresModel; + let azdataApi: azdataExt.IAzdataApi; + + afterEach(function (): void { + sinon.restore(); + }); + + beforeEach(async () => { + // Setup Controller Model + controllerModel = new FakeControllerModel(); + + //Stub calling azdata login and acquiring session + sinon.stub(controllerModel, 'acquireAzdataSession').returns(Promise.resolve(vscode.Disposable.from())); + + // Stub the azdata CLI API + azdataApi = new FakeAzdataApi(); + const azdataExt = TypeMoq.Mock.ofType(); + azdataExt.setup(x => x.azdata).returns(() => azdataApi); + sinon.stub(vscode.extensions, 'getExtension').returns({ exports: azdataExt.object }); + }); + + describe('refresh', function (): void { + + beforeEach(async () => { + // Setup PostgresModel + const postgresResource: PGResourceInfo = { name: 'pgt', resourceType: '' }; + const registration: Registration = { instanceName: '', state: '', instanceType: ResourceType.postgresInstances }; + postgresModel = new PostgresModel(controllerModel, postgresResource, registration, new AzureArcTreeDataProvider(TypeMoq.Mock.ofType().object)); + }); + + it('Updates model to expected config', async function (): Promise { + const postgresShow = sinon.stub().returns(FakePostgresServerShowOutput); + sinon.stub(azdataApi, 'arc').get(() => { + return { postgres: { server: { show(name: string) { return postgresShow(name); } } } }; + }); + + await postgresModel.refresh(); + sinon.assert.calledOnceWithExactly(postgresShow, postgresModel.info.name); + assert.match(postgresModel.config, FakePostgresServerShowOutput.result); + }); + + it('Updates onConfigLastUpdated when model is refreshed', async function (): Promise { + const postgresShow = sinon.stub().returns(FakePostgresServerShowOutput); + sinon.stub(azdataApi, 'arc').get(() => { + return { postgres: { server: { show(name: string) { return postgresShow(name); } } } }; + }); + + await postgresModel.refresh(); + sinon.assert.calledOnceWithExactly(postgresShow, postgresModel.info.name); + should(postgresModel.configLastUpdated).be.Date(); + }); + + it('Calls onConfigUpdated event when model is refreshed', async function (): Promise { + const postgresShow = sinon.stub().returns(FakePostgresServerShowOutput); + sinon.stub(azdataApi, 'arc').get(() => { + return { postgres: { server: { show(name: string) { return postgresShow(name); } } } }; + }); + const configUpdatedEvent = sinon.spy(vscode.EventEmitter.prototype, 'fire'); + + await postgresModel.refresh(); + sinon.assert.calledOnceWithExactly(postgresShow, postgresModel.info.name); + sinon.assert.calledOnceWithExactly(configUpdatedEvent, postgresModel.config); + }); + + it('Expected exception is thrown', async function (): Promise { + // Stub 'azdata arc postgres server show' to throw an exception + const error = new Error("something bad happened"); + const postgresShow = sinon.stub().throws(error); + sinon.stub(azdataApi, 'arc').get(() => { + return { postgres: { server: { show(name: string) { return postgresShow(name); } } } }; + }); + + await should(postgresModel.refresh()).be.rejectedWith(error); + }); + }); + + describe('getConnectionProfile', function (): void { + + beforeEach(async () => { + // Setup PostgresModel + const postgresResource: PGResourceInfo = { name: 'pgt', resourceType: '', userName: 'postgres', connectionId: '12345678' }; + const registration: Registration = { instanceName: '', state: '', instanceType: ResourceType.postgresInstances }; + postgresModel = new PostgresModel(controllerModel, postgresResource, registration, new AzureArcTreeDataProvider(TypeMoq.Mock.ofType().object)); + + //Stub calling refresh postgres model + const postgresShow = sinon.stub().returns(FakePostgresServerShowOutput); + sinon.stub(azdataApi, 'arc').get(() => { + return { postgres: { server: { show(name: string) { return postgresShow(name); } } } }; + }); + + //Call to provide external endpoint + await postgresModel.refresh(); + }); + + it('Rejected with expected error when user cancels', async function (): Promise { + const close = sinon.stub(ConnectToPGSqlDialog.prototype, 'waitForClose').returns(Promise.resolve(undefined)); + await should(postgresModel['getConnectionProfile']()).be.rejectedWith(new UserCancelledError()); + sinon.assert.calledOnce(close); + }); + + it('Show dialog prompt if password not found', async function (): Promise { + const connect = sinon.stub(azdata.connection, 'connect'); + + const cancelButtonMock = TypeMoq.Mock.ofType(); + cancelButtonMock.setup((x: any) => x.then).returns(() => undefined); + + const dialogMock = TypeMoq.Mock.ofType(); + dialogMock.setup(x => x.cancelButton).returns(() => cancelButtonMock.object); + dialogMock.setup((x: any) => x.then).returns(() => undefined); + const show = sinon.stub(azdata.window, 'createModelViewDialog').returns(dialogMock.object); + sinon.stub(azdata.window, 'openDialog'); + + const iconnectionProfileMock = TypeMoq.Mock.ofType(); + iconnectionProfileMock.setup((x: any) => x.then).returns(() => undefined); + const close = sinon.stub(ConnectToPGSqlDialog.prototype, 'waitForClose').returns(Promise.resolve(iconnectionProfileMock.object)); + + await postgresModel['getConnectionProfile'](); + sinon.assert.notCalled(connect); + sinon.assert.calledOnce(show); + sinon.assert.calledOnce(close); + }); + + it('Reads password from cred store and no dialog prompt', async function (): Promise { + const password = generateGuid(); + // Set up cred store to return our password + const credProviderMock = TypeMoq.Mock.ofType(); + credProviderMock.setup(x => x.readCredential(TypeMoq.It.isAny())).returns(() => Promise.resolve({ credentialId: 'id', password: password })); + credProviderMock.setup((x: any) => x.then).returns(() => undefined); + sinon.stub(azdata.credentials, 'getProvider').returns(Promise.resolve(credProviderMock.object)); + + const connectionResultMock = TypeMoq.Mock.ofType(); + connectionResultMock.setup(x => x.connected).returns(() => true); + connectionResultMock.setup((x: any) => x.then).returns(() => undefined); + const connect = sinon.stub(azdata.connection, 'connect').returns(Promise.resolve(connectionResultMock.object)); + + const cancelButtonMock = TypeMoq.Mock.ofType(); + cancelButtonMock.setup((x: any) => x.then).returns(() => undefined); + + const dialogMock = TypeMoq.Mock.ofType(); + dialogMock.setup(x => x.cancelButton).returns(() => cancelButtonMock.object); + dialogMock.setup((x: any) => x.then).returns(() => undefined); + const show = sinon.stub(azdata.window, 'createModelViewDialog').returns(dialogMock.object); + sinon.stub(azdata.window, 'openDialog'); + + const treeSave = sinon.spy(AzureArcTreeDataProvider.prototype, 'saveControllers'); + + await postgresModel['getConnectionProfile'](); + sinon.assert.calledOnce(connect); + sinon.assert.notCalled(show); + sinon.assert.calledOnce(treeSave); + }); + + it('Reads password from cred store and connect fails, show dialog prompt', async function (): Promise { + const password = generateGuid(); + // Set up cred store to return our password + const credProviderMock = TypeMoq.Mock.ofType(); + credProviderMock.setup(x => x.readCredential(TypeMoq.It.isAny())).returns(() => Promise.resolve({ credentialId: 'id', password: password })); + credProviderMock.setup((x: any) => x.then).returns(() => undefined); + sinon.stub(azdata.credentials, 'getProvider').returns(Promise.resolve(credProviderMock.object)); + + const connectionResultMock = TypeMoq.Mock.ofType(); + connectionResultMock.setup(x => x.connected).returns(() => false); + connectionResultMock.setup((x: any) => x.then).returns(() => undefined); + const connect = sinon.stub(azdata.connection, 'connect').returns(Promise.resolve(connectionResultMock.object)); + + const iconnectionProfileMock = TypeMoq.Mock.ofType(); + iconnectionProfileMock.setup((x: any) => x.then).returns(() => undefined); + const close = sinon.stub(ConnectToPGSqlDialog.prototype, 'waitForClose').returns(Promise.resolve(iconnectionProfileMock.object)); + + const cancelButtonMock = TypeMoq.Mock.ofType(); + cancelButtonMock.setup((x: any) => x.then).returns(() => undefined); + + const dialogMock = TypeMoq.Mock.ofType(); + dialogMock.setup(x => x.cancelButton).returns(() => cancelButtonMock.object); + dialogMock.setup((x: any) => x.then).returns(() => undefined); + const show = sinon.stub(azdata.window, 'createModelViewDialog').returns(dialogMock.object); + sinon.stub(azdata.window, 'openDialog'); + + await postgresModel['getConnectionProfile'](); + sinon.assert.calledOnce(connect); + sinon.assert.calledOnce(show); + sinon.assert.calledOnce(close); + }); + + it('Show dialog prompt if username not found', async function (): Promise { + // Setup PostgresModel without username + const postgresResource: PGResourceInfo = { name: 'pgt', resourceType: '', connectionId: '12345678' }; + const registration: Registration = { instanceName: '', state: '', instanceType: ResourceType.postgresInstances }; + let postgresModelNew = new PostgresModel(controllerModel, postgresResource, registration, new AzureArcTreeDataProvider(TypeMoq.Mock.ofType().object)); + await postgresModelNew.refresh(); + + const password = generateGuid(); + // Set up cred store to return our password + const credProviderMock = TypeMoq.Mock.ofType(); + credProviderMock.setup(x => x.readCredential(TypeMoq.It.isAny())).returns(() => Promise.resolve({ credentialId: 'id', password: password })); + credProviderMock.setup((x: any) => x.then).returns(() => undefined); + sinon.stub(azdata.credentials, 'getProvider').returns(Promise.resolve(credProviderMock.object)); + + const connect = sinon.stub(azdata.connection, 'connect'); + const cancelButtonMock = TypeMoq.Mock.ofType(); + cancelButtonMock.setup((x: any) => x.then).returns(() => undefined); + + const dialogMock = TypeMoq.Mock.ofType(); + dialogMock.setup(x => x.cancelButton).returns(() => cancelButtonMock.object); + dialogMock.setup((x: any) => x.then).returns(() => undefined); + const show = sinon.stub(azdata.window, 'createModelViewDialog').returns(dialogMock.object); + sinon.stub(azdata.window, 'openDialog'); + + const iconnectionProfileMock = TypeMoq.Mock.ofType(); + iconnectionProfileMock.setup((x: any) => x.then).returns(() => undefined); + const close = sinon.stub(ConnectToPGSqlDialog.prototype, 'waitForClose').returns(Promise.resolve(iconnectionProfileMock.object)); + + await postgresModelNew['getConnectionProfile'](); + sinon.assert.notCalled(connect); + sinon.assert.calledOnce(show); + sinon.assert.calledOnce(close); + }); + + it('Shows dialog prompt if no connection id', async function (): Promise { + // Setup PostgresModel without connectionId + const postgresResource: PGResourceInfo = { name: 'pgt', resourceType: '' }; + const registration: Registration = { instanceName: '', state: '', instanceType: ResourceType.postgresInstances }; + let postgresModelNew = new PostgresModel(controllerModel, postgresResource, registration, new AzureArcTreeDataProvider(TypeMoq.Mock.ofType().object)); + await postgresModelNew.refresh(); + + const provider = sinon.stub(azdata.credentials, 'getProvider'); + const connect = sinon.stub(azdata.connection, 'connect'); + const cancelButtonMock = TypeMoq.Mock.ofType(); + cancelButtonMock.setup((x: any) => x.then).returns(() => undefined); + + const dialogMock = TypeMoq.Mock.ofType(); + dialogMock.setup(x => x.cancelButton).returns(() => cancelButtonMock.object); + dialogMock.setup((x: any) => x.then).returns(() => undefined); + const show = sinon.stub(azdata.window, 'createModelViewDialog').returns(dialogMock.object); + sinon.stub(azdata.window, 'openDialog'); + + const iconnectionProfileMock = TypeMoq.Mock.ofType(); + iconnectionProfileMock.setup((x: any) => x.then).returns(() => undefined); + const close = sinon.stub(ConnectToPGSqlDialog.prototype, 'waitForClose').returns(Promise.resolve(iconnectionProfileMock.object)); + + await postgresModelNew['getConnectionProfile'](); + sinon.assert.notCalled(provider); + sinon.assert.notCalled(connect); + sinon.assert.calledOnce(show); + sinon.assert.calledOnce(close); + }); + }); + + describe('getEngineSettings', function (): void { + + beforeEach(async () => { + // Setup PostgresModel + const postgresResource: PGResourceInfo = { name: 'pgt', resourceType: '', userName: 'postgres', connectionId: '12345678' }; + const registration: Registration = { instanceName: '', state: '', instanceType: ResourceType.postgresInstances }; + postgresModel = new PostgresModel(controllerModel, postgresResource, registration, new AzureArcTreeDataProvider(TypeMoq.Mock.ofType().object)); + + //Stub calling refresh postgres model + const postgresShow = sinon.stub().returns(FakePostgresServerShowOutput); + sinon.stub(azdataApi, 'arc').get(() => { + return { postgres: { server: { show(name: string) { return postgresShow(name); } } } }; + }); + + //Stub how to get connection profile + const iconnectionProfileMock = TypeMoq.Mock.ofType(); + iconnectionProfileMock.setup((x: any) => x.then).returns(() => undefined); + sinon.stub(ConnectToPGSqlDialog.prototype, 'waitForClose').returns(Promise.resolve(iconnectionProfileMock.object)); + const cancelButtonMock = TypeMoq.Mock.ofType(); + cancelButtonMock.setup((x: any) => x.then).returns(() => undefined); + + const dialogMock = TypeMoq.Mock.ofType(); + dialogMock.setup(x => x.cancelButton).returns(() => cancelButtonMock.object); + dialogMock.setup((x: any) => x.then).returns(() => undefined); + sinon.stub(azdata.window, 'createModelViewDialog').returns(dialogMock.object); + sinon.stub(azdata.window, 'openDialog'); + + sinon.stub(azdata.connection, 'getUriForConnection'); + + //Call to provide external endpoint + await postgresModel.refresh(); + }); + + it('Throw error when trying to connect fails', async function (): Promise { + const errorMessage = 'Mock connection fail occured'; + const connectionResultMock = TypeMoq.Mock.ofType(); + connectionResultMock.setup(x => x.connected).returns(() => false); + connectionResultMock.setup(x => x.errorMessage).returns(() => errorMessage); + connectionResultMock.setup((x: any) => x.then).returns(() => undefined); + const connect = sinon.stub(azdata.connection, 'connect').returns(Promise.resolve(connectionResultMock.object)); + + await should(postgresModel.getEngineSettings()).be.rejectedWith(new Error(errorMessage)); + sinon.assert.calledOnce(connect); + }); + + it('Update active connection id when connect passes', async function (): Promise { + const connectionID = '098765'; + const connectionResultMock = TypeMoq.Mock.ofType(); + connectionResultMock.setup(x => x.connected).returns(() => true); + connectionResultMock.setup(x => x.connectionId).returns(() => connectionID); + connectionResultMock.setup((x: any) => x.then).returns(() => undefined); + const connect = sinon.stub(azdata.connection, 'connect').returns(Promise.resolve(connectionResultMock.object)); + + const array: azdata.DbCellValue[][] = []; + + const executeMock = TypeMoq.Mock.ofType(); + executeMock.setup(x => x.rows).returns(() => array); + executeMock.setup((x: any) => x.then).returns(() => undefined); + + const providerMock = TypeMoq.Mock.ofType(); + providerMock.setup(x => x.runQueryAndReturn(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(async () => executeMock.object); + providerMock.setup((x: any) => x.then).returns(() => undefined); + sinon.stub(azdata.dataprotocol, 'getProvider').returns(providerMock.object); + + await postgresModel.getEngineSettings(); + sinon.assert.calledOnce(connect); + sinon.assert.match(postgresModel['_activeConnectionId'], connectionID); + }); + + it('Updates engineSettingsLastUpdated after populating engine settings', async function (): Promise { + const connectionResultMock = TypeMoq.Mock.ofType(); + connectionResultMock.setup(x => x.connected).returns(() => true); + connectionResultMock.setup((x: any) => x.then).returns(() => undefined); + sinon.stub(azdata.connection, 'connect').returns(Promise.resolve(connectionResultMock.object)); + + const array: azdata.DbCellValue[][] = []; + + const executeMock = TypeMoq.Mock.ofType(); + executeMock.setup(x => x.rows).returns(() => array); + executeMock.setup((x: any) => x.then).returns(() => undefined); + + const providerMock = TypeMoq.Mock.ofType(); + providerMock.setup(x => x.runQueryAndReturn(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(async () => executeMock.object); + providerMock.setup((x: any) => x.then).returns(() => undefined); + sinon.stub(azdata.dataprotocol, 'getProvider').returns(providerMock.object); + + await postgresModel.getEngineSettings(); + should(postgresModel.engineSettingsLastUpdated).be.Date(); + }); + + it('Calls onEngineSettingsUpdated event after populating engine settings', async function (): Promise { + const connectionResultMock = TypeMoq.Mock.ofType(); + connectionResultMock.setup(x => x.connected).returns(() => true); + connectionResultMock.setup((x: any) => x.then).returns(() => undefined); + sinon.stub(azdata.connection, 'connect').returns(Promise.resolve(connectionResultMock.object)); + + const array: azdata.DbCellValue[][] = []; + + const executeMock = TypeMoq.Mock.ofType(); + executeMock.setup(x => x.rows).returns(() => array); + executeMock.setup((x: any) => x.then).returns(() => undefined); + + const providerMock = TypeMoq.Mock.ofType(); + providerMock.setup(x => x.runQueryAndReturn(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(async () => executeMock.object); + providerMock.setup((x: any) => x.then).returns(() => undefined); + sinon.stub(azdata.dataprotocol, 'getProvider').returns(providerMock.object); + + const onEngineSettingsUpdated = sinon.spy(vscode.EventEmitter.prototype, 'fire'); + + await postgresModel.getEngineSettings(); + sinon.assert.calledOnceWithExactly(onEngineSettingsUpdated, postgresModel.workerNodesEngineSettings); + }); + + it('Populating engine settings skips certain parameters', async function (): Promise { + const connectionResultMock = TypeMoq.Mock.ofType(); + connectionResultMock.setup(x => x.connected).returns(() => true); + connectionResultMock.setup((x: any) => x.then).returns(() => undefined); + sinon.stub(azdata.connection, 'connect').returns(Promise.resolve(connectionResultMock.object)); + + const rows: azdata.DbCellValue[][] = [ + [{ + displayValue: 'archive_timeout', + isNull: false, + invariantCultureDisplayValue: '' + }] + ]; + + const executeMock = TypeMoq.Mock.ofType(); + executeMock.setup(x => x.rows).returns(() => rows); + executeMock.setup((x: any) => x.then).returns(() => undefined); + + const providerMock = TypeMoq.Mock.ofType(); + providerMock.setup(x => x.runQueryAndReturn(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(async () => executeMock.object); + providerMock.setup((x: any) => x.then).returns(() => undefined); + sinon.stub(azdata.dataprotocol, 'getProvider').returns(providerMock.object); + + await postgresModel.getEngineSettings(); + should(postgresModel.workerNodesEngineSettings.pop()).be.undefined(); + }); + + it('Populates engine settings accurately', async function (): Promise { + const connectionResultMock = TypeMoq.Mock.ofType(); + connectionResultMock.setup(x => x.connected).returns(() => true); + connectionResultMock.setup((x: any) => x.then).returns(() => undefined); + sinon.stub(azdata.connection, 'connect').returns(Promise.resolve(connectionResultMock.object)); + + const rows: azdata.DbCellValue[][] = [ + [{ + displayValue: 'test0', + isNull: false, + invariantCultureDisplayValue: '' + }, + { + displayValue: 'test1', + isNull: false, + invariantCultureDisplayValue: '' + }, + { + displayValue: 'test2', + isNull: false, + invariantCultureDisplayValue: '' + }, + { + displayValue: 'test3', + isNull: false, + invariantCultureDisplayValue: '' + }, + { + displayValue: 'test4', + isNull: false, + invariantCultureDisplayValue: '' + }, + { + displayValue: 'test5', + isNull: false, + invariantCultureDisplayValue: '' + }, + { + displayValue: 'test6', + isNull: false, + invariantCultureDisplayValue: '' + }], + ]; + + const engineSettingsModelCompare: EngineSettingsModel = { + parameterName: 'test0', + value: 'test1', + description: 'test2', + min: 'test3', + max: 'test4', + options: 'test5', + type: 'test6' + }; + + const executeMock = TypeMoq.Mock.ofType(); + executeMock.setup(x => x.rows).returns(() => rows); + executeMock.setup((x: any) => x.then).returns(() => undefined); + + const providerMock = TypeMoq.Mock.ofType(); + providerMock.setup(x => x.runQueryAndReturn(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(async () => executeMock.object); + providerMock.setup((x: any) => x.then).returns(() => undefined); + sinon.stub(azdata.dataprotocol, 'getProvider').returns(providerMock.object); + + await postgresModel.getEngineSettings(); + should(postgresModel.workerNodesEngineSettings.pop()).be.match(engineSettingsModelCompare); + }); + + }); + +});