mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-14 01:25:37 -05:00
Add SQL Bindings Tests / Vbump (#19717)
* add further testing * vbump version * add successfully test * address comments
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
"name": "sql-bindings-vscode",
|
||||
"displayName": "%displayName%",
|
||||
"description": "%description%",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"publisher": "ms-mssql",
|
||||
"preview": true,
|
||||
"engines": {
|
||||
|
||||
@@ -36,7 +36,7 @@ export interface IFileFunctionObject {
|
||||
* @returns settings in local.settings.json. If no settings are found, returns default "empty" settings
|
||||
*/
|
||||
export async function getLocalSettingsJson(localSettingsPath: string): Promise<ILocalSettingsJson> {
|
||||
if (fs.existsSync(localSettingsPath)) {
|
||||
if (await utils.exists(localSettingsPath)) {
|
||||
const data: string = (fs.readFileSync(localSettingsPath)).toString();
|
||||
try {
|
||||
return JSON.parse(data);
|
||||
@@ -281,7 +281,7 @@ export async function getAFProjectContainingFile(fileUri: vscode.Uri): Promise<v
|
||||
// Use 'host.json' as an indicator that this is a functions project
|
||||
// copied from verifyIsproject.ts in vscode-azurefunctions extension
|
||||
export async function isFunctionProject(folderPath: string): Promise<boolean> {
|
||||
return fs.existsSync(path.join(folderPath, constants.hostFileName));
|
||||
return await utils.exists(path.join(folderPath, constants.hostFileName));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -359,7 +359,6 @@ export async function promptForObjectName(bindingType: BindingType, connectionIn
|
||||
*/
|
||||
export async function promptAndUpdateConnectionStringSetting(projectUri: vscode.Uri | undefined, connectionInfo?: IConnectionInfo): Promise<IConnectionStringInfo | undefined> {
|
||||
let connectionStringSettingName: string | undefined;
|
||||
const vscodeMssqlApi = await utils.getVscodeMssqlApi();
|
||||
|
||||
// show the settings from project's local.settings.json if there's an AF functions project
|
||||
if (projectUri) {
|
||||
@@ -494,6 +493,7 @@ export async function promptAndUpdateConnectionStringSetting(projectUri: vscode.
|
||||
}
|
||||
} else {
|
||||
// Let user choose from existing connections to create connection string from
|
||||
const vscodeMssqlApi = await utils.getVscodeMssqlApi();
|
||||
connectionInfo = await vscodeMssqlApi.promptForConnection(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +116,9 @@ export async function getUniqueFileName(fileName: string, folderPath?: string):
|
||||
let uniqueFileName = fileName;
|
||||
|
||||
while (count < maxCount) {
|
||||
if (!fs.existsSync(path.join(folderPath, uniqueFileName + '.cs'))) {
|
||||
// checks to see if file exists
|
||||
let uniqueFilePath = path.join(folderPath, uniqueFileName + '.cs');
|
||||
if (!(await exists(uniqueFilePath))) {
|
||||
return uniqueFileName;
|
||||
}
|
||||
count += 1;
|
||||
@@ -173,3 +175,12 @@ export function getErrorType(error: any): string | undefined {
|
||||
return 'UnknownError';
|
||||
}
|
||||
}
|
||||
|
||||
export async function exists(path: string): Promise<boolean> {
|
||||
try {
|
||||
await fs.promises.access(path);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,19 +2,19 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as vscode from 'vscode';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as should from 'should';
|
||||
import * as sinon from 'sinon';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as constants from '../common/constants';
|
||||
import * as vscode from 'vscode';
|
||||
import * as azureFunctionUtils from '../common/azureFunctionsUtils';
|
||||
import * as constants from '../common/constants';
|
||||
import * as utils from '../common/utils';
|
||||
|
||||
import { IConnectionInfo } from 'vscode-mssql';
|
||||
import { createAddConnectionStringStep } from '../createNewProject/addConnectionStringStep';
|
||||
import { createTestCredentials, createTestUtils, TestUtils } from './testUtils';
|
||||
import { IConnectionInfo } from 'vscode-mssql';
|
||||
|
||||
const rootFolderPath = 'test';
|
||||
const localSettingsPath: string = path.join(rootFolderPath, 'local.settings.json');
|
||||
|
||||
@@ -2,14 +2,17 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as should from 'should';
|
||||
import * as sinon from 'sinon';
|
||||
import * as constants from '../../common/constants';
|
||||
import * as vscode from 'vscode';
|
||||
import * as azureFunctionsUtils from '../../common/azureFunctionsUtils';
|
||||
import * as constants from '../../common/constants';
|
||||
import * as utils from '../../common/utils';
|
||||
import * as azureFunctionsContracts from '../../contracts/azureFunctions/azureFunctionsContracts';
|
||||
|
||||
import { BindingType } from 'sql-bindings';
|
||||
import { IConnectionInfo } from 'vscode-mssql';
|
||||
import { createTestCredentials, createTestUtils, TestUtils } from '../testUtils';
|
||||
|
||||
@@ -24,7 +27,7 @@ describe('AzureFunctionUtils', function (): void {
|
||||
|
||||
describe('Local.Settings.Json', function (): void {
|
||||
it('Should correctly parse local.settings.json', async () => {
|
||||
sinon.stub(fs, 'existsSync').withArgs(localSettingsPath).returns(true);
|
||||
sinon.stub(fs.promises, 'access').onFirstCall().resolves();
|
||||
sinon.stub(fs, 'readFileSync').withArgs(localSettingsPath).returns(
|
||||
`{"IsEncrypted": false,
|
||||
"Values": {"test1": "test1", "test2": "test2", "test3":"test3"}}`
|
||||
@@ -35,7 +38,7 @@ describe('AzureFunctionUtils', function (): void {
|
||||
});
|
||||
|
||||
it('setLocalAppSetting can update settings.json with new setting value', async () => {
|
||||
sinon.stub(fs, 'existsSync').withArgs(localSettingsPath).returns(true);
|
||||
sinon.stub(fs.promises, 'access').onFirstCall().resolves();
|
||||
sinon.stub(fs, 'readFileSync').withArgs(localSettingsPath).returns(
|
||||
`{"IsEncrypted": false,
|
||||
"Values": {"test1": "test1", "test2": "test2", "test3":"test3"}}`
|
||||
@@ -47,7 +50,7 @@ describe('AzureFunctionUtils', function (): void {
|
||||
});
|
||||
|
||||
it('Should not overwrite setting if value already exists in local.settings.json', async () => {
|
||||
sinon.stub(fs, 'existsSync').withArgs(localSettingsPath).returns(true);
|
||||
sinon.stub(fs.promises, 'access').onFirstCall().resolves();
|
||||
sinon.stub(fs, 'readFileSync').withArgs(localSettingsPath).returns(
|
||||
`{"IsEncrypted": false,
|
||||
"Values": {"test1": "test1", "test2": "test2", "test3":"test3"}}`
|
||||
@@ -67,7 +70,7 @@ describe('AzureFunctionUtils', function (): void {
|
||||
});
|
||||
|
||||
it('Should add connection string to local.settings.json', async () => {
|
||||
sinon.stub(fs, 'existsSync').withArgs(localSettingsPath).returns(true);
|
||||
sinon.stub(fs.promises, 'access').onFirstCall().resolves();
|
||||
sinon.stub(fs, 'readFileSync').withArgs(localSettingsPath).returns(
|
||||
`{"IsEncrypted": false,
|
||||
"Values": {"test1": "test1", "test2": "test2", "test3":"test3"}}`
|
||||
@@ -236,6 +239,123 @@ describe('AzureFunctionUtils', function (): void {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Get Azure Function Project', function (): void {
|
||||
it('Should return undefined if no azure function projects are found', async () => {
|
||||
// set workspace folder for testing
|
||||
sinon.replaceGetter(vscode.workspace, 'workspaceFolders', () => {
|
||||
return <vscode.WorkspaceFolder[]>[{
|
||||
uri: {
|
||||
fsPath: '/temp/'
|
||||
},
|
||||
}];
|
||||
});
|
||||
let findFilesStub = sinon.stub(vscode.workspace, 'findFiles');
|
||||
findFilesStub.onFirstCall().resolves([]);
|
||||
findFilesStub.onSecondCall().resolves(undefined);
|
||||
let result = await azureFunctionsUtils.getAzureFunctionProject();
|
||||
should(result).be.equal(undefined, 'Should be undefined since no azure function projects are found');
|
||||
});
|
||||
|
||||
it('Should return selectedProjectFile if only one azure function project is found', async () => {
|
||||
// set workspace folder for testing
|
||||
sinon.replaceGetter(vscode.workspace, 'workspaceFolders', () => {
|
||||
return <vscode.WorkspaceFolder[]>[{
|
||||
uri: {
|
||||
fsPath: '/temp/'
|
||||
},
|
||||
}];
|
||||
});
|
||||
// only one azure function project found - hostFiles and csproj files stubs
|
||||
let findFilesStub = sinon.stub(vscode.workspace, 'findFiles');
|
||||
findFilesStub.onFirstCall().resolves([vscode.Uri.file('/temp/host.json')]);
|
||||
findFilesStub.onSecondCall().returns(Promise.resolve([vscode.Uri.file('/temp/test.csproj')]) as any);
|
||||
|
||||
let result = await azureFunctionsUtils.getAzureFunctionProject();
|
||||
should(result).be.equal('/temp/test.csproj', 'Should return test.csproj since only one Azure function project is found');
|
||||
});
|
||||
|
||||
it('Should return prompt to choose azure function project if multiple azure function projects are found', async () => {
|
||||
// set workspace folder for testing
|
||||
sinon.replaceGetter(vscode.workspace, 'workspaceFolders', () => {
|
||||
return <vscode.WorkspaceFolder[]>[{
|
||||
uri: {
|
||||
fsPath: '/temp/'
|
||||
},
|
||||
}];
|
||||
});
|
||||
// multiple azure function projects found in workspace - hostFiles and project find files stubs
|
||||
let findFilesStub = sinon.stub(vscode.workspace, 'findFiles');
|
||||
findFilesStub.onFirstCall().returns(Promise.resolve([vscode.Uri.file('/temp/host.json'), vscode.Uri.file('/temp2/host.json')]) as any);
|
||||
// we loop through the hostFiles to find the csproj in same directory
|
||||
// first loop we use host of /temp/host.json
|
||||
findFilesStub.onSecondCall().returns(Promise.resolve([vscode.Uri.file('/temp/test.csproj')]) as any);
|
||||
// second loop we use host of /temp2/host.json
|
||||
findFilesStub.onThirdCall().returns(Promise.resolve([vscode.Uri.file('/temp2/test.csproj')]) as any);
|
||||
let quickPickStub = sinon.stub(vscode.window, 'showQuickPick').returns(Promise.resolve('/temp/test.csproj') as any);
|
||||
|
||||
let result = await azureFunctionsUtils.getAzureFunctionProject();
|
||||
should(result).be.equal('/temp/test.csproj', 'Should return test.csproj since user choose Azure function project');
|
||||
should(quickPickStub.calledOnce).be.true('showQuickPick should have been called to choose between azure function projects');
|
||||
});
|
||||
});
|
||||
|
||||
describe('PromptForObjectName', function (): void {
|
||||
it('Should prompt user to enter object name manually when no connection info given', async () => {
|
||||
let promptStub = sinon.stub(vscode.window, 'showInputBox').onFirstCall().resolves('test');
|
||||
|
||||
let result = await azureFunctionsUtils.promptForObjectName(BindingType.input);
|
||||
should(promptStub.calledOnce).be.true('showInputBox should have been called');
|
||||
should(result).be.equal('test', 'Should return test since user manually entered object name');
|
||||
});
|
||||
|
||||
it('Should return undefined when mssql connection error', async () => {
|
||||
sinon.stub(utils, 'getVscodeMssqlApi').resolves(testUtils.vscodeMssqlIExtension.object);
|
||||
let connectionInfo: IConnectionInfo = createTestCredentials();// Mocks promptForConnection
|
||||
let promptStub = sinon.stub(vscode.window, 'showInputBox');
|
||||
sinon.stub(azureFunctionsUtils, 'getConnectionURI').resolves(undefined);
|
||||
|
||||
let result = await azureFunctionsUtils.promptForObjectName(BindingType.input, connectionInfo);
|
||||
should(promptStub.notCalled).be.true('showInputBox should not have been called');
|
||||
should(result).be.equal(undefined, 'Should return undefined due to mssql connection error');
|
||||
});
|
||||
|
||||
it('Should return undefined if no database selected', async () => {
|
||||
sinon.stub(utils, 'getVscodeMssqlApi').resolves(testUtils.vscodeMssqlIExtension.object);
|
||||
let connectionInfo: IConnectionInfo = createTestCredentials();// Mocks promptForConnection
|
||||
let promptStub = sinon.stub(vscode.window, 'showInputBox');
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.connect(connectionInfo)).returns(() => Promise.resolve('testConnectionURI'));
|
||||
sinon.stub(vscode.window, 'showQuickPick').resolves(undefined);
|
||||
|
||||
let result = await azureFunctionsUtils.promptForObjectName(BindingType.input, connectionInfo);
|
||||
should(promptStub.notCalled).be.true('showInputBox should not have been called');
|
||||
should(result).be.equal(undefined, 'Should return undefined due to no database selected');
|
||||
});
|
||||
|
||||
it('Should successfully select object name', async () => {
|
||||
sinon.stub(utils, 'getVscodeMssqlApi').resolves(testUtils.vscodeMssqlIExtension.object);
|
||||
let connectionInfo: IConnectionInfo = createTestCredentials();// Mocks promptForConnection
|
||||
let promptStub = sinon.stub(vscode.window, 'showInputBox');
|
||||
// getConnectionURI stub
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.connect(connectionInfo)).returns(() => Promise.resolve('testConnectionURI'));
|
||||
// promptSelectDatabase stub
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.listDatabases('testConnectionURI')).returns(() => Promise.resolve(['testDb']));
|
||||
let quickPickStub = sinon.stub(vscode.window, 'showQuickPick').resolves('testDb' as any);
|
||||
// get tables from selected database
|
||||
const params = { ownerUri: 'testConnectionURI', queryString: azureFunctionsUtils.tablesQuery('testDb') };
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.sendRequest(azureFunctionsContracts.SimpleExecuteRequest.type, params))
|
||||
.returns(() => Promise.resolve({ rowCount: 1, columnInfo: [], rows: [['[schema].[testTable]']] }));
|
||||
// select the schema.testTable from list of tables based on connection info and database
|
||||
quickPickStub.onSecondCall().returns(Promise.resolve('[schema].[testTable]') as any);
|
||||
|
||||
let result = await azureFunctionsUtils.promptForObjectName(BindingType.input, connectionInfo);
|
||||
|
||||
should(promptStub.notCalled).be.true('showInputBox should not have been called');
|
||||
should(quickPickStub.calledTwice).be.true('showQuickPick should have been called twice');
|
||||
should(connectionInfo.database).be.equal('testDb', 'Should have connectionInfo.database to testDb after user selects database');
|
||||
should(result).be.equal('[schema].[testTable]', 'Should return [schema].[testTable] since user selected table');
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function (): void {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
56
extensions/sql-bindings/src/test/common/util.test.ts
Normal file
56
extensions/sql-bindings/src/test/common/util.test.ts
Normal 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.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as fs from 'fs';
|
||||
import * as should from 'should';
|
||||
import * as sinon from 'sinon';
|
||||
import * as constants from '../../common/constants';
|
||||
import { getErrorType, getUniqueFileName, TimeoutError, validateFunctionName } from '../../common/utils';
|
||||
|
||||
describe('Utils', function (): void {
|
||||
it('Should return undefined when no folderPath given to create unique file name', async () => {
|
||||
let testFile = 'testFile';
|
||||
let result = await getUniqueFileName(testFile);
|
||||
|
||||
should(result).be.equal(undefined, 'Should return undefined since no folderPath given');
|
||||
});
|
||||
|
||||
it('Should create unique file name if one exists', async () => {
|
||||
let testFile = 'testFile';
|
||||
let testFolder = 'testFolder';
|
||||
let fileAccessStub = sinon.stub(fs.promises, 'access').onFirstCall().resolves();
|
||||
fileAccessStub.onSecondCall().throws();
|
||||
|
||||
let result = await getUniqueFileName(testFile, testFolder);
|
||||
|
||||
should(result).be.equal('testFile1', 'Should return testFile1 since one testFile exists');
|
||||
});
|
||||
|
||||
it('Should create unique file name if multiple versions of the file exists', async () => {
|
||||
let testFile = 'testFile';
|
||||
let testFolder = 'testFolder';
|
||||
let fileAccessStub = sinon.stub(fs.promises, 'access').onFirstCall().resolves();
|
||||
fileAccessStub.onSecondCall().resolves();
|
||||
fileAccessStub.onThirdCall().throws();
|
||||
|
||||
let result = await getUniqueFileName(testFile, testFolder);
|
||||
|
||||
should(result).be.equal('testFile2', 'Should return testFile2 since both testFile1 and testFile exists');
|
||||
});
|
||||
|
||||
it('Should validate function name', async () => {
|
||||
should(validateFunctionName('')).be.equal(constants.nameMustNotBeEmpty);
|
||||
should(validateFunctionName('@$%@%@%')).be.equal(constants.hasSpecialCharacters);
|
||||
should(validateFunctionName('test')).be.equal(undefined);
|
||||
});
|
||||
|
||||
it('Should get error type', async () => {
|
||||
should(getErrorType(new Error('test'))).be.equal('UnknownError');
|
||||
should(getErrorType(new TimeoutError('test'))).be.equal('TimeoutError');
|
||||
});
|
||||
|
||||
afterEach(function (): void {
|
||||
sinon.restore();
|
||||
});
|
||||
});
|
||||
@@ -3,21 +3,21 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as should from 'should';
|
||||
import * as sinon from 'sinon';
|
||||
import * as vscode from 'vscode';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as fs from 'fs';
|
||||
import * as utils from '../../common/utils';
|
||||
import * as constants from '../../common/constants';
|
||||
import * as vscode from 'vscode';
|
||||
import * as azureFunctionUtils from '../../common/azureFunctionsUtils';
|
||||
import * as azureFunctionService from '../../services/azureFunctionsService';
|
||||
import * as constants from '../../common/constants';
|
||||
import * as utils from '../../common/utils';
|
||||
import * as azureFunctionsContracts from '../../contracts/azureFunctions/azureFunctionsContracts';
|
||||
import * as azureFunctionService from '../../services/azureFunctionsService';
|
||||
|
||||
import { createTestUtils, TestUtils, createTestCredentials } from '../testUtils';
|
||||
import { launchAddSqlBindingQuickpick } from '../../dialogs/addSqlBindingQuickpick';
|
||||
import { BindingType } from 'sql-bindings';
|
||||
import { IConnectionInfo } from 'vscode-mssql';
|
||||
import { launchAddSqlBindingQuickpick } from '../../dialogs/addSqlBindingQuickpick';
|
||||
import { createTestCredentials, createTestUtils, TestUtils } from '../testUtils';
|
||||
|
||||
let testUtils: TestUtils;
|
||||
const fileUri = vscode.Uri.file('testUri');
|
||||
@@ -30,30 +30,13 @@ describe('Add SQL Binding quick pick', () => {
|
||||
sinon.restore();
|
||||
});
|
||||
|
||||
it('Should show error if the file contains no Azure Functions', async function (): Promise<void> {
|
||||
sinon.stub(utils, 'getVscodeMssqlApi').resolves(testUtils.vscodeMssqlIExtension.object);
|
||||
sinon.stub(azureFunctionService, 'getAzureFunctions').withArgs(fileUri.fsPath).returns(
|
||||
Promise.resolve({
|
||||
success: true,
|
||||
errorMessage: '',
|
||||
azureFunctions: []
|
||||
}));
|
||||
const spy = sinon.spy(vscode.window, 'showErrorMessage');
|
||||
|
||||
await launchAddSqlBindingQuickpick(fileUri);
|
||||
|
||||
const msg = constants.noAzureFunctionsInFile;
|
||||
should(spy.calledOnce).be.true('showErrorMessage should have been called exactly once');
|
||||
should(spy.calledWith(msg)).be.true(`showErrorMessage not called with expected message '${msg}' Actual '${spy.getCall(0).args[0]}'`);
|
||||
});
|
||||
|
||||
it('Should show error if adding SQL binding was not successful', async function (): Promise<void> {
|
||||
it('Should successfully add SQL binding', async function (): Promise<void> {
|
||||
sinon.stub(utils, 'getVscodeMssqlApi').resolves(testUtils.vscodeMssqlIExtension.object);
|
||||
let connectionCreds: IConnectionInfo = createTestCredentials();// Mocks promptForConnection
|
||||
let connectionDetails = { options: connectionCreds };
|
||||
// set test vscode-mssql API calls
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.promptForConnection(true)).returns(() => Promise.resolve(connectionCreds));
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.getConnectionString(connectionDetails, true, false)).returns(() => Promise.resolve('testConnectionString'));
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.getConnectionString(connectionDetails, true, false)).returns(() => Promise.resolve('testConnectionString1'));
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.connect(connectionCreds)).returns(() => Promise.resolve('testConnectionURI'));
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.listDatabases('testConnectionURI')).returns(() => Promise.resolve(['testDb']));
|
||||
const params = { ownerUri: 'testConnectionURI', queryString: azureFunctionUtils.tablesQuery('testDb') };
|
||||
@@ -66,17 +49,15 @@ describe('Add SQL Binding quick pick', () => {
|
||||
errorMessage: '',
|
||||
azureFunctions: ['af1', 'af2']
|
||||
}));
|
||||
//failure since no AFs are found in the project
|
||||
|
||||
const errormsg = 'Error inserting binding';
|
||||
sinon.stub(azureFunctionService, 'addSqlBinding').withArgs(
|
||||
sinon.match.any, sinon.match.any, sinon.match.any,
|
||||
sinon.match.any, sinon.match.any).returns(
|
||||
Promise.resolve({
|
||||
success: false,
|
||||
errorMessage: errormsg
|
||||
success: true,
|
||||
errorMessage: ''
|
||||
}));
|
||||
const spy = sinon.spy(vscode.window, 'showErrorMessage');
|
||||
const showErrorMessageSpy = sinon.spy(vscode.window, 'showErrorMessage');
|
||||
|
||||
// select Azure function
|
||||
let quickpickStub = sinon.stub(vscode.window, 'showQuickPick').returns(Promise.resolve('af1') as any);
|
||||
@@ -91,18 +72,88 @@ describe('Add SQL Binding quick pick', () => {
|
||||
quickpickStub.onCall(4).returns(Promise.resolve(constants.yesString) as any);
|
||||
// setLocalAppSetting fails if we dont set writeFile stub
|
||||
sinon.stub(fs.promises, 'writeFile');
|
||||
sinon.stub(azureFunctionUtils, 'setLocalAppSetting').withArgs(sinon.match.any, 'sqlConnectionString', 'testConnectionString').returns(Promise.resolve(true));
|
||||
sinon.stub(azureFunctionUtils, 'setLocalAppSetting').withArgs(sinon.match.any, 'sqlConnectionString', 'testConnectionString1').returns(Promise.resolve(true));
|
||||
sinon.stub(utils, 'executeCommand').resolves('downloaded nuget package');
|
||||
quickpickStub.onCall(5).returns(Promise.resolve('testDb') as any);
|
||||
quickpickStub.onCall(6).returns(Promise.resolve('[schema].[testTable]') as any);
|
||||
|
||||
await launchAddSqlBindingQuickpick(vscode.Uri.file('testUri'));
|
||||
|
||||
should(spy.calledOnce).be.true('showErrorMessage should have been called exactly once');
|
||||
should(spy.calledWith(errormsg)).be.true(`showErrorMessage not called with expected message '${errormsg}' Actual '${spy.getCall(0).args[0]}'`);
|
||||
should(showErrorMessageSpy.notCalled).be.true('showErrorMessage should not be called');
|
||||
});
|
||||
|
||||
it('Should show error connection profile does not connect', async function (): Promise<void> {
|
||||
it('Should show error if adding SQL binding was not successful', async function (): Promise<void> {
|
||||
sinon.stub(utils, 'getVscodeMssqlApi').resolves(testUtils.vscodeMssqlIExtension.object);
|
||||
let connectionCreds: IConnectionInfo = createTestCredentials();// Mocks promptForConnection
|
||||
let connectionDetails = { options: connectionCreds };
|
||||
// set test vscode-mssql API calls
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.promptForConnection(true)).returns(() => Promise.resolve(connectionCreds));
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.getConnectionString(connectionDetails, true, false)).returns(() => Promise.resolve('testConnectionString2'));
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.connect(connectionCreds)).returns(() => Promise.resolve('testConnectionURI'));
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.listDatabases('testConnectionURI')).returns(() => Promise.resolve(['testDb']));
|
||||
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: [['[schema].[testTable]']] }));
|
||||
|
||||
sinon.stub(azureFunctionService, 'getAzureFunctions').withArgs(fileUri.fsPath).returns(
|
||||
Promise.resolve({
|
||||
success: true,
|
||||
errorMessage: '',
|
||||
azureFunctions: ['af1', 'af2']
|
||||
}));
|
||||
//failure since no AFs are found in the project
|
||||
const errormsg = 'Error inserting binding';
|
||||
sinon.stub(azureFunctionService, 'addSqlBinding').withArgs(
|
||||
sinon.match.any, sinon.match.any, sinon.match.any,
|
||||
sinon.match.any, sinon.match.any).returns(
|
||||
Promise.resolve({
|
||||
success: false,
|
||||
errorMessage: errormsg
|
||||
}));
|
||||
const showErrorMessageSpy = sinon.spy(vscode.window, 'showErrorMessage');
|
||||
|
||||
// select Azure function
|
||||
let quickpickStub = sinon.stub(vscode.window, 'showQuickPick').returns(Promise.resolve('af1') as any);
|
||||
// select input or output binding
|
||||
quickpickStub.onSecondCall().resolves(<any>{ label: constants.input, type: BindingType.input });
|
||||
sinon.stub(azureFunctionUtils, 'getAFProjectContainingFile').resolves(vscode.Uri.file('testUri'));
|
||||
// select connection profile - create new
|
||||
quickpickStub.onThirdCall().resolves(<any>{ label: constants.createNewLocalAppSettingWithIcon });
|
||||
// give connection string setting name
|
||||
sinon.stub(vscode.window, 'showInputBox').onFirstCall().resolves('sqlConnectionString');
|
||||
quickpickStub.onCall(3).returns(Promise.resolve(constants.connectionProfile) as any);
|
||||
quickpickStub.onCall(4).returns(Promise.resolve(constants.yesString) as any);
|
||||
// setLocalAppSetting fails if we dont set writeFile stub
|
||||
sinon.stub(fs.promises, 'writeFile');
|
||||
sinon.stub(azureFunctionUtils, 'setLocalAppSetting').withArgs(sinon.match.any, 'sqlConnectionString', 'testConnectionString2').returns(Promise.resolve(true));
|
||||
sinon.stub(utils, 'executeCommand').resolves('downloaded nuget package');
|
||||
quickpickStub.onCall(5).returns(Promise.resolve('testDb') as any);
|
||||
quickpickStub.onCall(6).returns(Promise.resolve('[schema].[testTable]') as any);
|
||||
|
||||
await launchAddSqlBindingQuickpick(vscode.Uri.file('testUri'));
|
||||
|
||||
should(showErrorMessageSpy.calledOnce).be.true('showErrorMessage should have been called exactly once');
|
||||
should(showErrorMessageSpy.calledWith(errormsg)).be.true(`showErrorMessage not called with expected message '${errormsg}' Actual '${showErrorMessageSpy.getCall(0).args[0]}'`);
|
||||
});
|
||||
|
||||
it('Should show error if the file contains no Azure Functions', async function (): Promise<void> {
|
||||
sinon.stub(utils, 'getVscodeMssqlApi').resolves(testUtils.vscodeMssqlIExtension.object);
|
||||
sinon.stub(azureFunctionService, 'getAzureFunctions').withArgs(fileUri.fsPath).returns(
|
||||
Promise.resolve({
|
||||
success: true,
|
||||
errorMessage: '',
|
||||
azureFunctions: []
|
||||
}));
|
||||
const showErrorMessageSpy = sinon.spy(vscode.window, 'showErrorMessage');
|
||||
|
||||
await launchAddSqlBindingQuickpick(fileUri);
|
||||
|
||||
const msg = constants.noAzureFunctionsInFile;
|
||||
should(showErrorMessageSpy.calledOnce).be.true('showErrorMessage should have been called exactly once');
|
||||
should(showErrorMessageSpy.calledWith(msg)).be.true(`showErrorMessage not called with expected message '${msg}' Actual '${showErrorMessageSpy.getCall(0).args[0]}'`);
|
||||
});
|
||||
|
||||
it('Should show error when connection profile does not connect', async function (): Promise<void> {
|
||||
sinon.stub(utils, 'getVscodeMssqlApi').resolves(testUtils.vscodeMssqlIExtension.object);
|
||||
let connectionCreds = createTestCredentials();
|
||||
|
||||
@@ -114,40 +165,116 @@ describe('Add SQL Binding quick pick', () => {
|
||||
azureFunctions: ['af1']
|
||||
}));
|
||||
|
||||
// Mocks connect call to mssql
|
||||
let error = new Error('Connection Request Failed');
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.connect(TypeMoq.It.isAny(), undefined)).throws(error);
|
||||
|
||||
// Mocks promptForConnection
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.promptForConnection(true)).returns(() => Promise.resolve(connectionCreds));
|
||||
let quickpickStub = sinon.stub(vscode.window, 'showQuickPick');
|
||||
// select Azure function
|
||||
quickpickStub.onFirstCall().resolves({ label: 'af1' });
|
||||
// select input or output binding
|
||||
quickpickStub.onSecondCall().resolves(<any>{ label: constants.input, type: BindingType.input });
|
||||
|
||||
// give object name
|
||||
let inputBoxStub = sinon.stub(vscode.window, 'showInputBox').onFirstCall().resolves('dbo.table1');
|
||||
|
||||
// select connection string setting name
|
||||
quickpickStub.onThirdCall().resolves({ label: constants.createNewLocalAppSettingWithIcon });
|
||||
|
||||
// give connection string setting name
|
||||
inputBoxStub.onSecondCall().resolves('SqlConnectionString');
|
||||
sinon.stub(vscode.window, 'showInputBox').onFirstCall().resolves('SqlConnectionString');
|
||||
|
||||
// select connection profile method
|
||||
quickpickStub.onCall(3).resolves({ label: constants.connectionProfile });
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.promptForConnection(true)).returns(() => Promise.resolve(connectionCreds));
|
||||
|
||||
// Mocks connect call to mssql
|
||||
let error = new Error('Connection Request Failed');
|
||||
testUtils.vscodeMssqlIExtension.setup(x => x.connect(TypeMoq.It.isAny(), undefined)).throws(error);
|
||||
|
||||
await launchAddSqlBindingQuickpick(vscode.Uri.file('testUri'));
|
||||
|
||||
// should go back to the select connection string methods
|
||||
should(quickpickStub.callCount === 4);
|
||||
should(quickpickStub.callCount).be.equal(5,'showQuickPick should have been called 5 times');
|
||||
should(quickpickStub.getCall(3).args).deepEqual([
|
||||
[constants.connectionProfile, constants.userConnectionString],
|
||||
{
|
||||
canPickMany: false,
|
||||
ignoreFocusOut: true,
|
||||
title: constants.selectConnectionString
|
||||
}]);
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
it('Should show user connection string setting method after cancelling out of connection string setting name', async function (): Promise<void> {
|
||||
sinon.stub(azureFunctionUtils, 'getAFProjectContainingFile').resolves(vscode.Uri.file('testUri'));
|
||||
sinon.stub(azureFunctionService, 'getAzureFunctions').withArgs(fileUri.fsPath).returns(
|
||||
Promise.resolve({
|
||||
success: true,
|
||||
errorMessage: '',
|
||||
azureFunctions: ['af1']
|
||||
}));
|
||||
|
||||
// Mocks promptForConnection
|
||||
let quickpickStub = sinon.stub(vscode.window, 'showQuickPick');
|
||||
// select Azure function
|
||||
quickpickStub.onFirstCall().resolves({ label: 'af1' });
|
||||
// select input or output binding
|
||||
quickpickStub.onSecondCall().resolves(<any>{ label: constants.input, type: BindingType.input });
|
||||
|
||||
// select connection string setting name
|
||||
quickpickStub.onThirdCall().resolves({ label: constants.createNewLocalAppSettingWithIcon });
|
||||
|
||||
// give connection string setting name
|
||||
sinon.stub(vscode.window, 'showInputBox').onFirstCall().resolves(undefined);
|
||||
|
||||
await launchAddSqlBindingQuickpick(vscode.Uri.file('testUri'));
|
||||
|
||||
// should go back to the select connection string methods
|
||||
should(quickpickStub.callCount).be.equal(4,'showQuickPick should have been called 4 times');
|
||||
should(quickpickStub.getCall(2).args).containDeepOrdered([
|
||||
[{ label: constants.createNewLocalAppSettingWithIcon }],
|
||||
{
|
||||
canPickMany: false,
|
||||
title: constants.selectSetting,
|
||||
ignoreFocusOut: true
|
||||
}]
|
||||
);
|
||||
});
|
||||
|
||||
it('Should show user connection string setting method after cancelling out of manually entering connection string', async function (): Promise<void> {
|
||||
sinon.stub(azureFunctionUtils, 'getAFProjectContainingFile').resolves(vscode.Uri.file('testUri'));
|
||||
sinon.stub(azureFunctionService, 'getAzureFunctions').withArgs(fileUri.fsPath).returns(
|
||||
Promise.resolve({
|
||||
success: true,
|
||||
errorMessage: '',
|
||||
azureFunctions: ['af1']
|
||||
}));
|
||||
|
||||
// Mocks promptForConnection
|
||||
let quickpickStub = sinon.stub(vscode.window, 'showQuickPick');
|
||||
// select Azure function
|
||||
quickpickStub.onFirstCall().resolves({ label: 'af1' });
|
||||
// select input or output binding
|
||||
quickpickStub.onSecondCall().resolves(<any>{ label: constants.input, type: BindingType.input });
|
||||
|
||||
// select connection string setting name
|
||||
quickpickStub.onThirdCall().resolves({ label: constants.createNewLocalAppSettingWithIcon });
|
||||
|
||||
// give connection string setting name
|
||||
let inputBox = sinon.stub(vscode.window, 'showInputBox').onFirstCall().resolves('SqlConnectionString');
|
||||
|
||||
// select enter connection string manually
|
||||
quickpickStub.onCall(3).resolves({ label: constants.enterConnectionString });
|
||||
|
||||
// user cancels prompt to enter connection string
|
||||
inputBox.onSecondCall().resolves(undefined);
|
||||
|
||||
await launchAddSqlBindingQuickpick(vscode.Uri.file('testUri'));
|
||||
|
||||
// should go back to the select connection string methods
|
||||
should(quickpickStub.callCount).be.equal(5,'showQuickPick should have been called 5 times');
|
||||
should(quickpickStub.getCall(4).args).containDeepOrdered([
|
||||
[constants.connectionProfile, constants.enterConnectionString],
|
||||
{
|
||||
canPickMany: false,
|
||||
title: constants.selectConnectionString,
|
||||
ignoreFocusOut: true
|
||||
}]
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,21 +3,21 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as should from 'should';
|
||||
import * as sinon from 'sinon';
|
||||
import * as vscode from 'vscode';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as should from 'should';
|
||||
import * as sinon from 'sinon';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as utils from '../../common/utils';
|
||||
import * as constants from '../../common/constants';
|
||||
import * as vscode from 'vscode';
|
||||
import * as azureFunctionUtils from '../../common/azureFunctionsUtils';
|
||||
import * as constants from '../../common/constants';
|
||||
import * as utils from '../../common/utils';
|
||||
import * as azureFunctionsContracts from '../../contracts/azureFunctions/azureFunctionsContracts';
|
||||
import * as azureFunctionService from '../../services/azureFunctionsService';
|
||||
|
||||
import { createTestUtils, TestUtils, createTestCredentials, createTestTableNode } from '../testUtils';
|
||||
import { IConnectionInfo } from 'vscode-mssql';
|
||||
import { BindingType } from 'sql-bindings';
|
||||
import { IConnectionInfo } from 'vscode-mssql';
|
||||
import { createTestCredentials, createTestTableNode, createTestUtils, TestUtils } from '../testUtils';
|
||||
|
||||
const rootFolderPath = 'test';
|
||||
const projectFilePath: string = path.join(rootFolderPath, 'test.csproj');
|
||||
|
||||
Reference in New Issue
Block a user