From 1a84db089aa7cc62c30e2181843ff6459d3449e1 Mon Sep 17 00:00:00 2001 From: Charles Gagnon Date: Tue, 26 Jan 2021 10:52:35 -0800 Subject: [PATCH] Add more azdata tests (#14049) * Add more azdata tests * cleanup --- extensions/azdata/src/api.ts | 2 +- extensions/azdata/src/test/api.test.ts | 128 ++++++++++++++---- .../azdata/src/test/common/utils.test.ts | 11 +- 3 files changed, 115 insertions(+), 26 deletions(-) diff --git a/extensions/azdata/src/api.ts b/extensions/azdata/src/api.ts index 4ceb23d785..9f6408e9f9 100644 --- a/extensions/azdata/src/api.ts +++ b/extensions/azdata/src/api.ts @@ -12,7 +12,7 @@ import * as constants from './constants'; import * as loc from './localizedConstants'; import { AzdataToolService } from './services/azdataToolService'; -function throwIfNoAzdataOrEulaNotAccepted(azdata: IAzdataTool | undefined, eulaAccepted: boolean): asserts azdata { +export function throwIfNoAzdataOrEulaNotAccepted(azdata: IAzdataTool | undefined, eulaAccepted: boolean): asserts azdata { throwIfNoAzdata(azdata); if (!eulaAccepted) { Logger.log(loc.eulaNotAccepted); diff --git a/extensions/azdata/src/test/api.test.ts b/extensions/azdata/src/test/api.test.ts index f23da28ef8..2ad1e6f20a 100644 --- a/extensions/azdata/src/test/api.test.ts +++ b/extensions/azdata/src/test/api.test.ts @@ -3,46 +3,126 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as azdataExt from 'azdata-ext'; +import * as childProcess from '../common/childProcess'; import * as sinon from 'sinon'; +import * as should from 'should'; import * as vscode from 'vscode'; import * as TypeMoq from 'typemoq'; -import { getExtensionApi } from '../api'; +import { getExtensionApi, throwIfNoAzdataOrEulaNotAccepted } from '../api'; import { AzdataToolService } from '../services/azdataToolService'; import { assertRejected } from './testUtils'; +import { AzdataTool, IAzdataTool, AzdataDeployOption } from '../azdata'; describe('api', function (): void { afterEach(function (): void { sinon.restore(); }); + describe('throwIfNoAzdataOrEulaNotAccepted', function (): void { + it('throws when no azdata', function (): void { + should(() => throwIfNoAzdataOrEulaNotAccepted(undefined, false)).throw(); + }); + it('throws when EULA not accepted', function (): void { + should(() => throwIfNoAzdataOrEulaNotAccepted(TypeMoq.Mock.ofType().object, false)).throw(); + }); + it('passes with AzdataTool and EULA accepted', function (): void { + throwIfNoAzdataOrEulaNotAccepted(TypeMoq.Mock.ofType().object, true); + }); + }); describe('getExtensionApi', function (): void { - it('throws when no azdata', async function(): Promise { + it('throws when no azdata', async function (): Promise { const mementoMock = TypeMoq.Mock.ofType(); const azdataToolService = new AzdataToolService(); const api = getExtensionApi(mementoMock.object, azdataToolService, Promise.resolve(undefined)); await assertRejected(api.isEulaAccepted(), 'isEulaAccepted'); - - await assertRejected(api.azdata.getPath(), 'getPath'); - await assertRejected(api.azdata.getSemVersion(), 'getSemVersion'); - await assertRejected(api.azdata.login('', '', ''), 'login'); - await assertRejected(api.azdata.acquireSession('', '', ''), 'acquireSession'); - await assertRejected(api.azdata.version(), 'version'); - - await assertRejected(api.azdata.arc.dc.create('', '', '', '', '', ''), 'arc dc create'); - - await assertRejected(api.azdata.arc.dc.config.list(), 'arc dc config list'); - await assertRejected(api.azdata.arc.dc.config.show(), 'arc dc config show'); - - await assertRejected(api.azdata.arc.dc.endpoint.list(), 'arc dc endpoint list'); - - await assertRejected(api.azdata.arc.sql.mi.list(), 'arc sql mi list'); - await assertRejected(api.azdata.arc.sql.mi.delete(''), 'arc sql mi delete'); - await assertRejected(api.azdata.arc.sql.mi.show(''), 'arc sql mi show'); - - await assertRejected(api.azdata.arc.postgres.server.list(), 'arc sql postgres server list'); - await assertRejected(api.azdata.arc.postgres.server.delete(''), 'arc sql postgres server delete'); - await assertRejected(api.azdata.arc.postgres.server.show(''), 'arc sql postgres server show'); - await assertRejected(api.azdata.arc.postgres.server.edit('', { }), 'arc sql postgres server edit'); + await assertApiCalls(api, assertRejected); }); + + it('throws when EULA not accepted', async function (): Promise { + const mementoMock = TypeMoq.Mock.ofType(); + mementoMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => false); + const azdataToolService = new AzdataToolService(); + // Not using a mock here because it'll hang when resolving mocked objects + const api = getExtensionApi(mementoMock.object, azdataToolService, Promise.resolve(new AzdataTool('', '1.0.0'))); + should(await api.isEulaAccepted()).be.false('EULA should not be accepted'); + await assertApiCalls(api, assertRejected); + }); + + it('succeed when azdata present and EULA accepted', async function (): Promise { + const mementoMock = TypeMoq.Mock.ofType(); + mementoMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => true); + const azdataTool = new AzdataTool('', '1.0.0'); + const azdataToolService = new AzdataToolService(); + azdataToolService.localAzdata = azdataTool; + // Not using a mock here because it'll hang when resolving mocked objects + const api = getExtensionApi(mementoMock.object, azdataToolService, Promise.resolve(azdataTool)); + should(await api.isEulaAccepted()).be.true('EULA should be accepted'); + sinon.stub(childProcess, 'executeCommand').callsFake(async (_command, args) => { + // Version needs to be valid so it can be parsed correctly + if (args[0] === '--version') { + return { stdout: `1.0.0`, stderr: '' }; + } + console.log(args[0]); + return { stdout: `{ }`, stderr: '' }; + }); + await assertApiCalls(api, async (promise, message) => { + try { + await promise; + } catch (err) { + throw new Error(`API call to ${message} should have succeeded. ${err}`); + } + }); + }); + + it('promptForEula', async function (): Promise { + const mementoMock = TypeMoq.Mock.ofType(); + mementoMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => true); + const azdataToolService = new AzdataToolService(); + // Not using a mock here because it'll hang when resolving mocked objects + const api = getExtensionApi(mementoMock.object, azdataToolService, Promise.resolve(new AzdataTool('', '1.0.0'))); + const configMock = TypeMoq.Mock.ofType(); + configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => AzdataDeployOption.dontPrompt); + sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object); + const showErrorMessageStub = sinon.stub(vscode.window, 'showErrorMessage'); + should(await api.promptForEula()).be.false(); + should(showErrorMessageStub.called).be.true('User should have been prompted to accept'); + }); + + /** + * Asserts that calls to the Azdata API behave as expected + * @param api The API object to test the calls with + * @param assertCallback The function to assert that the results are as expected + */ + async function assertApiCalls(api: azdataExt.IExtension, assertCallback: (promise: Promise, message: string) => Promise): Promise { + await assertCallback(api.azdata.getPath(), 'getPath'); + await assertCallback(api.azdata.getSemVersion(), 'getSemVersion'); + await assertCallback(api.azdata.login('', '', ''), 'login'); + await assertCallback((async () => { + let session: azdataExt.AzdataSession | undefined; + try { + session = await api.azdata.acquireSession('', '', ''); + } finally { + session?.dispose(); + } + })(), 'acquireSession'); + await assertCallback(api.azdata.version(), 'version'); + + await assertCallback(api.azdata.arc.dc.create('', '', '', '', '', ''), 'arc dc create'); + + await assertCallback(api.azdata.arc.dc.config.list(), 'arc dc config list'); + await assertCallback(api.azdata.arc.dc.config.show(), 'arc dc config show'); + + await assertCallback(api.azdata.arc.dc.endpoint.list(), 'arc dc endpoint list'); + + await assertCallback(api.azdata.arc.sql.mi.list(), 'arc sql mi list'); + await assertCallback(api.azdata.arc.sql.mi.delete(''), 'arc sql mi delete'); + await assertCallback(api.azdata.arc.sql.mi.show(''), 'arc sql mi show'); + await assertCallback(api.azdata.arc.sql.mi.edit('', { }), 'arc sql mi edit'); + await assertCallback(api.azdata.arc.postgres.server.list(), 'arc sql postgres server list'); + await assertCallback(api.azdata.arc.postgres.server.delete(''), 'arc sql postgres server delete'); + await assertCallback(api.azdata.arc.postgres.server.show(''), 'arc sql postgres server show'); + await assertCallback(api.azdata.arc.postgres.server.edit('', {}), 'arc sql postgres server edit'); + } }); }); diff --git a/extensions/azdata/src/test/common/utils.test.ts b/extensions/azdata/src/test/common/utils.test.ts index a5078733d5..6bd4bc2481 100644 --- a/extensions/azdata/src/test/common/utils.test.ts +++ b/extensions/azdata/src/test/common/utils.test.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as should from 'should'; -import { searchForCmd as searchForExe } from '../../common/utils'; +import { NoAzdataError, searchForCmd as searchForExe } from '../../common/utils'; describe('utils', function () { describe('searchForExe', function (): void { @@ -14,4 +14,13 @@ describe('utils', function () { await should(searchForExe('someFakeExe')).be.rejected(); }); }); + + describe('NoAzdataError', function (): void { + it('error contains message with and without links', function (): void { + const error = new NoAzdataError(); + should(error.message).not.be.empty(); + should(error.messageWithLink).not.be.empty(); + should(error.message).not.equal(error.messageWithLink, 'Messages should not be equal'); + }); + }); });