SQL Bindings - Adds Views support for Create Azure Function with SQL Binding (#19894)

* add views logic

* add views tests

* address PR and Figma comments

* add ObjectType Enum to be used as a parameter

* add comment
This commit is contained in:
Vasu Bhog
2022-07-06 10:31:00 -07:00
committed by GitHub
parent 2e2fcbe5fc
commit 163ca5ec64
8 changed files with 378 additions and 185 deletions

View File

@@ -15,8 +15,8 @@ import * as utils from '../../common/utils';
import * as azureFunctionsContracts from '../../contracts/azureFunctions/azureFunctionsContracts';
import * as azureFunctionService from '../../services/azureFunctionsService';
import { BindingType } from 'sql-bindings';
import { IConnectionInfo } from 'vscode-mssql';
import { BindingType, ObjectType } from 'sql-bindings';
import { ConnectionDetails, IConnectionInfo } from 'vscode-mssql';
import { createTestCredentials, createTestTableNode, createTestUtils, TestUtils } from '../testUtils';
const rootFolderPath = 'test';
@@ -36,118 +36,6 @@ describe('AzureFunctionsService', () => {
constants.install, constants.learnMore, constants.doNotInstall]);
});
it('Should create azure function project using the command from command palette (no connection info)', async function (): Promise<void> {
// This test will have an azure function project already in the project and the azure functions extension installed (stubbed)
sinon.stub(azureFunctionUtils, 'getAzureFunctionsExtensionApi').resolves(testUtils.azureFunctionsExtensionApi.object); // set azure functions extension api
sinon.stub(azureFunctionUtils, 'getAzureFunctionProject').resolves(projectFilePath); //set azure function project to have one project
sinon.stub(utils, 'getVscodeMssqlApi').resolves(testUtils.vscodeMssqlIExtension.object);
// create fake connection string settings for local.setting.json to be used
sinon.stub(fs.promises, 'access').onFirstCall().resolves();
sinon.stub(fs, 'readFileSync').withArgs(sinon.match.any).returns(
`{"IsEncrypted": false,
"Values": {"test1": "test1", "test2": "test2", "test3":"test3"}}`
);
let connectionInfo: IConnectionInfo = createTestCredentials(); // create test connectionInfo
let connectionDetails = { options: connectionInfo };
testUtils.vscodeMssqlIExtension.setup(x => x.getConnectionString(connectionDetails, true, false)).returns(() => Promise.resolve('testConnectionString'));
const showErrorMessageSpy = sinon.spy(vscode.window, 'showErrorMessage');
// select input or output binding
let quickPickStub = sinon.stub(vscode.window, 'showQuickPick').resolves(<any>{ label: constants.input, type: BindingType.input });
// no table used for connection info so prompt user to get connection info
testUtils.vscodeMssqlIExtension.setup(x => x.promptForConnection(true)).returns(() => Promise.resolve(connectionInfo));
testUtils.vscodeMssqlIExtension.setup(x => x.connect(connectionInfo)).returns(() => Promise.resolve('testConnectionURI'));
testUtils.vscodeMssqlIExtension.setup(x => x.listDatabases('testConnectionURI')).returns(() => Promise.resolve(['testDb']));
// select the testDB from list of databases based on connection info
quickPickStub.onSecondCall().resolves(('testDb') as any);
// get tables from selected database
const params = { ownerUri: 'testConnectionURI', queryString: azureFunctionUtils.tablesQuery('testDb') };
testUtils.vscodeMssqlIExtension.setup(x => x.sendRequest(azureFunctionsContracts.SimpleExecuteRequest.type, params))
.returns(() => Promise.resolve({ rowCount: 1, columnInfo: [], rows: [[{ displayValue: '[schema].[testTable]' }]] }));
// select the schema.testTable from list of tables based on connection info and database
quickPickStub.onThirdCall().resolves(('[schema].[testTable]') as any);
// set azure function name
let inputStub = sinon.stub(vscode.window, 'showInputBox').resolves('testFunctionName');
// promptAndUpdateConnectionStringSetting
quickPickStub.onCall(3).resolves(<any>{ label: constants.createNewLocalAppSettingWithIcon });
inputStub.onSecondCall().resolves('SqlConnectionString');
// promptConnectionStringPasswordAndUpdateConnectionString - tested in AzureFunctionUtils.test.ts
quickPickStub.onCall(4).resolves((constants.yesString) as any);
testUtils.vscodeMssqlIExtension.setup(x => x.getConnectionString(connectionDetails, true, false)).returns(() => Promise.resolve('testConnectionString'));
// setLocalAppSetting with connection string setting name and connection string
// fails if we dont set writeFile stub
sinon.stub(fs.promises, 'writeFile').resolves();
sinon.stub(azureFunctionUtils, 'setLocalAppSetting').withArgs(sinon.match.any, 'SqlConnectionString', 'testConnectionString').resolves((true));
sinon.stub(utils, 'executeCommand').resolves('downloaded nuget package');
const testWatcher = TypeMoq.Mock.ofType<vscode.FileSystemWatcher>().object;
sinon.stub(azureFunctionUtils, 'waitForNewFunctionFile').withArgs(sinon.match.any).returns({ filePromise: Promise.resolve('TestFileCreated'), watcherDisposable: testWatcher });
should(connectionInfo.database).equal('my_db', 'ConnectionInfo database should not be changed');
await azureFunctionService.createAzureFunction();
should(showErrorMessageSpy.notCalled).be.true('showErrorMessage should not have been called');
// set the connection info to be the one the user selects from list of databases quickpick
should(connectionInfo.database).equal('testDb', 'connectionInfo.database should be testDb after user selects testDb');
});
it('Should create azure function project using command via the sql server table OE', async function (): Promise<void> {
// This test will have an azure function project already in the project and the azure functions extension installed (stubbed)
sinon.stub(azureFunctionUtils, 'getAzureFunctionsExtensionApi').resolves(testUtils.azureFunctionsExtensionApi.object); // set azure functions extension api
sinon.stub(azureFunctionUtils, 'getAzureFunctionProject').resolves(projectFilePath); //set azure function project to have one project
sinon.stub(utils, 'getVscodeMssqlApi').resolves(testUtils.vscodeMssqlIExtension.object);
// create fake connection string settings for local.setting.json to be used
sinon.stub(fs.promises, 'access').onFirstCall().resolves();
sinon.stub(fs, 'readFileSync').withArgs(sinon.match.any).returns(
`{"IsEncrypted": false,
"Values": {"test1": "test1", "test2": "test2", "test3":"test3"}}`
);
let connectionInfo: IConnectionInfo = createTestCredentials();// create test connectionInfo
let connectionDetails = { options: connectionInfo };
testUtils.vscodeMssqlIExtension.setup(x => x.getConnectionString(connectionDetails, true, false)).returns(() => Promise.resolve('testConnectionString'));
const showErrorMessageSpy = sinon.spy(vscode.window, 'showErrorMessage');
// select input or output binding
let quickPickStub = sinon.stub(vscode.window, 'showQuickPick').resolves(<any>{ label: constants.input, type: BindingType.input });
// table node used when creating azure function project
let tableTestNode = createTestTableNode(connectionInfo);
// set azure function name
let inputStub = sinon.stub(vscode.window, 'showInputBox').resolves('testFunctionName');
// promptAndUpdateConnectionStringSetting
quickPickStub.onSecondCall().resolves(<any>{ label: constants.createNewLocalAppSettingWithIcon });
inputStub.onSecondCall().resolves('SqlConnectionString');
// promptConnectionStringPasswordAndUpdateConnectionString - tested in AzureFunctionUtils.test.ts
quickPickStub.onThirdCall().resolves((constants.yesString) as any);
testUtils.vscodeMssqlIExtension.setup(x => x.getConnectionString(connectionDetails, true, false)).returns(() => Promise.resolve('testConnectionString'));
// setLocalAppSetting with connection string setting name and connection string
// fails if we dont set writeFile stub
sinon.stub(fs.promises, 'writeFile').resolves();
sinon.stub(azureFunctionUtils, 'setLocalAppSetting').withArgs(sinon.match.any, 'SqlConnectionString', 'testConnectionString').resolves((true));
sinon.stub(utils, 'executeCommand').resolves('downloaded nuget package');
const testWatcher = TypeMoq.Mock.ofType<vscode.FileSystemWatcher>().object;
sinon.stub(azureFunctionUtils, 'waitForNewFunctionFile').withArgs(sinon.match.any).returns({ filePromise: Promise.resolve('TestFileCreated'), watcherDisposable: testWatcher });
should(connectionInfo.database).equal('my_db', 'ConnectionInfo database should not be changed');
await azureFunctionService.createAzureFunction(tableTestNode);
should(showErrorMessageSpy.notCalled).be.true('showErrorMessage should not have been called');
// set the connection info to be the one used from the test table node from OE
should(connectionInfo.database).equal('testDb', 'connectionInfo.database should be testDb after user selects testDb');
});
it('Should open link to learn more about SQL bindings when no azure function project found in folder or workspace', async function (): Promise<void> {
// This test will ask user that an azure function project must be opened to create an azure function with sql binding
sinon.stub(azureFunctionUtils, 'getAzureFunctionsExtensionApi').resolves(testUtils.azureFunctionsExtensionApi.object); // set azure functions extension api
@@ -205,11 +93,199 @@ describe('AzureFunctionsService', () => {
const testWatcher = TypeMoq.Mock.ofType<vscode.FileSystemWatcher>().object;
sinon.stub(azureFunctionUtils, 'waitForNewFunctionFile').withArgs(sinon.match.any).returns({ filePromise: Promise.resolve('TestFileCreated'), watcherDisposable: testWatcher });
should(connectionInfo.database).equal('my_db', 'ConnectionInfo database should not be changed');
should(connectionInfo.database).equal('my_db', 'Initial ConnectionInfo database should be my_db');
await azureFunctionService.createAzureFunction(tableTestNode);
should(showErrorStub.calledOnce).be.true('showErrorMessage should have been called');
});
describe('For table object', () => {
let connectionInfo: IConnectionInfo;
let connectionDetails: ConnectionDetails;
let showErrorMessageSpy: sinon.SinonSpy;
beforeEach(function (): void {
// This test will have an azure function project already in the project and the azure functions extension installed (stubbed)
sinon.stub(azureFunctionUtils, 'getAzureFunctionsExtensionApi').resolves(testUtils.azureFunctionsExtensionApi.object); // set azure functions extension api
sinon.stub(azureFunctionUtils, 'getAzureFunctionProject').resolves(projectFilePath); //set azure function project to have one project
sinon.stub(utils, 'getVscodeMssqlApi').resolves(testUtils.vscodeMssqlIExtension.object);
// create fake connection string settings for local.setting.json to be used
sinon.stub(fs.promises, 'access').onFirstCall().resolves();
sinon.stub(fs, 'readFileSync').withArgs(sinon.match.any).returns(
`{"IsEncrypted": false,
"Values": {"test1": "test1", "test2": "test2", "test3":"test3"}}`
);
connectionInfo = createTestCredentials(); // create test connectionInfo
connectionDetails = { options: connectionInfo }; // use for getConnectionString request
testUtils.vscodeMssqlIExtension.setup(x => x.getConnectionString(connectionDetails, true, false)).returns(() => Promise.resolve('testConnectionString'));
// setLocalAppSetting with connection string setting name and connection string
// fails if we dont set writeFile stub
sinon.stub(fs.promises, 'writeFile').resolves();
sinon.stub(azureFunctionUtils, 'setLocalAppSetting').withArgs(sinon.match.any, 'SqlConnectionString', 'testConnectionString').resolves((true));
sinon.stub(utils, 'executeCommand').resolves('downloaded nuget package');
const testWatcher = TypeMoq.Mock.ofType<vscode.FileSystemWatcher>().object;
sinon.stub(azureFunctionUtils, 'waitForNewFunctionFile').withArgs(sinon.match.any).returns({ filePromise: Promise.resolve('TestFileCreated'), watcherDisposable: testWatcher });
showErrorMessageSpy = sinon.spy(vscode.window, 'showErrorMessage'); // error message spy to be used for checking tests
});
it('Should create azure function project using the command from command palette (no connection info)', async function (): Promise<void> {
// select table
let quickPickStub = sinon.stub(vscode.window, 'showQuickPick').onFirstCall().resolves({ label: constants.input, type: ObjectType.Table } as any);
// select input or output binding
quickPickStub.onSecondCall().resolves(<any>{ label: constants.input, type: BindingType.input });
// no connection node used for connection info so prompt user to get connection info
testUtils.vscodeMssqlIExtension.setup(x => x.promptForConnection(true)).returns(() => Promise.resolve(connectionInfo));
testUtils.vscodeMssqlIExtension.setup(x => x.connect(connectionInfo)).returns(() => Promise.resolve('testConnectionURI'));
testUtils.vscodeMssqlIExtension.setup(x => x.listDatabases('testConnectionURI')).returns(() => Promise.resolve(['testDb']));
// select the testDB from list of databases based on connection info
quickPickStub.onThirdCall().resolves(('testDb') as any);
// get tables from selected database
const params = { ownerUri: 'testConnectionURI', queryString: azureFunctionUtils.tablesQuery('testDb') };
testUtils.vscodeMssqlIExtension.setup(x => x.sendRequest(azureFunctionsContracts.SimpleExecuteRequest.type, params))
.returns(() => Promise.resolve({ rowCount: 1, columnInfo: [], rows: [[{ displayValue: '[schema].[testTable]' }]] }));
// select the schema.testTable from list of tables based on connection info and database
quickPickStub.onCall(3).resolves(('[schema].[testTable]') as any);
// set azure function name
let inputStub = sinon.stub(vscode.window, 'showInputBox').resolves('testFunctionName');
// promptAndUpdateConnectionStringSetting
quickPickStub.onCall(4).resolves(<any>{ label: constants.createNewLocalAppSettingWithIcon });
inputStub.onSecondCall().resolves('SqlConnectionString');
// promptConnectionStringPasswordAndUpdateConnectionString - tested in AzureFunctionUtils.test.ts
quickPickStub.onCall(5).resolves((constants.yesString) as any);
testUtils.vscodeMssqlIExtension.setup(x => x.getConnectionString(connectionDetails, true, false)).returns(() => Promise.resolve('testConnectionString'));
should(connectionInfo.database).equal('my_db', 'Initial ConnectionInfo database should be my_db');
await azureFunctionService.createAzureFunction();
should(showErrorMessageSpy.notCalled).be.true('showErrorMessage should not have been called');
should(connectionInfo.database).equal('testDb', 'connectionInfo.database should be testDb after user selects testDb');
});
it('Should create azure function project using command via the sql server table object explorer', async function (): Promise<void> {
// select input or output binding
let quickPickStub = sinon.stub(vscode.window, 'showQuickPick').resolves(<any>{ label: constants.input, type: BindingType.input });
// table node used when creating azure function project
let tableTestNode = createTestTableNode(connectionInfo);
// set azure function name
let inputStub = sinon.stub(vscode.window, 'showInputBox').resolves('testFunctionName');
// promptAndUpdateConnectionStringSetting
quickPickStub.onSecondCall().resolves(<any>{ label: constants.createNewLocalAppSettingWithIcon });
inputStub.onSecondCall().resolves('SqlConnectionString');
// promptConnectionStringPasswordAndUpdateConnectionString - tested in AzureFunctionUtils.test.ts
quickPickStub.onThirdCall().resolves((constants.yesString) as any);
testUtils.vscodeMssqlIExtension.setup(x => x.getConnectionString(connectionDetails, true, false)).returns(() => Promise.resolve('testConnectionString'));
should(connectionInfo.database).equal('my_db', 'Initial ConnectionInfo database should be my_db');
await azureFunctionService.createAzureFunction(tableTestNode);
should(showErrorMessageSpy.notCalled).be.true('showErrorMessage should not have been called');
should(connectionInfo.database).equal('testDb', 'connectionInfo.database should be testDb used from the test table node from OE');
});
});
describe('For view object', function (): void {
let connectionInfo: IConnectionInfo;
let connectionDetails: ConnectionDetails;
let showErrorMessageSpy: sinon.SinonSpy;
beforeEach(function (): void {
// This test will have an azure function project already in the project and the azure functions extension installed (stubbed)
sinon.stub(azureFunctionUtils, 'getAzureFunctionsExtensionApi').resolves(testUtils.azureFunctionsExtensionApi.object); // set azure functions extension api
sinon.stub(azureFunctionUtils, 'getAzureFunctionProject').resolves(projectFilePath); //set azure function project to have one project
sinon.stub(utils, 'getVscodeMssqlApi').resolves(testUtils.vscodeMssqlIExtension.object);
// create fake connection string settings for local.setting.json to be used
sinon.stub(fs.promises, 'access').onFirstCall().resolves();
sinon.stub(fs, 'readFileSync').withArgs(sinon.match.any).returns(
`{"IsEncrypted": false,
"Values": {"test1": "test1", "test2": "test2", "test3":"test3"}}`
);
connectionInfo = createTestCredentials(); // create test connectionInfo
connectionDetails = { options: connectionInfo }; // use for getConnectionString request
testUtils.vscodeMssqlIExtension.setup(x => x.getConnectionString(connectionDetails, true, false)).returns(() => Promise.resolve('testConnectionString'));
// setLocalAppSetting with connection string setting name and connection string
// fails if we dont set writeFile stub
sinon.stub(fs.promises, 'writeFile').resolves();
sinon.stub(azureFunctionUtils, 'setLocalAppSetting').withArgs(sinon.match.any, 'SqlConnectionString', 'testConnectionString').resolves((true));
sinon.stub(utils, 'executeCommand').resolves('downloaded nuget package');
const testWatcher = TypeMoq.Mock.ofType<vscode.FileSystemWatcher>().object;
sinon.stub(azureFunctionUtils, 'waitForNewFunctionFile').withArgs(sinon.match.any).returns({ filePromise: Promise.resolve('TestFileCreated'), watcherDisposable: testWatcher });
showErrorMessageSpy = sinon.spy(vscode.window, 'showErrorMessage'); // error message spy to be used for checking tests
});
it('Should create azure function project using the command from command palette (no connection info)', async function (): Promise<void> {
// select view
let quickPickStub = sinon.stub(vscode.window, 'showQuickPick').onFirstCall().resolves({ label: constants.input, type: ObjectType.View } as any);
// input binding should be used for views
// no connection node used for connection info so prompt user to get connection info
testUtils.vscodeMssqlIExtension.setup(x => x.promptForConnection(true)).returns(() => Promise.resolve(connectionInfo));
testUtils.vscodeMssqlIExtension.setup(x => x.connect(connectionInfo)).returns(() => Promise.resolve('testConnectionURI'));
testUtils.vscodeMssqlIExtension.setup(x => x.listDatabases('testConnectionURI')).returns(() => Promise.resolve(['testDb']));
// select the testDB from list of databases based on connection info
quickPickStub.onSecondCall().resolves(('testDb') as any);
// get views from selected database
const params = { ownerUri: 'testConnectionURI', queryString: azureFunctionUtils.viewsQuery('testDb') };
testUtils.vscodeMssqlIExtension.setup(x => x.sendRequest(azureFunctionsContracts.SimpleExecuteRequest.type, params))
.returns(() => Promise.resolve({ rowCount: 1, columnInfo: [], rows: [[{ displayValue: '[schema].[testView]' }]] }));
// select the schema.testView from list of tables based on connection info and database
quickPickStub.onThirdCall().resolves(('[schema].[testView]') as any);
// set azure function name
let inputStub = sinon.stub(vscode.window, 'showInputBox').resolves('testFunctionName');
// promptAndUpdateConnectionStringSetting
quickPickStub.onCall(3).resolves(<any>{ label: constants.createNewLocalAppSettingWithIcon });
inputStub.onSecondCall().resolves('SqlConnectionString');
// promptConnectionStringPasswordAndUpdateConnectionString - tested in AzureFunctionUtils.test.ts
quickPickStub.onCall(4).resolves((constants.yesString) as any);
testUtils.vscodeMssqlIExtension.setup(x => x.getConnectionString(connectionDetails, true, false)).returns(() => Promise.resolve('testConnectionString'));
should(connectionInfo.database).equal('my_db', 'Initial ConnectionInfo database should be my_db');
await azureFunctionService.createAzureFunction();
should(showErrorMessageSpy.notCalled).be.true('showErrorMessage should not have been called');
should(connectionInfo.database).equal('testDb', 'connectionInfo.database should be testDb after user selects testDb');
});
it('Should create azure function project using command via the sql server view object explorer', async function (): Promise<void> {
// Since views is stricly used only with input binding we go directly to asking for function name
// set azure function name
let inputStub = sinon.stub(vscode.window, 'showInputBox').resolves('testFunctionName');
// prompt user to select sql connection string setting from local.settings.json
let quickPickStub = sinon.stub(vscode.window, 'showQuickPick').onFirstCall().resolves(<any>{ label: constants.createNewLocalAppSettingWithIcon });
// promptAndUpdateConnectionStringSetting
inputStub.onSecondCall().resolves('SqlConnectionString');
// promptConnectionStringPasswordAndUpdateConnectionString - tested in AzureFunctionUtils.test.ts
quickPickStub.onSecondCall().resolves((constants.yesString) as any);
testUtils.vscodeMssqlIExtension.setup(x => x.getConnectionString(connectionDetails, true, false)).returns(() => Promise.resolve('testConnectionString'));
should(connectionInfo.database).equal('my_db', 'Initial ConnectionInfo database should be my_db');
// table node used when creating azure function project
let tableTestNode = createTestTableNode(connectionInfo);
await azureFunctionService.createAzureFunction(tableTestNode);
should(showErrorMessageSpy.notCalled).be.true('showErrorMessage should not have been called');
should(connectionInfo.database).equal('testDb', 'connectionInfo.database should be testDb used from the test view node from OE');
});
});
});
describe('Cancel/Error scenarios for Azure Function with SQL Binding ', function (): void {
@@ -218,11 +294,12 @@ describe('AzureFunctionsService', () => {
sinon.stub(azureFunctionUtils, 'getAzureFunctionsExtensionApi').resolves(testUtils.azureFunctionsExtensionApi.object); // set azure functions extension api
sinon.stub(azureFunctionUtils, 'getAzureFunctionProject').resolves(projectFilePath); //set azure function project to have one project
sinon.stub(utils, 'getVscodeMssqlApi').resolves(testUtils.vscodeMssqlIExtension.object);
// select input or output binding
quickPickStub = sinon.stub(vscode.window, 'showQuickPick').resolves(<any>{ label: constants.input, type: BindingType.input });
});
it('Should prompt connection profile when user cancels selecting database', async function (): Promise<void> {
// select view for object type
quickPickStub = sinon.stub(vscode.window, 'showQuickPick').onFirstCall().resolves({ label: constants.input, type: ObjectType.View } as any);
// This test will have an azure function project already in the project and the azure functions extension installed (stubbed)
let connectionInfo: IConnectionInfo = createTestCredentials();// create test connectionInfo
@@ -241,7 +318,10 @@ describe('AzureFunctionsService', () => {
should(promptForConnectionStub.callCount).equal(2, 'promptForConnection should have been called 2 times only');
});
it('Should prompt connection profile when user cancels selecting table', async function (): Promise<void> {
it('Should prompt connection profile when user cancels selecting object from object lists', async function (): Promise<void> {
// select view for object type
quickPickStub = sinon.stub(vscode.window, 'showQuickPick').onFirstCall().resolves({ label: constants.input, type: ObjectType.View } as any);
// This test will re-prompt the user to choose connection profile
let connectionInfo: IConnectionInfo = createTestCredentials();// create test connectionInfo
@@ -253,10 +333,10 @@ describe('AzureFunctionsService', () => {
// select the testDB for promptForDatabase
quickPickStub.onSecondCall().resolves(('testDb') as any);
// get tables from selected database
const params = { ownerUri: 'testConnectionURI', queryString: azureFunctionUtils.tablesQuery('testDb') };
// get views from selected database
const params = { ownerUri: 'testConnectionURI', queryString: azureFunctionUtils.viewsQuery('testDb') };
testUtils.vscodeMssqlIExtension.setup(x => x.sendRequest(azureFunctionsContracts.SimpleExecuteRequest.type, params))
.returns(() => Promise.resolve({ rowCount: 1, columnInfo: [], rows: [[{ displayValue: '[schema].[testTable]' }]] }));
.returns(() => Promise.resolve({ rowCount: 1, columnInfo: [], rows: [[{ displayValue: '[schema].[testView]' }]] }));
// cancel out of promptForTables - select table to use
quickPickStub.onThirdCall().resolves(undefined);
@@ -270,31 +350,34 @@ describe('AzureFunctionsService', () => {
});
it('Should prompt select table when user cancels out of manually entering table', async function (): Promise<void> {
// select table for object type
quickPickStub = sinon.stub(vscode.window, 'showQuickPick').onFirstCall().resolves({ label: constants.input, type: ObjectType.Table } as any);
quickPickStub.onSecondCall().resolves(<any>{ label: constants.input, type: BindingType.input });
// This test will have an azure function project already in the project and the azure functions extension installed (stubbed)
let connectionInfo: IConnectionInfo = createTestCredentials();// create test connectionInfo
// no table used for connection info so prompt user to get connection info
// no connection node used for connection info so prompt user to get connection info
// promptForConnection is set first time for user
let promptForConnectionStub = sinon.stub(testUtils.vscodeMssqlIExtension.object, 'promptForConnection').withArgs(true).onFirstCall().resolves(connectionInfo);
// setup listDatabases request with connectionURI
testUtils.vscodeMssqlIExtension.setup(x => x.connect(connectionInfo)).returns(() => Promise.resolve('testConnectionURI'));
testUtils.vscodeMssqlIExtension.setup(x => x.listDatabases('testConnectionURI')).returns(() => Promise.resolve(['testDb']));
// select the testDB from list of databases based on connection info
quickPickStub.onSecondCall().resolves(('testDb') as any);
quickPickStub.onThirdCall().resolves(('testDb') as any);
// get tables from selected database
const params = { ownerUri: 'testConnectionURI', queryString: azureFunctionUtils.tablesQuery('testDb') };
testUtils.vscodeMssqlIExtension.setup(x => x.sendRequest(azureFunctionsContracts.SimpleExecuteRequest.type, params))
.returns(() => Promise.resolve({ rowCount: 1, columnInfo: [], rows: [[{ displayValue: '[schema].[testTable]' }]] }));
// select the option to manually enter table name
let manuallyEnterObjectName = constants.manuallyEnterObjectName(constants.enterObjectName);
quickPickStub.onThirdCall().resolves(manuallyEnterObjectName as any);
let manuallyEnterObjectName = constants.manuallyEnterObjectName(constants.enterTableName);
quickPickStub.onCall(3).resolves(manuallyEnterObjectName as any);
// cancel out of manually enter inputBox
sinon.stub(vscode.window, 'showInputBox').resolves(undefined);
// resolve promises to undefined to exit out of createFunction
quickPickStub.onCall(4).resolves(undefined);
promptForConnectionStub.onSecondCall().resolves(undefined);
should(connectionInfo.database).equal('my_db', 'ConnectionInfo database should not be changed');
should(connectionInfo.database).equal('my_db', 'Initial ConnectionInfo database should be my_db');
await azureFunctionService.createAzureFunction();
should(connectionInfo.database).equal('testDb', 'ConnectionInfo database should be user selected database');
@@ -308,8 +391,52 @@ describe('AzureFunctionsService', () => {
);
});
it('Should prompt select view when user cancels out of manually entering view', async function (): Promise<void> {
// select view for object type
quickPickStub = sinon.stub(vscode.window, 'showQuickPick').onFirstCall().resolves({ label: constants.input, type: ObjectType.View } as any);
// This test will have an azure function project already in the project and the azure functions extension installed (stubbed)
let connectionInfo: IConnectionInfo = createTestCredentials();// create test connectionInfo
// no connection node used for connection info so prompt user to get connection info
// promptForConnection is set first time for user
let promptForConnectionStub = sinon.stub(testUtils.vscodeMssqlIExtension.object, 'promptForConnection').withArgs(true).onFirstCall().resolves(connectionInfo);
// setup listDatabases request with connectionURI
testUtils.vscodeMssqlIExtension.setup(x => x.connect(connectionInfo)).returns(() => Promise.resolve('testConnectionURI'));
testUtils.vscodeMssqlIExtension.setup(x => x.listDatabases('testConnectionURI')).returns(() => Promise.resolve(['testDb']));
// select the testDB from list of databases based on connection info
quickPickStub.onSecondCall().resolves(('testDb') as any);
// get tables from selected database
const params = { ownerUri: 'testConnectionURI', queryString: azureFunctionUtils.viewsQuery('testDb') };
testUtils.vscodeMssqlIExtension.setup(x => x.sendRequest(azureFunctionsContracts.SimpleExecuteRequest.type, params))
.returns(() => Promise.resolve({ rowCount: 1, columnInfo: [], rows: [[{ displayValue: '[schema].[testView]' }]] }));
// select the option to manually enter table name
let manuallyEnterObjectName = constants.manuallyEnterObjectName(constants.enterViewName);
quickPickStub.onThirdCall().resolves(manuallyEnterObjectName as any);
// cancel out of manually enter inputBox
sinon.stub(vscode.window, 'showInputBox').resolves(undefined);
// resolve promises to undefined to exit out of createFunction
quickPickStub.onCall(3).resolves(undefined);
promptForConnectionStub.onSecondCall().resolves(undefined);
should(connectionInfo.database).equal('my_db', 'Initial ConnectionInfo database should be my_db');
await azureFunctionService.createAzureFunction();
should(connectionInfo.database).equal('testDb', 'ConnectionInfo database should be user selected database');
should(quickPickStub.getCall(3).args).containDeepOrdered([
[manuallyEnterObjectName, '[schema].[testView]'],
{
canPickMany: false,
title: constants.selectView,
ignoreFocusOut: true
}]
);
});
it('Should prompt for connection profile if connection throws connection error', async function (): Promise<void> {
// no table used for connection info so prompt user to get connection info
// select view for object type
quickPickStub = sinon.stub(vscode.window, 'showQuickPick').onFirstCall().resolves({ label: constants.input, type: ObjectType.View } as any);
// no connection node used for connection info so prompt user to get connection info
// promptForConnection is selected first time for user and then set undefined in order to exit out of the createFunction
let promptForConnectionStub = sinon.stub(testUtils.vscodeMssqlIExtension.object, 'promptForConnection').withArgs(true).throws('Error connecting to connection profile');
promptForConnectionStub.onSecondCall().resolves(undefined);