diff --git a/extensions/arc/src/common/utils.ts b/extensions/arc/src/common/utils.ts index a915321cf1..3478d133e4 100644 --- a/extensions/arc/src/common/utils.ts +++ b/extensions/arc/src/common/utils.ts @@ -91,7 +91,7 @@ export function getDatabaseStateDisplayText(state: string): string { return loc.restoring; case 'RECOVERING': return loc.recovering; - case 'RECOVERY PENDING ': + case 'RECOVERY PENDING': return loc.recoveryPending; case 'SUSPECT': return loc.suspect; diff --git a/extensions/arc/src/test/common/promise.test.ts b/extensions/arc/src/test/common/promise.test.ts new file mode 100644 index 0000000000..611c00e249 --- /dev/null +++ b/extensions/arc/src/test/common/promise.test.ts @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import 'mocha'; +import { Deferred } from '../../common/promise'; + +describe('Deferred', () => { + it('Then should be called upon resolution', function (done): void { + const deferred = new Deferred(); + deferred.then(() => { + done(); + }); + deferred.resolve(); + }); +}); diff --git a/extensions/arc/src/test/common/utils.test.ts b/extensions/arc/src/test/common/utils.test.ts index 0a5f873f67..9402a9a9ee 100644 --- a/extensions/arc/src/test/common/utils.test.ts +++ b/extensions/arc/src/test/common/utils.test.ts @@ -3,14 +3,16 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as vscode from 'vscode'; import * as should from 'should'; import 'mocha'; -import { resourceTypeToDisplayName, parseEndpoint, parseInstanceName } from '../../common/utils'; +import { resourceTypeToDisplayName, parseEndpoint, parseInstanceName, getAzurecoreApi, getResourceTypeIcon, getConnectionModeDisplayText, getDatabaseStateDisplayText, promptForResourceDeletion } from '../../common/utils'; import * as loc from '../../localizedConstants'; -import { ResourceType } from '../../constants'; +import { ResourceType, IconPathHelper, Connectionmode as ConnectionMode } from '../../constants'; +import { MockInputBox } from '../stubs'; -describe('resourceTypeToDisplayName Method Tests', () => { +describe('resourceTypeToDisplayName Method Tests', function(): void { it('Display Name should be correct for valid ResourceType', function (): void { should(resourceTypeToDisplayName(ResourceType.dataControllers)).equal(loc.dataControllersType); should(resourceTypeToDisplayName(ResourceType.postgresInstances)).equal(loc.pgSqlType); @@ -30,17 +32,17 @@ describe('resourceTypeToDisplayName Method Tests', () => { }); }); -describe('parseEndpoint Method Tests', () => { +describe('parseEndpoint Method Tests', function(): void { it('Should parse valid endpoint correctly', function (): void { - should(parseEndpoint('127.0.0.1:1337')).deepEqual({ ip: '127.0.0.1', port: '1337'}); + should(parseEndpoint('127.0.0.1:1337')).deepEqual({ ip: '127.0.0.1', port: '1337' }); }); it('Should parse empty endpoint correctly', function (): void { - should(parseEndpoint('')).deepEqual({ ip: '', port: ''}); + should(parseEndpoint('')).deepEqual({ ip: '', port: '' }); }); it('Should parse undefined endpoint correctly', function (): void { - should(parseEndpoint('')).deepEqual({ ip: '', port: ''}); + should(parseEndpoint('')).deepEqual({ ip: '', port: '' }); }); }); @@ -61,3 +63,102 @@ describe('parseInstanceName Method Tests', () => { should(parseInstanceName('')).equal(''); }); }); + +describe('getAzurecoreApi Method Tests', function() { + it('Should get azurecore API correctly', function (): void { + should(getAzurecoreApi()).not.be.undefined(); + }); +}); + +describe('getResourceTypeIcon Method Tests', function() { + it('Correct icons should be returned for valid ResourceTypes', function (): void { + should(getResourceTypeIcon(ResourceType.sqlManagedInstances)).equal(IconPathHelper.miaa, 'Unexpected MIAA icon'); + should(getResourceTypeIcon(ResourceType.postgresInstances)).equal(IconPathHelper.postgres, 'Unexpected Postgres icon'); + should(getResourceTypeIcon(ResourceType.dataControllers)).equal(IconPathHelper.controller, 'Unexpected controller icon'); + }); + it('Undefined should be returned for undefined resource types', function (): void { + should(getResourceTypeIcon(undefined)).be.undefined(); + }); + it('Undefined should be returned for empty resource types', function (): void { + should(getResourceTypeIcon('')).be.undefined(); + }); + it('Undefined should be returned for unknown resource types', function (): void { + should(getResourceTypeIcon('UnknownType')).be.undefined(); + }); +}); + +describe('getConnectionModeDisplayText Method Tests', function() { + it('Display Name should be correct for valid ResourceType', function (): void { + should(getConnectionModeDisplayText(ConnectionMode.connected)).equal(loc.connected); + should(getConnectionModeDisplayText(ConnectionMode.disconnected)).equal(loc.disconnected); + }); + + it('Display Name should be correct for unknown value', function (): void { + should(getConnectionModeDisplayText('UnknownMode')).equal('UnknownMode'); + }); + + it('Display Name should be correct for empty value', function (): void { + should(getConnectionModeDisplayText('')).equal(''); + }); + + it('Display Name should be correct for undefined value', function (): void { + should(getConnectionModeDisplayText(undefined)).equal(''); + }); +}); + +describe('getDatabaseStateDisplayText Method Tests', function() { + it('State should be correct for valid states', function (): void { + should(getDatabaseStateDisplayText('ONLINE')).equal(loc.online); + should(getDatabaseStateDisplayText('OFFLINE')).equal(loc.offline); + should(getDatabaseStateDisplayText('RESTORING')).equal(loc.restoring); + should(getDatabaseStateDisplayText('RECOVERING')).equal(loc.recovering); + should(getDatabaseStateDisplayText('RECOVERY PENDING')).equal(loc.recoveryPending); + should(getDatabaseStateDisplayText('SUSPECT')).equal(loc.suspect); + should(getDatabaseStateDisplayText('EMERGENCY')).equal(loc.emergecy); + }); + + it('State should stay the same for unknown value', function (): void { + should(getDatabaseStateDisplayText('UnknownState')).equal('UnknownState'); + }); + + it('State should stay the same for empty value', function (): void { + should(getDatabaseStateDisplayText('')).equal(''); + }); +}); + +describe('promptForResourceDeletion Method Tests', function (): void { + let mockInputBox: MockInputBox; + before(function (): void { + vscode.window.createInputBox = () => { + return mockInputBox; + }; + }); + + beforeEach(function (): void { + mockInputBox = new MockInputBox(); + }); + + it('Resolves as true when value entered is correct', function (done): void { + promptForResourceDeletion('mynamespace', 'myname').then((value: boolean) => { + value ? done() : done(new Error('Expected return value to be true')); + }); + mockInputBox.value = 'myname'; + mockInputBox.triggerAccept(); + }); + + it('Resolves as false when input box is closed early', function (done): void { + promptForResourceDeletion('mynamespace', 'myname').then((value: boolean) => { + !value ? done() : done(new Error('Expected return value to be false')); + }); + mockInputBox.hide(); + }); + + it('Validation message is set when value entered is incorrect', async function (): Promise { + promptForResourceDeletion('mynamespace', 'myname'); + mockInputBox.value = 'wrong value'; + await mockInputBox.triggerAccept(); + should(mockInputBox.validationMessage).not.be.equal('', 'Validation message should not be empty after incorrect value entered'); + mockInputBox.value = 'new value'; + should(mockInputBox.validationMessage).be.equal('', 'Validation message should be empty after new value entered'); + }); +}); diff --git a/extensions/arc/src/test/stubs.ts b/extensions/arc/src/test/stubs.ts new file mode 100644 index 0000000000..8fa717c16a --- /dev/null +++ b/extensions/arc/src/test/stubs.ts @@ -0,0 +1,61 @@ +/*--------------------------------------------------------------------------------------------- + * 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'; + +export class MockInputBox implements vscode.InputBox { + private _value: string = ''; + public get value(): string { + return this._value; + } + public set value(newValue: string) { + this._value = newValue; + if (this._onDidChangeValueCallback) { + this._onDidChangeValueCallback(this._value); + } + } + placeholder: string | undefined; + password: boolean = false; + private _onDidChangeValueCallback: ((e: string) => any) | undefined = undefined; + onDidChangeValue: vscode.Event = (listener) => { + this._onDidChangeValueCallback = listener; + return new vscode.Disposable(() => { }); + }; + private _onDidAcceptCallback: ((e: void) => any) | undefined = undefined; + public onDidAccept: vscode.Event = (listener) => { + this._onDidAcceptCallback = listener; + return new vscode.Disposable(() => { }); + }; + buttons: readonly vscode.QuickInputButton[] = []; + onDidTriggerButton: vscode.Event = (_) => { return new vscode.Disposable(() => { }); }; + prompt: string | undefined; + validationMessage: string | undefined; + title: string | undefined; + step: number | undefined; + totalSteps: number | undefined; + enabled: boolean = false; + busy: boolean = false; + ignoreFocusOut: boolean = false; + show(): void { } + + hide(): void { + if (this._onDidHideCallback) { + this._onDidHideCallback(); + } + } + private _onDidHideCallback: ((e: void) => any) | undefined = undefined; + onDidHide: vscode.Event = (listener) => { + this._onDidHideCallback = listener; + return new vscode.Disposable(() => { }); + }; + dispose(): void { } + + public async triggerAccept(): Promise { + if (this._onDidAcceptCallback) { + return await this._onDidAcceptCallback(); + } + return undefined; + } +} diff --git a/scripts/test-extensions-unit.bat b/scripts/test-extensions-unit.bat index 2b47da500b..24e9bc8fb4 100755 --- a/scripts/test-extensions-unit.bat +++ b/scripts/test-extensions-unit.bat @@ -19,6 +19,7 @@ if "%INTEGRATION_TEST_ELECTRON_PATH%"=="" ( :: Run from a build: need to compile all test extensions call yarn gulp compile-extension:admin-tool-ext-win call yarn gulp compile-extension:agent + call yarn gulp compile-extension:arc call yarn gulp compile-extension:azurecore call yarn gulp compile-extension:cms call yarn gulp compile-extension:dacpac