mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
@@ -17,7 +17,7 @@ import { getErrorMessage, NoAzdataError, searchForCmd } from './common/utils';
|
||||
import { azdataAcceptEulaKey, azdataConfigSection, azdataFound, azdataInstallKey, azdataUpdateKey, debugConfigKey, eulaAccepted, eulaUrl, microsoftPrivacyStatementUrl } from './constants';
|
||||
import * as loc from './localizedConstants';
|
||||
|
||||
const enum AzdataDeployOption {
|
||||
export const enum AzdataDeployOption {
|
||||
dontPrompt = 'dontPrompt',
|
||||
prompt = 'prompt'
|
||||
}
|
||||
|
||||
47
extensions/azdata/src/test/api.test.ts
Normal file
47
extensions/azdata/src/test/api.test.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as sinon from 'sinon';
|
||||
import * as vscode from 'vscode';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import { getExtensionApi } from '../api';
|
||||
import { AzdataToolService } from '../services/azdataToolService';
|
||||
import { assertRejected } from './testUtils';
|
||||
|
||||
describe('api', function (): void {
|
||||
afterEach(function (): void {
|
||||
sinon.restore();
|
||||
});
|
||||
describe('getExtensionApi', function (): void {
|
||||
it('throws when no azdata', async function(): Promise<void> {
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
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.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');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -14,8 +14,11 @@ import * as loc from '../localizedConstants';
|
||||
import * as os from 'os';
|
||||
import * as fs from 'fs';
|
||||
import { AzdataReleaseInfo } from '../azdataReleaseInfo';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import { eulaAccepted } from '../constants';
|
||||
|
||||
const oldAzdataMock = new azdata.AzdataTool('/path/to/azdata', '0.0.0');
|
||||
const currentAzdataMock = new azdata.AzdataTool('/path/to/azdata', '9999.999.999');
|
||||
|
||||
/**
|
||||
* This matches the schema of the JSON file used to determine the current version of
|
||||
@@ -131,6 +134,24 @@ describe('azdata', function () {
|
||||
'--replace-engine-settings',
|
||||
args.workers.toString()]);
|
||||
});
|
||||
it('edit no optional args', async function (): Promise<void> {
|
||||
await azdataTool.arc.postgres.server.edit(name, {});
|
||||
verifyExecuteCommandCalledWithArgs([
|
||||
'arc', 'postgres', 'server', 'edit',
|
||||
name]);
|
||||
verifyExecuteCommandCalledWithoutArgs([
|
||||
'--admin-password',
|
||||
'--cores-limit',
|
||||
'--cores-request',
|
||||
'--engine-settings',
|
||||
'--extensions',
|
||||
'--memory-limit',
|
||||
'--memory-request',
|
||||
'--no-wait',
|
||||
'--port',
|
||||
'--replace-engine-settings',
|
||||
'--workers']);
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('sql', function (): void {
|
||||
@@ -207,10 +228,23 @@ describe('azdata', function () {
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Verifies that the specified args were included in the call to executeCommand
|
||||
* @param args The args to check were included in the execute command call
|
||||
*/
|
||||
function verifyExecuteCommandCalledWithArgs(args: string[]): void {
|
||||
const commandArgs = executeCommandStub.args[0][1] as string[];
|
||||
args.forEach(arg => should(commandArgs).containEql(arg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that the specified args weren't included in the call to executeCommand
|
||||
* @param args The args to check weren't included in the execute command call
|
||||
*/
|
||||
function verifyExecuteCommandCalledWithoutArgs(args: string[]): void {
|
||||
const commandArgs = executeCommandStub.args[0][1] as string[];
|
||||
args.forEach(arg => should(commandArgs).not.containEql(arg));
|
||||
}
|
||||
});
|
||||
|
||||
describe('findAzdata', function (): void {
|
||||
@@ -235,8 +269,9 @@ describe('azdata', function () {
|
||||
|
||||
describe('installAzdata', function (): void {
|
||||
|
||||
let errorMessageStub: sinon.SinonStub;
|
||||
beforeEach(function (): void {
|
||||
sinon.stub(vscode.window, 'showErrorMessage').returns(Promise.resolve(<any>loc.yes));
|
||||
errorMessageStub = sinon.stub(vscode.window, 'showErrorMessage').returns(Promise.resolve(<any>loc.yes));
|
||||
sinon.stub(utils, 'searchForCmd').returns(Promise.resolve('/path/to/azdata'));
|
||||
executeSudoCommandStub = sinon.stub(childProcess, 'executeSudoCommand').returns(Promise.resolve({ stdout: '', stderr: '' }));
|
||||
});
|
||||
@@ -255,6 +290,42 @@ describe('azdata', function () {
|
||||
}
|
||||
});
|
||||
|
||||
it('skipped install - dont prompt config', async function (): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => 'dontPrompt');
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await testWin32SkippedInstall();
|
||||
break;
|
||||
case 'darwin':
|
||||
await testDarwinSkippedInstall();
|
||||
break;
|
||||
case 'linux':
|
||||
await testLinuxSkippedInstall();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
it('skipped install - user chose not to prompt', async function (): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
errorMessageStub.resolves(<any>loc.doNotAskAgain);
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await testWin32SkippedInstall();
|
||||
break;
|
||||
case 'darwin':
|
||||
await testDarwinSkippedInstall();
|
||||
break;
|
||||
case 'linux':
|
||||
await testLinuxSkippedInstall();
|
||||
break;
|
||||
}
|
||||
configMock.verify(x => x.update(TypeMoq.It.isAny(), azdata.AzdataDeployOption.dontPrompt, TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
});
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
it('unsuccessful download - win32', async function (): Promise<void> {
|
||||
sinon.stub(HttpClient, 'downloadFile').rejects();
|
||||
@@ -283,8 +354,10 @@ describe('azdata', function () {
|
||||
});
|
||||
|
||||
describe('updateAzdata', function (): void {
|
||||
let showInformationMessageStub: sinon.SinonStub;
|
||||
|
||||
beforeEach(function (): void {
|
||||
sinon.stub(vscode.window, 'showInformationMessage').returns(Promise.resolve(<any>loc.yes));
|
||||
showInformationMessageStub = sinon.stub(vscode.window, 'showInformationMessage').returns(Promise.resolve(<any>loc.yes));
|
||||
executeSudoCommandStub = sinon.stub(childProcess, 'executeSudoCommand').returns(Promise.resolve({ stdout: '', stderr: '' }));
|
||||
});
|
||||
|
||||
@@ -302,6 +375,78 @@ describe('azdata', function () {
|
||||
}
|
||||
});
|
||||
|
||||
it('successful update - always prompt if user requested', async function (): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.dontPrompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await testWin32SuccessfulUpdate(true);
|
||||
break;
|
||||
case 'darwin':
|
||||
await testDarwinSuccessfulUpdate(true);
|
||||
break;
|
||||
case 'linux':
|
||||
await testLinuxSuccessfulUpdate(true);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
it('skipped update - config set not to prompt', async function (): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.dontPrompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await testWin32SkippedUpdateDontPrompt();
|
||||
break;
|
||||
case 'darwin':
|
||||
await testDarwinSkippedUpdateDontPrompt();
|
||||
break;
|
||||
case 'linux':
|
||||
await testLinuxSkippedUpdateDontPrompt();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
it('skipped update - user chose to never prompt again', async function (): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
showInformationMessageStub.resolves(<any>loc.doNotAskAgain);
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await testWin32SkippedUpdateDontPrompt();
|
||||
break;
|
||||
case 'darwin':
|
||||
await testDarwinSkippedUpdateDontPrompt();
|
||||
break;
|
||||
case 'linux':
|
||||
await testLinuxSkippedUpdateDontPrompt();
|
||||
break;
|
||||
}
|
||||
// Config should have been updated since user chose never to prompt again
|
||||
configMock.verify(x => x.update(TypeMoq.It.isAny(), azdata.AzdataDeployOption.dontPrompt, TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
});
|
||||
|
||||
it('skipped update - no new version', async function (): Promise<void> {
|
||||
switch (process.platform) {
|
||||
case 'win32':
|
||||
await testWin32SkippedUpdate();
|
||||
break;
|
||||
case 'darwin':
|
||||
await testDarwinSkippedUpdate();
|
||||
break;
|
||||
case 'linux':
|
||||
await testLinuxSkippedUpdate();
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
it('skipped update - no azdata', async function (): Promise<void> {
|
||||
const result = await azdata.checkAndUpdateAzdata();
|
||||
should(result).be.false();
|
||||
});
|
||||
|
||||
it('unsuccessful update', async function (): Promise<void> {
|
||||
switch (process.platform) {
|
||||
@@ -323,6 +468,81 @@ describe('azdata', function () {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('promptForEula', function(): void {
|
||||
it('skipped because of config', async function(): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.dontPrompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
const result = await azdata.promptForEula(mementoMock.object);
|
||||
should(result).be.false();
|
||||
});
|
||||
|
||||
it('always prompt if user requested', async function(): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.dontPrompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
const showInformationMessage = sinon.stub(vscode.window, 'showInformationMessage');
|
||||
const result = await azdata.promptForEula(mementoMock.object, true);
|
||||
should(result).be.false();
|
||||
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
||||
});
|
||||
|
||||
it('prompt if config set to do so', async function(): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
const showInformationMessage = sinon.stub(vscode.window, 'showInformationMessage');
|
||||
const result = await azdata.promptForEula(mementoMock.object);
|
||||
should(result).be.false();
|
||||
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
||||
});
|
||||
|
||||
it('update config if user chooses not to prompt', async function(): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
const showInformationMessage = sinon.stub(vscode.window, 'showInformationMessage').resolves(<any>loc.doNotAskAgain);
|
||||
const result = await azdata.promptForEula(mementoMock.object);
|
||||
configMock.verify(x => x.update(TypeMoq.It.isAny(), azdata.AzdataDeployOption.dontPrompt, TypeMoq.It.isAny()), TypeMoq.Times.once());
|
||||
should(result).be.false('EULA should not have been accepted');
|
||||
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
||||
});
|
||||
|
||||
it('user accepted EULA', async function(): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
const showInformationMessage = sinon.stub(vscode.window, 'showInformationMessage').resolves(<any>loc.accept);
|
||||
const result = await azdata.promptForEula(mementoMock.object);
|
||||
mementoMock.verify(x => x.update(eulaAccepted, true), TypeMoq.Times.once());
|
||||
should(result).be.true('EULA should have been accepted');
|
||||
should(showInformationMessage.calledOnce).be.true('showInformationMessage should have been called to prompt user');
|
||||
});
|
||||
|
||||
it('user accepted EULA - require user action', async function(): Promise<void> {
|
||||
const configMock = TypeMoq.Mock.ofType<vscode.WorkspaceConfiguration>();
|
||||
configMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => azdata.AzdataDeployOption.prompt);
|
||||
sinon.stub(vscode.workspace, 'getConfiguration').returns(configMock.object);
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
const showErrorMessage = sinon.stub(vscode.window, 'showErrorMessage').resolves(<any>loc.accept);
|
||||
const result = await azdata.promptForEula(mementoMock.object, true, true);
|
||||
mementoMock.verify(x => x.update(eulaAccepted, true), TypeMoq.Times.once());
|
||||
should(result).be.true('EULA should have been accepted');
|
||||
should(showErrorMessage.calledOnce).be.true('showErrorMessage should have been called to prompt user');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isEulaAccepted', function(): void {
|
||||
const mementoMock = TypeMoq.Mock.ofType<vscode.Memento>();
|
||||
mementoMock.setup(x => x.get(TypeMoq.It.isAny())).returns(() => true);
|
||||
should(azdata.isEulaAccepted(mementoMock.object)).be.true();
|
||||
});
|
||||
});
|
||||
|
||||
async function testLinuxUnsuccessfulUpdate() {
|
||||
@@ -371,16 +591,56 @@ async function testWin32UnsuccessfulUpdate() {
|
||||
should(executeSudoCommandStub.calledOnce).be.true();
|
||||
}
|
||||
|
||||
async function testLinuxSuccessfulUpdate() {
|
||||
async function testLinuxSuccessfulUpdate(userRequested = false) {
|
||||
sinon.stub(HttpClient, 'getTextContent').returns(Promise.resolve(JSON.stringify(releaseJson)));
|
||||
const executeCommandStub = sinon.stub(childProcess, 'executeCommand').returns(Promise.resolve({ stdout: '0.0.0', stderr: '' }));
|
||||
executeSudoCommandStub.resolves({ stdout: '0.0.0', stderr: '' });
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock);
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock, userRequested);
|
||||
should(executeSudoCommandStub.callCount).be.equal(6);
|
||||
should(executeCommandStub.calledOnce).be.true();
|
||||
}
|
||||
|
||||
async function testDarwinSuccessfulUpdate() {
|
||||
async function testDarwinSuccessfulUpdate(userRequested = false) {
|
||||
const brewInfoOutput = [{
|
||||
name: 'azdata-cli',
|
||||
full_name: 'microsoft/azdata-cli-release/azdata-cli',
|
||||
versions: {
|
||||
'stable': '9999.999.999',
|
||||
'devel': null,
|
||||
'head': null,
|
||||
'bottle': true
|
||||
}
|
||||
}];
|
||||
const executeCommandStub = sinon.stub(childProcess, 'executeCommand')
|
||||
.onThirdCall() //third call is brew info azdata-cli --json which needs to return json of new available azdata versions.
|
||||
.resolves({
|
||||
stderr: '',
|
||||
stdout: JSON.stringify(brewInfoOutput)
|
||||
})
|
||||
.resolves({ stdout: '0.0.0', stderr: '' });
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock, userRequested);
|
||||
should(executeCommandStub.callCount).be.equal(6);
|
||||
should(executeCommandStub.getCall(2).args[0]).be.equal('brew', '3rd call should have been to brew');
|
||||
should(executeCommandStub.getCall(2).args[1]).deepEqual(['info', 'azdata-cli', '--json'], '3rd call did not have expected arguments');
|
||||
}
|
||||
|
||||
|
||||
async function testWin32SuccessfulUpdate(userRequested = false) {
|
||||
sinon.stub(HttpClient, 'getTextContent').returns(Promise.resolve(JSON.stringify(releaseJson)));
|
||||
sinon.stub(HttpClient, 'downloadFile').returns(Promise.resolve(__filename));
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock, userRequested);
|
||||
should(executeSudoCommandStub.calledOnce).be.true('executeSudoCommand should have been called once');
|
||||
should(executeSudoCommandStub.getCall(0).args[0]).startWith('msiexec /qn /i');
|
||||
}
|
||||
|
||||
async function testLinuxSkippedUpdate() {
|
||||
sinon.stub(HttpClient, 'getTextContent').returns(Promise.resolve(JSON.stringify(releaseJson)));
|
||||
executeSudoCommandStub.resolves({ stdout: '0.0.0', stderr: '' });
|
||||
await azdata.checkAndUpdateAzdata(currentAzdataMock);
|
||||
should(executeSudoCommandStub.callCount).be.equal(0, 'executeSudoCommand was not expected to be called');
|
||||
}
|
||||
|
||||
async function testDarwinSkippedUpdateDontPrompt() {
|
||||
const brewInfoOutput = [{
|
||||
name: 'azdata-cli',
|
||||
full_name: 'microsoft/azdata-cli-release/azdata-cli',
|
||||
@@ -400,17 +660,92 @@ async function testDarwinSuccessfulUpdate() {
|
||||
.resolves({ stdout: '0.0.0', stderr: '' });
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock);
|
||||
should(executeCommandStub.callCount).be.equal(6);
|
||||
should(executeCommandStub.getCall(2).args[0]).be.equal('brew', '3rd call should have been to brew');
|
||||
should(executeCommandStub.getCall(2).args[1]).deepEqual(['info', 'azdata-cli', '--json'], '3rd call did not have expected arguments');
|
||||
should(executeCommandStub.notCalledWith(sinon.match.any, sinon.match.array.contains(['upgrade', 'azdata-cli'])));
|
||||
}
|
||||
|
||||
|
||||
async function testWin32SuccessfulUpdate() {
|
||||
async function testWin32SkippedUpdateDontPrompt() {
|
||||
sinon.stub(HttpClient, 'getTextContent').returns(Promise.resolve(JSON.stringify(releaseJson)));
|
||||
sinon.stub(HttpClient, 'downloadFile').returns(Promise.resolve(__filename));
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock);
|
||||
should(executeSudoCommandStub.calledOnce).be.true('executeSudoCommand should have been called once');
|
||||
should(executeSudoCommandStub.getCall(0).args[0]).startWith('msiexec /qn /i');
|
||||
should(executeSudoCommandStub.notCalled).be.true('executeSudoCommand should not have been called');
|
||||
}
|
||||
|
||||
async function testLinuxSkippedUpdateDontPrompt() {
|
||||
sinon.stub(HttpClient, 'getTextContent').returns(Promise.resolve(JSON.stringify(releaseJson)));
|
||||
sinon.stub(childProcess, 'executeCommand').returns(Promise.resolve({ stdout: '0.0.0', stderr: '' }));
|
||||
executeSudoCommandStub.resolves({ stdout: '0.0.0', stderr: '' });
|
||||
await azdata.checkAndUpdateAzdata(oldAzdataMock);
|
||||
should(executeSudoCommandStub.callCount).be.equal(0, 'executeSudoCommand was not expected to be called');
|
||||
}
|
||||
|
||||
async function testDarwinSkippedUpdate() {
|
||||
const brewInfoOutput = [{
|
||||
name: 'azdata-cli',
|
||||
full_name: 'microsoft/azdata-cli-release/azdata-cli',
|
||||
versions: {
|
||||
'stable': '9999.999.999',
|
||||
'devel': null,
|
||||
'head': null,
|
||||
'bottle': true
|
||||
}
|
||||
}];
|
||||
const executeCommandStub = sinon.stub(childProcess, 'executeCommand')
|
||||
.onThirdCall() //third call is brew info azdata-cli --json which needs to return json of new available azdata versions.
|
||||
.resolves({
|
||||
stderr: '',
|
||||
stdout: JSON.stringify(brewInfoOutput)
|
||||
})
|
||||
.resolves({ stdout: '0.0.0', stderr: '' });
|
||||
await azdata.checkAndUpdateAzdata(currentAzdataMock);
|
||||
should(executeCommandStub.callCount).be.equal(6);
|
||||
should(executeCommandStub.notCalledWith(sinon.match.any, sinon.match.array.contains(['upgrade', 'azdata-cli'])));
|
||||
}
|
||||
|
||||
async function testWin32SkippedUpdate() {
|
||||
sinon.stub(HttpClient, 'getTextContent').returns(Promise.resolve(JSON.stringify(releaseJson)));
|
||||
sinon.stub(HttpClient, 'downloadFile').returns(Promise.resolve(__filename));
|
||||
await azdata.checkAndUpdateAzdata(currentAzdataMock);
|
||||
should(executeSudoCommandStub.notCalled).be.true('executeSudoCommand should not have been called');
|
||||
}
|
||||
|
||||
async function testDarwinSkippedInstall() {
|
||||
const executeCommandStub = sinon.stub(childProcess, 'executeCommand')
|
||||
.onFirstCall()
|
||||
.callsFake(async (_command: string, _args: string[]) => {
|
||||
return Promise.reject(new Error('not Found'));
|
||||
})
|
||||
.callsFake(async (_command: string, _args: string[]) => {
|
||||
return Promise.resolve({ stdout: '0.0.0', stderr: '' });
|
||||
});
|
||||
const result = await azdata.checkAndInstallAzdata();
|
||||
should(result).equal(undefined, 'result should be undefined');
|
||||
should(executeCommandStub.callCount).be.equal(0);
|
||||
}
|
||||
|
||||
async function testLinuxSkippedInstall() {
|
||||
sinon.stub(childProcess, 'executeCommand')
|
||||
.onFirstCall()
|
||||
.rejects(new Error('not Found'))
|
||||
.resolves({ stdout: '0.0.0', stderr: '' });
|
||||
executeSudoCommandStub
|
||||
.resolves({ stdout: 'success', stderr: '' });
|
||||
const result = await azdata.checkAndInstallAzdata();
|
||||
should(result).equal(undefined, 'result should be undefined');
|
||||
should(executeSudoCommandStub.callCount).be.equal(0);
|
||||
}
|
||||
|
||||
async function testWin32SkippedInstall() {
|
||||
sinon.stub(HttpClient, 'getTextContent').returns(Promise.resolve(JSON.stringify(releaseJson)));
|
||||
sinon.stub(HttpClient, 'downloadFile').returns(Promise.resolve(__filename));
|
||||
sinon.stub(childProcess, 'executeCommand')
|
||||
.onFirstCall()
|
||||
.rejects(new Error('not Found')) // First call mock the tool not being found
|
||||
.resolves({ stdout: '1.0.0', stderr: '' });
|
||||
executeSudoCommandStub
|
||||
.returns({ stdout: '', stderr: '' });
|
||||
const result = await azdata.checkAndInstallAzdata();
|
||||
should(result).equal(undefined, 'result should be undefined');
|
||||
should(executeSudoCommandStub.notCalled).be.true('executeSudoCommand should not have been called');
|
||||
}
|
||||
|
||||
async function testWin32SuccessfulInstall() {
|
||||
|
||||
20
extensions/azdata/src/test/testUtils.ts
Normal file
20
extensions/azdata/src/test/testUtils.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* Asserts that the specified promise was rejected. This is similar to should(..).be.rejected but
|
||||
* allows specifying a message in the thrown Error to add more information to the failure.
|
||||
* @param promise The promise to verify was rejected
|
||||
* @param message The message to include in the error if the promise isn't rejected
|
||||
*/
|
||||
export async function assertRejected(promise: Promise<any>, message: string): Promise<void> {
|
||||
try {
|
||||
await promise;
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user