Port the Azure Resource Explorer extension to core. (#2701)

* Port the Azure Resource Explorer extension to core.

This will enable Azure viewlet by default in the next release.

- Moving this code from the SQL Server 2019 extension to Azure Data Studio core
- Ported tests and verified they work in the integration tests.sh file
- Fixed an issue that caused integration tests to fail if you have a SQL Server 2019 big data cluster endpoint listed, but the extension isn't installed.
This commit is contained in:
Kevin Cunnane
2018-10-03 10:41:07 -07:00
committed by GitHub
parent 3f84e8e652
commit a77bb50b9e
70 changed files with 3955 additions and 5 deletions

View File

@@ -0,0 +1,37 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as should from 'should';
import * as vscode from 'vscode';
import 'mocha';
import { AzureResourceItemType } from '../../../azureResource/constants';
import { AzureResourceAccountNotSignedInTreeNode } from '../../../azureResource/tree/accountNotSignedInTreeNode';
describe('AzureResourceAccountNotSignedInTreeNode.info', function(): void {
it('Should be correct.', async function(): Promise<void> {
const label = 'Sign in to Azure ...';
const treeNode = new AzureResourceAccountNotSignedInTreeNode();
should(treeNode.nodePathValue).equal('message_accountNotSignedIn');
const treeItem = await treeNode.getTreeItem();
should(treeItem.label).equal(label);
should(treeItem.contextValue).equal(AzureResourceItemType.message);
should(treeItem.collapsibleState).equal(vscode.TreeItemCollapsibleState.None);
should(treeItem.command).not.undefined();
should(treeItem.command.title).equal(label);
should(treeItem.command.command).equal('azureresource.signin');
const nodeInfo = treeNode.getNodeInfo();
should(nodeInfo.isLeaf).true();
should(nodeInfo.label).equal(label);
should(nodeInfo.nodeType).equal(AzureResourceItemType.message);
should(nodeInfo.iconType).equal(AzureResourceItemType.message);
});
});

View File

@@ -0,0 +1,294 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as should from 'should';
import * as TypeMoq from 'typemoq';
import * as sqlops from 'sqlops';
import * as vscode from 'vscode';
import 'mocha';
import { ServiceClientCredentials } from 'ms-rest';
import { AzureResourceServicePool } from '../../../azureResource/servicePool';
import {
IAzureResourceCacheService,
IAzureResourceContextService,
IAzureResourceCredentialService,
IAzureResourceSubscriptionService,
IAzureResourceSubscriptionFilterService
} from '../../../azureResource/interfaces';
import { IAzureResourceTreeChangeHandler } from '../../../azureResource/tree/treeChangeHandler';
import { AzureResourceAccountTreeNode } from '../../../azureResource/tree/accountTreeNode';
import { AzureResourceSubscription } from '../../../azureResource/models';
import { AzureResourceSubscriptionTreeNode } from '../../../azureResource/tree/subscriptionTreeNode';
import { AzureResourceItemType } from '../../../azureResource/constants';
import { AzureResourceMessageTreeNode } from '../../../azureResource/tree/messageTreeNode';
// Mock services
const mockServicePool = AzureResourceServicePool.getInstance();
let mockCacheService: TypeMoq.IMock<IAzureResourceCacheService>;
let mockContextService: TypeMoq.IMock<IAzureResourceContextService>;
let mockCredentialService: TypeMoq.IMock<IAzureResourceCredentialService>;
let mockSubscriptionService: TypeMoq.IMock<IAzureResourceSubscriptionService>;
let mockSubscriptionFilterService: TypeMoq.IMock<IAzureResourceSubscriptionFilterService>;
let mockTreeChangeHandler: TypeMoq.IMock<IAzureResourceTreeChangeHandler>;
// Mock test data
const mockAccount: sqlops.Account = {
key: {
accountId: 'mock_account',
providerId: 'mock_provider'
},
displayInfo: {
displayName: 'mock_account@test.com',
accountType: 'Microsoft',
contextualDisplayName: 'test'
},
properties: undefined,
isStale: false
};
const mockCredential = TypeMoq.Mock.ofType<ServiceClientCredentials>().object;
const mockCredentials = [mockCredential];
const mockSubscription1: AzureResourceSubscription = {
id: 'mock_subscription_1',
name: 'mock subscription 1'
};
const mockSubscription2: AzureResourceSubscription = {
id: 'mock_subscription_2',
name: 'mock subscription 2'
};
const mockSubscriptions = [mockSubscription1, mockSubscription2];
const mockFilteredSubscriptions = [mockSubscription1];
let mockSubscriptionCache: { subscriptions: { [accountId: string]: AzureResourceSubscription[]} };
describe('AzureResourceAccountTreeNode.info', function(): void {
beforeEach(() => {
mockContextService = TypeMoq.Mock.ofType<IAzureResourceContextService>();
mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>();
mockCredentialService = TypeMoq.Mock.ofType<IAzureResourceCredentialService>();
mockSubscriptionService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionService>();
mockSubscriptionFilterService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionFilterService>();
mockTreeChangeHandler = TypeMoq.Mock.ofType<IAzureResourceTreeChangeHandler>();
mockSubscriptionCache = { subscriptions: {} };
mockServicePool.contextService = mockContextService.object;
mockServicePool.cacheService = mockCacheService.object;
mockServicePool.credentialService = mockCredentialService.object;
mockServicePool.subscriptionService = mockSubscriptionService.object;
mockServicePool.subscriptionFilterService = mockSubscriptionFilterService.object;
mockCredentialService.setup((o) => o.getCredentials(mockAccount)).returns(() => Promise.resolve(mockCredentials));
mockCacheService.setup((o) => o.get(TypeMoq.It.isAnyString())).returns(() => mockSubscriptionCache);
mockCacheService.setup((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => mockSubscriptionCache.subscriptions[mockAccount.key.accountId] = mockSubscriptions);
});
it('Should be correct when created.', async function(): Promise<void> {
const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockTreeChangeHandler.object);
const accountTreeNodeId = `account_${mockAccount.key.accountId}`;
const accountTreeNodeLabel = `${mockAccount.displayInfo.displayName} (${mockAccount.key.accountId})`;
should(accountTreeNode.nodePathValue).equal(accountTreeNodeId);
const treeItem = await accountTreeNode.getTreeItem();
should(treeItem.id).equal(accountTreeNodeId);
should(treeItem.label).equal(accountTreeNodeLabel);
should(treeItem.contextValue).equal(AzureResourceItemType.account);
should(treeItem.collapsibleState).equal(vscode.TreeItemCollapsibleState.Collapsed);
const nodeInfo = accountTreeNode.getNodeInfo();
should(nodeInfo.label).equal(accountTreeNodeLabel);
should(nodeInfo.isLeaf).false();
should(nodeInfo.nodeType).equal(AzureResourceItemType.account);
should(nodeInfo.iconType).equal(AzureResourceItemType.account);
});
it('Should be correct when there are subscriptions listed.', async function(): Promise<void> {
mockSubscriptionService.setup((o) => o.getSubscriptions(mockAccount, mockCredentials)).returns(() => Promise.resolve(mockSubscriptions));
mockSubscriptionFilterService.setup((o) => o.getSelectedSubscriptions(mockAccount)).returns(() => Promise.resolve(undefined));
const accountTreeNodeLabel = `${mockAccount.displayInfo.displayName} (${mockAccount.key.accountId}) (${mockSubscriptions.length} / ${mockSubscriptions.length} subscriptions)`;
const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockTreeChangeHandler.object);
await accountTreeNode.getChildren();
const treeItem = await accountTreeNode.getTreeItem();
should(treeItem.label).equal(accountTreeNodeLabel);
const nodeInfo = accountTreeNode.getNodeInfo();
should(nodeInfo.label).equal(accountTreeNodeLabel);
});
it('Should be correct when there are subscriptions filtered.', async function(): Promise<void> {
mockSubscriptionService.setup((o) => o.getSubscriptions(mockAccount, mockCredentials)).returns(() => Promise.resolve(mockSubscriptions));
mockSubscriptionFilterService.setup((o) => o.getSelectedSubscriptions(mockAccount)).returns(() => Promise.resolve(mockFilteredSubscriptions));
const accountTreeNodeLabel = `${mockAccount.displayInfo.displayName} (${mockAccount.key.accountId}) (${mockFilteredSubscriptions.length} / ${mockSubscriptions.length} subscriptions)`;
const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockTreeChangeHandler.object);
await accountTreeNode.getChildren();
const treeItem = await accountTreeNode.getTreeItem();
should(treeItem.label).equal(accountTreeNodeLabel);
const nodeInfo = accountTreeNode.getNodeInfo();
should(nodeInfo.label).equal(accountTreeNodeLabel);
});
});
describe('AzureResourceAccountTreeNode.getChildren', function(): void {
beforeEach(() => {
mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>();
mockCredentialService = TypeMoq.Mock.ofType<IAzureResourceCredentialService>();
mockSubscriptionService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionService>();
mockSubscriptionFilterService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionFilterService>();
mockTreeChangeHandler = TypeMoq.Mock.ofType<IAzureResourceTreeChangeHandler>();
mockSubscriptionCache = { subscriptions: {} };
mockServicePool.cacheService = mockCacheService.object;
mockServicePool.credentialService = mockCredentialService.object;
mockServicePool.subscriptionService = mockSubscriptionService.object;
mockServicePool.subscriptionFilterService = mockSubscriptionFilterService.object;
mockCredentialService.setup((o) => o.getCredentials(mockAccount)).returns(() => Promise.resolve(mockCredentials));
mockCacheService.setup((o) => o.get(TypeMoq.It.isAnyString())).returns(() => mockSubscriptionCache);
mockCacheService.setup((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => mockSubscriptionCache.subscriptions[mockAccount.key.accountId] = mockSubscriptions);
});
it('Should load subscriptions from scratch and update cache when it is clearing cache.', async function(): Promise<void> {
mockSubscriptionService.setup((o) => o.getSubscriptions(mockAccount, mockCredentials)).returns(() => Promise.resolve(mockSubscriptions));
mockSubscriptionFilterService.setup((o) => o.getSelectedSubscriptions(mockAccount)).returns(() => Promise.resolve(undefined));
const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockTreeChangeHandler.object);
const children = await accountTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.once());
mockSubscriptionService.verify((o) => o.getSubscriptions(mockAccount, mockCredentials), TypeMoq.Times.once());
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.once());
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.once());
mockSubscriptionFilterService.verify((o) => o.getSelectedSubscriptions(mockAccount), TypeMoq.Times.once());
mockTreeChangeHandler.verify((o) => o.notifyNodeChanged(accountTreeNode), TypeMoq.Times.once());
should(accountTreeNode.totalSubscriptionCount).equal(mockSubscriptions.length);
should(accountTreeNode.selectedSubscriptionCount).equal(mockSubscriptions.length);
should(accountTreeNode.isClearingCache).false();
should(children).Array();
should(children.length).equal(mockSubscriptions.length);
should(Object.keys(mockSubscriptionCache.subscriptions)).deepEqual([mockAccount.key.accountId]);
should(mockSubscriptionCache.subscriptions[mockAccount.key.accountId]).deepEqual(mockSubscriptions);
for (let ix = 0; ix < mockSubscriptions.length; ix++) {
const child = children[ix];
const subscription = mockSubscriptions[ix];
should(child).instanceof(AzureResourceSubscriptionTreeNode);
should(child.nodePathValue).equal(`subscription_${subscription.id}`);
}
});
it('Should load subscriptions from cache when it is not clearing cache.', async function(): Promise<void> {
mockSubscriptionService.setup((o) => o.getSubscriptions(mockAccount, mockCredentials)).returns(() => Promise.resolve(mockSubscriptions));
mockSubscriptionFilterService.setup((o) => o.getSelectedSubscriptions(mockAccount)).returns(() => Promise.resolve(undefined));
const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockTreeChangeHandler.object);
await accountTreeNode.getChildren();
const children = await accountTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.exactly(1));
mockSubscriptionService.verify((o) => o.getSubscriptions(mockAccount, mockCredentials), TypeMoq.Times.exactly(1));
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.exactly(2));
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.exactly(1));
should(children.length).equal(mockSubscriptionCache.subscriptions[mockAccount.key.accountId].length);
for (let ix = 0; ix < mockSubscriptionCache.subscriptions[mockAccount.key.accountId].length; ix++) {
should(children[ix].nodePathValue).equal(`subscription_${mockSubscriptionCache.subscriptions[mockAccount.key.accountId][ix].id}`);
}
});
it('Should handle when there is no subscriptions.', async function(): Promise<void> {
mockSubscriptionService.setup((o) => o.getSubscriptions(mockAccount, mockCredentials)).returns(() => Promise.resolve(undefined));
const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockTreeChangeHandler.object);
const children = await accountTreeNode.getChildren();
should(accountTreeNode.totalSubscriptionCount).equal(0);
should(children).Array();
should(children.length).equal(1);
should(children[0]).instanceof(AzureResourceMessageTreeNode);
should(children[0].nodePathValue).startWith('message_');
should(children[0].getNodeInfo().label).equal('No Subscriptions found.');
});
it('Should honor subscription filtering.', async function(): Promise<void> {
mockSubscriptionService.setup((o) => o.getSubscriptions(mockAccount, mockCredentials)).returns(() => Promise.resolve(mockSubscriptions));
mockSubscriptionFilterService.setup((o) => o.getSelectedSubscriptions(mockAccount)).returns(() => Promise.resolve(mockFilteredSubscriptions));
const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockTreeChangeHandler.object);
const children = await accountTreeNode.getChildren();
mockSubscriptionFilterService.verify((o) => o.getSelectedSubscriptions(mockAccount), TypeMoq.Times.once());
should(accountTreeNode.selectedSubscriptionCount).equal(mockFilteredSubscriptions.length);
should(children.length).equal(mockFilteredSubscriptions.length);
for (let ix = 0; ix < mockFilteredSubscriptions.length; ix++) {
should(children[ix].nodePathValue).equal(`subscription_${mockFilteredSubscriptions[ix].id}`);
}
});
it('Should handle errors.', async function(): Promise<void> {
const mockError = 'Test error';
mockSubscriptionService.setup((o) => o.getSubscriptions(mockAccount, mockCredentials)).returns(() => { throw new Error(mockError); });
const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockTreeChangeHandler.object);
const children = await accountTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.once());
mockSubscriptionService.verify((o) => o.getSubscriptions(mockAccount, mockCredentials), TypeMoq.Times.once());
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.never());
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.never());
mockSubscriptionFilterService.verify((o) => o.getSelectedSubscriptions(mockAccount), TypeMoq.Times.never());
should(children).Array();
should(children.length).equal(1);
should(children[0]).instanceof(AzureResourceMessageTreeNode);
should(children[0].nodePathValue).startWith('message_');
should(children[0].getNodeInfo().label).equal(`Error: ${mockError}`);
});
});
describe('AzureResourceAccountTreeNode.clearCache', function() : void {
beforeEach(() => {
mockTreeChangeHandler = TypeMoq.Mock.ofType<IAzureResourceTreeChangeHandler>();
});
it('Should clear cache.', async function(): Promise<void> {
const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockTreeChangeHandler.object);
accountTreeNode.clearCache();
should(accountTreeNode.isClearingCache).true();
});
});

View File

@@ -0,0 +1,219 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as should from 'should';
import * as TypeMoq from 'typemoq';
import * as sqlops from 'sqlops';
import * as vscode from 'vscode';
import 'mocha';
import { ServiceClientCredentials } from 'ms-rest';
import { AzureResourceServicePool } from '../../../azureResource/servicePool';
import {
IAzureResourceCacheService,
IAzureResourceContextService,
IAzureResourceCredentialService,
IAzureResourceDatabaseService
} from '../../../azureResource/interfaces';
import { IAzureResourceTreeChangeHandler } from '../../../azureResource/tree/treeChangeHandler';
import { AzureResourceSubscription, AzureResourceDatabase } from '../../../azureResource/models';
import { AzureResourceItemType } from '../../../azureResource/constants';
import { AzureResourceMessageTreeNode } from '../../../azureResource/tree/messageTreeNode';
import { AzureResourceDatabaseContainerTreeNode } from '../../../azureResource/tree/databaseContainerTreeNode';
import { AzureResourceDatabaseTreeNode } from '../../../azureResource/tree/databaseTreeNode';
// Mock services
const mockServicePool = AzureResourceServicePool.getInstance();
let mockCacheService: TypeMoq.IMock<IAzureResourceCacheService>;
let mockContextService: TypeMoq.IMock<IAzureResourceContextService>;
let mockCredentialService: TypeMoq.IMock<IAzureResourceCredentialService>;
let mockDatabaseService: TypeMoq.IMock<IAzureResourceDatabaseService>;
let mockTreeChangeHandler: TypeMoq.IMock<IAzureResourceTreeChangeHandler>;
// Mock test data
const mockAccount: sqlops.Account = {
key: {
accountId: 'mock_account',
providerId: 'mock_provider'
},
displayInfo: {
displayName: 'mock_account@test.com',
accountType: 'Microsoft',
contextualDisplayName: 'test'
},
properties: undefined,
isStale: false
};
const mockCredential = TypeMoq.Mock.ofType<ServiceClientCredentials>().object;
const mockCredentials = [mockCredential];
const mockSubscription: AzureResourceSubscription = {
id: 'mock_subscription',
name: 'mock subscription'
};
const mockDatabase1: AzureResourceDatabase = {
name: 'mock database 1',
serverName: 'mock server 1',
serverFullName: 'mock server 1',
loginName: 'mock user 1'
};
const mockDatabase2: AzureResourceDatabase = {
name: 'mock database 2',
serverName: 'mock server 2',
serverFullName: 'mock server 2',
loginName: 'mock user 2'
};
const mockDatabases = [mockDatabase1, mockDatabase2];
let mockDatabaseContainerCache: { databases: { [subscriptionId: string]: AzureResourceDatabase[] } };
describe('AzureResourceDatabaseContainerTreeNode.info', function(): void {
beforeEach(() => {
mockContextService = TypeMoq.Mock.ofType<IAzureResourceContextService>();
mockTreeChangeHandler = TypeMoq.Mock.ofType<IAzureResourceTreeChangeHandler>();
mockServicePool.contextService = mockContextService.object;
});
it('Should be correct when created.', async function(): Promise<void> {
const databaseContainerTreeNode = new AzureResourceDatabaseContainerTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
const databaseContainerTreeNodeLabel = 'SQL Databases';
should(databaseContainerTreeNode.nodePathValue).equal('databaseContainer');
const treeItem = await databaseContainerTreeNode.getTreeItem();
should(treeItem.label).equal(databaseContainerTreeNodeLabel);
should(treeItem.contextValue).equal(AzureResourceItemType.databaseContainer);
should(treeItem.collapsibleState).equal(vscode.TreeItemCollapsibleState.Collapsed);
const nodeInfo = databaseContainerTreeNode.getNodeInfo();
should(nodeInfo.isLeaf).false();
should(nodeInfo.label).equal(databaseContainerTreeNodeLabel);
should(nodeInfo.nodeType).equal(AzureResourceItemType.databaseContainer);
should(nodeInfo.iconType).equal(AzureResourceItemType.databaseContainer);
});
});
describe('AzureResourceDatabaseContainerTreeNode.getChildren', function(): void {
beforeEach(() => {
mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>();
mockCredentialService = TypeMoq.Mock.ofType<IAzureResourceCredentialService>();
mockDatabaseService = TypeMoq.Mock.ofType<IAzureResourceDatabaseService>();
mockTreeChangeHandler = TypeMoq.Mock.ofType<IAzureResourceTreeChangeHandler>();
mockDatabaseContainerCache = { databases: {} };
mockServicePool.cacheService = mockCacheService.object;
mockServicePool.credentialService = mockCredentialService.object;
mockServicePool.databaseService = mockDatabaseService.object;
mockCredentialService.setup((o) => o.getCredentials(mockAccount)).returns(() => Promise.resolve(mockCredentials));
mockCacheService.setup((o) => o.get(TypeMoq.It.isAnyString())).returns(() => mockDatabaseContainerCache);
mockCacheService.setup((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => mockDatabaseContainerCache.databases[mockSubscription.id] = mockDatabases);
});
it('Should load databases from scratch and update cache when it is clearing cache.', async function(): Promise<void> {
mockDatabaseService.setup((o) => o.getDatabases(mockSubscription, mockCredentials)).returns(() => Promise.resolve(mockDatabases));
const databaseContainerTreeNode = new AzureResourceDatabaseContainerTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
const children = await databaseContainerTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.once());
mockDatabaseService.verify((o) => o.getDatabases(mockSubscription, mockCredentials), TypeMoq.Times.once());
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.once());
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.once());
should(databaseContainerTreeNode.isClearingCache).false();
should(children).Array();
should(children.length).equal(mockDatabases.length);
should(Object.keys(mockDatabaseContainerCache.databases)).deepEqual([mockSubscription.id]);
should(mockDatabaseContainerCache.databases[mockSubscription.id]).deepEqual(mockDatabases);
for (let ix = 0; ix < mockDatabases.length; ix++) {
const child = children[ix];
const database = mockDatabases[ix];
should(child).instanceof(AzureResourceDatabaseTreeNode);
should(child.nodePathValue).equal(`database_${database.name}`);
}
});
it('Should load databases from cache when it is not clearing cache.', async function(): Promise<void> {
mockDatabaseService.setup((o) => o.getDatabases(mockSubscription, mockCredentials)).returns(() => Promise.resolve(mockDatabases));
const databaseContainerTreeNode = new AzureResourceDatabaseContainerTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
await databaseContainerTreeNode.getChildren();
const children = await databaseContainerTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.exactly(1));
mockDatabaseService.verify((o) => o.getDatabases(mockSubscription, mockCredentials), TypeMoq.Times.exactly(1));
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.exactly(2));
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.exactly(1));
should(children.length).equal(mockDatabaseContainerCache.databases[mockSubscription.id].length);
for (let ix = 0; ix < mockDatabaseContainerCache.databases[mockSubscription.id].length; ix++) {
should(children[ix].nodePathValue).equal(`database_${mockDatabaseContainerCache.databases[mockSubscription.id][ix].name}`);
}
});
it('Should handle when there is no databases.', async function(): Promise<void> {
mockDatabaseService.setup((o) => o.getDatabases(mockSubscription, mockCredentials)).returns(() => Promise.resolve(undefined));
const databaseContainerTreeNode = new AzureResourceDatabaseContainerTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
const children = await databaseContainerTreeNode.getChildren();
should(children).Array();
should(children.length).equal(1);
should(children[0]).instanceof(AzureResourceMessageTreeNode);
should(children[0].nodePathValue).startWith('message_');
should(children[0].getNodeInfo().label).equal('No SQL Databases found.');
});
it('Should handle errors.', async function(): Promise<void> {
const mockError = 'Test error';
mockDatabaseService.setup((o) => o.getDatabases(mockSubscription, mockCredentials)).returns(() => { throw new Error(mockError); });
const databaseContainerTreeNode = new AzureResourceDatabaseContainerTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
const children = await databaseContainerTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.once());
mockDatabaseService.verify((o) => o.getDatabases(mockSubscription, mockCredentials), TypeMoq.Times.once());
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.never());
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.never());
should(children).Array();
should(children.length).equal(1);
should(children[0]).instanceof(AzureResourceMessageTreeNode);
should(children[0].nodePathValue).startWith('message_');
should(children[0].getNodeInfo().label).equal(`Error: ${mockError}`);
});
});
describe('AzureResourceDatabaseContainerTreeNode.clearCache', function() : void {
beforeEach(() => {
mockTreeChangeHandler = TypeMoq.Mock.ofType<IAzureResourceTreeChangeHandler>();
});
it('Should clear cache.', async function(): Promise<void> {
const databaseContainerTreeNode = new AzureResourceDatabaseContainerTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
databaseContainerTreeNode.clearCache();
should(databaseContainerTreeNode.isClearingCache).true();
});
});

View File

@@ -0,0 +1,219 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as should from 'should';
import * as TypeMoq from 'typemoq';
import * as sqlops from 'sqlops';
import * as vscode from 'vscode';
import 'mocha';
import { ServiceClientCredentials } from 'ms-rest';
import { AzureResourceServicePool } from '../../../azureResource/servicePool';
import {
IAzureResourceCacheService,
IAzureResourceContextService,
IAzureResourceCredentialService,
IAzureResourceDatabaseServerService
} from '../../../azureResource/interfaces';
import { IAzureResourceTreeChangeHandler } from '../../../azureResource/tree/treeChangeHandler';
import { AzureResourceSubscription, AzureResourceDatabaseServer } from '../../../azureResource/models';
import { AzureResourceItemType } from '../../../azureResource/constants';
import { AzureResourceMessageTreeNode } from '../../../azureResource/tree/messageTreeNode';
import { AzureResourceDatabaseServerContainerTreeNode } from '../../../azureResource/tree/databaseServerContainerTreeNode';
import { AzureResourceDatabaseServerTreeNode } from '../../../azureResource/tree/databaseServerTreeNode';
// Mock services
const mockServicePool = AzureResourceServicePool.getInstance();
let mockCacheService: TypeMoq.IMock<IAzureResourceCacheService>;
let mockContextService: TypeMoq.IMock<IAzureResourceContextService>;
let mockCredentialService: TypeMoq.IMock<IAzureResourceCredentialService>;
let mockDatabaseServerService: TypeMoq.IMock<IAzureResourceDatabaseServerService>;
let mockTreeChangeHandler: TypeMoq.IMock<IAzureResourceTreeChangeHandler>;
// Mock test data
const mockAccount: sqlops.Account = {
key: {
accountId: 'mock_account',
providerId: 'mock_provider'
},
displayInfo: {
displayName: 'mock_account@test.com',
accountType: 'Microsoft',
contextualDisplayName: 'test'
},
properties: undefined,
isStale: false
};
const mockCredential = TypeMoq.Mock.ofType<ServiceClientCredentials>().object;
const mockCredentials = [mockCredential];
const mockSubscription: AzureResourceSubscription = {
id: 'mock_subscription',
name: 'mock subscription'
};
const mockDatabaseServer1: AzureResourceDatabaseServer = {
name: 'mock server 1',
fullName: 'mock server 1',
loginName: 'mock user 1',
defaultDatabaseName: 'master'
};
const mockDatabaseServer2: AzureResourceDatabaseServer = {
name: 'mock server 2',
fullName: 'mock server 2',
loginName: 'mock user 2',
defaultDatabaseName: 'master'
};
const mockDatabaseServers = [mockDatabaseServer1, mockDatabaseServer2];
let mockDatabaseServerContainerCache: { databaseServers: { [subscriptionId: string]: AzureResourceDatabaseServer[] } };
describe('AzureResourceDatabaseServerContainerTreeNode.info', function(): void {
beforeEach(() => {
mockContextService = TypeMoq.Mock.ofType<IAzureResourceContextService>();
mockTreeChangeHandler = TypeMoq.Mock.ofType<IAzureResourceTreeChangeHandler>();
mockServicePool.contextService = mockContextService.object;
});
it('Should be correct when created.', async function(): Promise<void> {
const databaseServerContainerTreeNode = new AzureResourceDatabaseServerContainerTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
const databaseServerContainerTreeNodeLabel = 'SQL Servers';
should(databaseServerContainerTreeNode.nodePathValue).equal('databaseServerContainer');
const treeItem = await databaseServerContainerTreeNode.getTreeItem();
should(treeItem.label).equal(databaseServerContainerTreeNodeLabel);
should(treeItem.contextValue).equal(AzureResourceItemType.databaseServerContainer);
should(treeItem.collapsibleState).equal(vscode.TreeItemCollapsibleState.Collapsed);
const nodeInfo = databaseServerContainerTreeNode.getNodeInfo();
should(nodeInfo.isLeaf).false();
should(nodeInfo.label).equal(databaseServerContainerTreeNodeLabel);
should(nodeInfo.nodeType).equal(AzureResourceItemType.databaseServerContainer);
should(nodeInfo.iconType).equal(AzureResourceItemType.databaseServerContainer);
});
});
describe('AzureResourceDatabaseServerContainerTreeNode.getChildren', function(): void {
beforeEach(() => {
mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>();
mockCredentialService = TypeMoq.Mock.ofType<IAzureResourceCredentialService>();
mockDatabaseServerService = TypeMoq.Mock.ofType<IAzureResourceDatabaseServerService>();
mockTreeChangeHandler = TypeMoq.Mock.ofType<IAzureResourceTreeChangeHandler>();
mockDatabaseServerContainerCache = { databaseServers: {} };
mockServicePool.cacheService = mockCacheService.object;
mockServicePool.credentialService = mockCredentialService.object;
mockServicePool.databaseServerService = mockDatabaseServerService.object;
mockCredentialService.setup((o) => o.getCredentials(mockAccount)).returns(() => Promise.resolve(mockCredentials));
mockCacheService.setup((o) => o.get(TypeMoq.It.isAnyString())).returns(() => mockDatabaseServerContainerCache);
mockCacheService.setup((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => mockDatabaseServerContainerCache.databaseServers[mockSubscription.id] = mockDatabaseServers);
});
it('Should load database servers from scratch and update cache when it is clearing cache.', async function(): Promise<void> {
mockDatabaseServerService.setup((o) => o.getDatabaseServers(mockSubscription, mockCredentials)).returns(() => Promise.resolve(mockDatabaseServers));
const databaseServerContainerTreeNode = new AzureResourceDatabaseServerContainerTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
const children = await databaseServerContainerTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.once());
mockDatabaseServerService.verify((o) => o.getDatabaseServers(mockSubscription, mockCredentials), TypeMoq.Times.once());
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.once());
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.once());
should(databaseServerContainerTreeNode.isClearingCache).false();
should(children).Array();
should(children.length).equal(mockDatabaseServers.length);
should(Object.keys(mockDatabaseServerContainerCache.databaseServers)).deepEqual([mockSubscription.id]);
should(mockDatabaseServerContainerCache.databaseServers[mockSubscription.id]).deepEqual(mockDatabaseServers);
for (let ix = 0; ix < mockDatabaseServers.length; ix++) {
const child = children[ix];
const databaseServer = mockDatabaseServers[ix];
should(child).instanceof(AzureResourceDatabaseServerTreeNode);
should(child.nodePathValue).equal(`databaseServer_${databaseServer.name}`);
}
});
it('Should load database servers from cache when it is not clearing cache.', async function(): Promise<void> {
mockDatabaseServerService.setup((o) => o.getDatabaseServers(mockSubscription, mockCredentials)).returns(() => Promise.resolve(mockDatabaseServers));
const databaseServerContainerTreeNode = new AzureResourceDatabaseServerContainerTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
await databaseServerContainerTreeNode.getChildren();
const children = await databaseServerContainerTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.exactly(1));
mockDatabaseServerService.verify((o) => o.getDatabaseServers(mockSubscription, mockCredentials), TypeMoq.Times.exactly(1));
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.exactly(2));
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.exactly(1));
should(children.length).equal(mockDatabaseServerContainerCache.databaseServers[mockSubscription.id].length);
for (let ix = 0; ix < mockDatabaseServerContainerCache.databaseServers[mockSubscription.id].length; ix++) {
should(children[ix].nodePathValue).equal(`databaseServer_${mockDatabaseServerContainerCache.databaseServers[mockSubscription.id][ix].name}`);
}
});
it('Should handle when there is no database servers.', async function(): Promise<void> {
mockDatabaseServerService.setup((o) => o.getDatabaseServers(mockSubscription, mockCredentials)).returns(() => Promise.resolve(undefined));
const databaseContainerTreeNode = new AzureResourceDatabaseServerContainerTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
const children = await databaseContainerTreeNode.getChildren();
should(children).Array();
should(children.length).equal(1);
should(children[0]).instanceof(AzureResourceMessageTreeNode);
should(children[0].nodePathValue).startWith('message_');
should(children[0].getNodeInfo().label).equal('No SQL Servers found.');
});
it('Should handle errors.', async function(): Promise<void> {
const mockError = 'Test error';
mockDatabaseServerService.setup((o) => o.getDatabaseServers(mockSubscription, mockCredentials)).returns(() => { throw new Error(mockError); });
const databaseServerContainerTreeNode = new AzureResourceDatabaseServerContainerTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
const children = await databaseServerContainerTreeNode.getChildren();
mockCredentialService.verify((o) => o.getCredentials(mockAccount), TypeMoq.Times.once());
mockDatabaseServerService.verify((o) => o.getDatabaseServers(mockSubscription, mockCredentials), TypeMoq.Times.once());
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.never());
mockCacheService.verify((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny()), TypeMoq.Times.never());
should(children).Array();
should(children.length).equal(1);
should(children[0]).instanceof(AzureResourceMessageTreeNode);
should(children[0].nodePathValue).startWith('message_');
should(children[0].getNodeInfo().label).equal(`Error: ${mockError}`);
});
});
describe('AzureResourceDatabaseServerContainerTreeNode.clearCache', function() : void {
beforeEach(() => {
mockTreeChangeHandler = TypeMoq.Mock.ofType<IAzureResourceTreeChangeHandler>();
});
it('Should clear cache.', async function(): Promise<void> {
const databaseServerContainerTreeNode = new AzureResourceDatabaseServerContainerTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
databaseServerContainerTreeNode.clearCache();
should(databaseServerContainerTreeNode.isClearingCache).true();
});
});

View File

@@ -0,0 +1,62 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as should from 'should';
import * as TypeMoq from 'typemoq';
import * as vscode from 'vscode';
import 'mocha';
import { AzureResourceServicePool } from '../../../azureResource/servicePool';
import { IAzureResourceContextService } from '../../../azureResource/interfaces';
import { IAzureResourceTreeChangeHandler } from '../../../azureResource/tree/treeChangeHandler';
import { AzureResourceDatabaseServer } from '../../../azureResource/models';
import { AzureResourceItemType } from '../../../azureResource/constants';
import { AzureResourceDatabaseServerTreeNode } from '../../../azureResource/tree/databaseServerTreeNode';
// Mock services
const mockServicePool = AzureResourceServicePool.getInstance();
let mockContextService: TypeMoq.IMock<IAzureResourceContextService>;
let mockTreeChangeHandler: TypeMoq.IMock<IAzureResourceTreeChangeHandler>;
// Mock test data
const mockDatabaseServer: AzureResourceDatabaseServer = {
name: 'mock database 1',
fullName: 'mock server 1',
loginName: 'mock user 1',
defaultDatabaseName: 'master'
};
describe('AzureResourceDatabaseServerTreeNode.info', function(): void {
beforeEach(() => {
mockContextService = TypeMoq.Mock.ofType<IAzureResourceContextService>();
mockTreeChangeHandler = TypeMoq.Mock.ofType<IAzureResourceTreeChangeHandler>();
mockServicePool.contextService = mockContextService.object;
});
it('Should be correct when created.', async function(): Promise<void> {
const databaseServerTreeNode = new AzureResourceDatabaseServerTreeNode(mockDatabaseServer, mockTreeChangeHandler.object, undefined);
const databaseServerTreeNodeLabel = mockDatabaseServer.name;
should(databaseServerTreeNode.nodePathValue).equal(`databaseServer_${mockDatabaseServer.name}`);
const treeItem = await databaseServerTreeNode.getTreeItem();
should(treeItem.label).equal(databaseServerTreeNodeLabel);
should(treeItem.contextValue).equal(AzureResourceItemType.databaseServer);
should(treeItem.collapsibleState).equal(vscode.TreeItemCollapsibleState.None);
const nodeInfo = databaseServerTreeNode.getNodeInfo();
should(nodeInfo.isLeaf).true();
should(nodeInfo.label).equal(databaseServerTreeNodeLabel);
should(nodeInfo.nodeType).equal(AzureResourceItemType.databaseServer);
should(nodeInfo.iconType).equal(AzureResourceItemType.databaseServer);
});
});

View File

@@ -0,0 +1,62 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as should from 'should';
import * as TypeMoq from 'typemoq';
import * as vscode from 'vscode';
import 'mocha';
import { AzureResourceServicePool } from '../../../azureResource/servicePool';
import { IAzureResourceContextService } from '../../../azureResource/interfaces';
import { IAzureResourceTreeChangeHandler } from '../../../azureResource/tree/treeChangeHandler';
import { AzureResourceDatabase } from '../../../azureResource/models';
import { AzureResourceItemType } from '../../../azureResource/constants';
import { AzureResourceDatabaseTreeNode } from '../../../azureResource/tree/databaseTreeNode';
// Mock services
const mockServicePool = AzureResourceServicePool.getInstance();
let mockContextService: TypeMoq.IMock<IAzureResourceContextService>;
let mockTreeChangeHandler: TypeMoq.IMock<IAzureResourceTreeChangeHandler>;
// Mock test data
const mockDatabase: AzureResourceDatabase = {
name: 'mock database 1',
serverName: 'mock server 1',
serverFullName: 'mock server 1',
loginName: 'mock user 1'
};
describe('AzureResourceDatabaseTreeNode.info', function(): void {
beforeEach(() => {
mockContextService = TypeMoq.Mock.ofType<IAzureResourceContextService>();
mockTreeChangeHandler = TypeMoq.Mock.ofType<IAzureResourceTreeChangeHandler>();
mockServicePool.contextService = mockContextService.object;
});
it('Should be correct.', async function(): Promise<void> {
const databaseTreeNode = new AzureResourceDatabaseTreeNode(mockDatabase, mockTreeChangeHandler.object, undefined);
const databaseTreeNodeLabel = `${mockDatabase.name} (${mockDatabase.serverName})`;
should(databaseTreeNode.nodePathValue).equal(`database_${mockDatabase.name}`);
const treeItem = await databaseTreeNode.getTreeItem();
should(treeItem.label).equal(databaseTreeNodeLabel);
should(treeItem.contextValue).equal(AzureResourceItemType.database);
should(treeItem.collapsibleState).equal(vscode.TreeItemCollapsibleState.None);
const nodeInfo = databaseTreeNode.getNodeInfo();
should(nodeInfo.isLeaf).true();
should(nodeInfo.label).equal(databaseTreeNodeLabel);
should(nodeInfo.nodeType).equal(AzureResourceItemType.database);
should(nodeInfo.iconType).equal(AzureResourceItemType.database);
});
});

View File

@@ -0,0 +1,41 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as should from 'should';
import * as vscode from 'vscode';
import 'mocha';
import { AzureResourceItemType } from '../../../azureResource/constants';
import { AzureResourceMessageTreeNode } from '../../../azureResource/tree/messageTreeNode';
describe('AzureResourceMessageTreeNode.info', function(): void {
it('Should be correct when created.', async function(): Promise<void> {
const mockMessage = 'Test messagse';
const treeNode = new AzureResourceMessageTreeNode(mockMessage, undefined);
should(treeNode.nodePathValue).startWith('message_');
const treeItem = await treeNode.getTreeItem();
should(treeItem.label).equal(mockMessage);
should(treeItem.contextValue).equal(AzureResourceItemType.message);
should(treeItem.collapsibleState).equal(vscode.TreeItemCollapsibleState.None);
const nodeInfo = treeNode.getNodeInfo();
should(nodeInfo.isLeaf).true();
should(nodeInfo.label).equal(mockMessage);
should(nodeInfo.nodeType).equal(AzureResourceItemType.message);
should(nodeInfo.iconType).equal(AzureResourceItemType.message);
});
});
describe('AzureResourceMessageTreeNode.create', function(): void {
it('Should create a message node.', async function(): Promise<void> {
const mockMessage = 'Test messagse';
const treeNode = AzureResourceMessageTreeNode.create(mockMessage, undefined);
should(treeNode).instanceof(AzureResourceMessageTreeNode);
});
});

View File

@@ -0,0 +1,91 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as should from 'should';
import * as TypeMoq from 'typemoq';
import * as sqlops from 'sqlops';
import * as vscode from 'vscode';
import 'mocha';
import { AzureResourceServicePool } from '../../../azureResource/servicePool';
import { IAzureResourceContextService } from '../../../azureResource/interfaces';
import { IAzureResourceTreeChangeHandler } from '../../../azureResource/tree/treeChangeHandler';
import { AzureResourceSubscription } from '../../../azureResource/models';
import { AzureResourceSubscriptionTreeNode } from '../../../azureResource/tree/subscriptionTreeNode';
import { AzureResourceDatabaseContainerTreeNode } from '../../../azureResource/tree/databaseContainerTreeNode';
import { AzureResourceDatabaseServerContainerTreeNode } from '../../../azureResource/tree/databaseServerContainerTreeNode';
import { AzureResourceItemType } from '../../../azureResource/constants';
// Mock services
const mockServicePool = AzureResourceServicePool.getInstance();
let mockContextService: TypeMoq.IMock<IAzureResourceContextService>;
let mockTreeChangeHandler: TypeMoq.IMock<IAzureResourceTreeChangeHandler>;
// Mock test data
const mockAccount: sqlops.Account = {
key: {
accountId: 'mock_account',
providerId: 'mock_provider'
},
displayInfo: {
displayName: 'mock_account@test.com',
accountType: 'Microsoft',
contextualDisplayName: 'test'
},
properties: undefined,
isStale: false
};
const mockSubscription: AzureResourceSubscription = {
id: 'mock_subscription',
name: 'mock subscription'
};
describe('AzureResourceSubscriptionTreeNode.info', function(): void {
beforeEach(() => {
mockContextService = TypeMoq.Mock.ofType<IAzureResourceContextService>();
mockTreeChangeHandler = TypeMoq.Mock.ofType<IAzureResourceTreeChangeHandler>();
mockServicePool.contextService = mockContextService.object;
});
it('Should be correct when created.', async function(): Promise<void> {
const subscriptionTreeNode = new AzureResourceSubscriptionTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
should(subscriptionTreeNode.nodePathValue).equal(`subscription_${mockSubscription.id}`);
const treeItem = await subscriptionTreeNode.getTreeItem();
should(treeItem.label).equal(mockSubscription.name);
should(treeItem.collapsibleState).equal(vscode.TreeItemCollapsibleState.Collapsed);
should(treeItem.contextValue).equal(AzureResourceItemType.subscription);
const nodeInfo = subscriptionTreeNode.getNodeInfo();
should(nodeInfo.label).equal(mockSubscription.name);
should(nodeInfo.isLeaf).equal(false);
should(nodeInfo.nodeType).equal(AzureResourceItemType.subscription);
should(nodeInfo.iconType).equal(AzureResourceItemType.subscription);
});
});
describe('AzureResourceSubscriptionTreeNode.getChildren', function(): void {
beforeEach(() => {
mockTreeChangeHandler = TypeMoq.Mock.ofType<IAzureResourceTreeChangeHandler>();
});
it('Should load database containers.', async function(): Promise<void> {
const subscriptionTreeNode = new AzureResourceSubscriptionTreeNode(mockSubscription, mockAccount, mockTreeChangeHandler.object, undefined);
const children = await subscriptionTreeNode.getChildren();
should(children).Array();
should(children.length).equal(2);
should(children[0]).instanceof(AzureResourceDatabaseContainerTreeNode);
should(children[1]).instanceof(AzureResourceDatabaseServerContainerTreeNode);
});
});

View File

@@ -0,0 +1,113 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as should from 'should';
import * as TypeMoq from 'typemoq';
import * as sqlops from 'sqlops';
import 'mocha';
import { AzureResourceServicePool } from '../../../azureResource/servicePool';
import { IAzureResourceAccountService } from '../../../azureResource/interfaces';
import { AzureResourceTreeProvider } from '../../../azureResource/tree/treeProvider';
import { AzureResourceAccountTreeNode } from '../../../azureResource/tree/accountTreeNode';
import { AzureResourceAccountNotSignedInTreeNode } from '../../../azureResource/tree/accountNotSignedInTreeNode';
import { AzureResourceMessageTreeNode } from '../../../azureResource/tree/messageTreeNode';
// Mock services
const mockServicePool = AzureResourceServicePool.getInstance();
let mockAccountService: TypeMoq.IMock<IAzureResourceAccountService>;
// Mock test data
const mockAccount1: sqlops.Account = {
key: {
accountId: 'mock_account_1',
providerId: 'mock_provider'
},
displayInfo: {
displayName: 'mock_account_1@test.com',
accountType: 'Microsoft',
contextualDisplayName: 'test'
},
properties: undefined,
isStale: false
};
const mockAccount2: sqlops.Account = {
key: {
accountId: 'mock_account_2',
providerId: 'mock_provider'
},
displayInfo: {
displayName: 'mock_account_2@test.com',
accountType: 'Microsoft',
contextualDisplayName: 'test'
},
properties: undefined,
isStale: false
};
const mockAccounts = [mockAccount1, mockAccount2];
describe('AzureResourceTreeProvider.getChildren', function(): void {
beforeEach(() => {
mockAccountService = TypeMoq.Mock.ofType<IAzureResourceAccountService>();
mockServicePool.accountService = mockAccountService.object;
});
it('Should load accounts.', async function(): Promise<void> {
mockAccountService.setup((o) => o.getAccounts()).returns(() => Promise.resolve(mockAccounts));
const treeProvider = new AzureResourceTreeProvider();
treeProvider.isSystemInitialized = true;
const children = await treeProvider.getChildren(undefined);
mockAccountService.verify((o) => o.getAccounts(), TypeMoq.Times.once());
should(children).Array();
should(children.length).equal(mockAccounts.length);
for (let ix = 0; ix < mockAccounts.length; ix++) {
const child = children[ix];
const account = mockAccounts[ix];
should(child).instanceof(AzureResourceAccountTreeNode);
should(child.nodePathValue).equal(`account_${account.key.accountId}`);
}
});
it('Should handle when there is no accounts.', async function(): Promise<void> {
mockAccountService.setup((o) => o.getAccounts()).returns(() => Promise.resolve(undefined));
const treeProvider = new AzureResourceTreeProvider();
treeProvider.isSystemInitialized = true;
const children = await treeProvider.getChildren(undefined);
should(children).Array();
should(children.length).equal(1);
should(children[0]).instanceof(AzureResourceAccountNotSignedInTreeNode);
});
it('Should handle errors.', async function(): Promise<void> {
const mockAccountError = 'Test account error';
mockAccountService.setup((o) => o.getAccounts()).returns(() => { throw new Error(mockAccountError); });
const treeProvider = new AzureResourceTreeProvider();
treeProvider.isSystemInitialized = true;
const children = await treeProvider.getChildren(undefined);
mockAccountService.verify((o) => o.getAccounts(), TypeMoq.Times.once());
should(children).Array();
should(children.length).equal(1);
should(children[0]).instanceof(AzureResourceMessageTreeNode);
should(children[0].nodePathValue).startWith('message_');
should(children[0].getNodeInfo().label).equal(`Error: ${mockAccountError}`);
});
});

View File

@@ -0,0 +1,30 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const path = require('path');
const testRunner = require('vscode/lib/testrunner');
const suite = 'Integration Azure Tests';
const options: any = {
ui: 'bdd',
useColors: true,
timeout: 60000
};
if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) {
options.reporter = 'mocha-multi-reporters';
options.reporterOptions = {
reporterEnabled: 'spec, mocha-junit-reporter',
mochaJunitReporterReporterOptions: {
testsuitesTitle: `${suite} ${process.platform}`,
mochaFile: path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${suite.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`)
}
};
}
testRunner.configure(options);
export = testRunner;