From 6d56701b5b6814db1ed3b9388071a6e43ff44f94 Mon Sep 17 00:00:00 2001 From: Kevin Cunnane Date: Wed, 29 May 2019 17:23:23 -0700 Subject: [PATCH] Refactor to remove controller and static instance (#5735) --- .../azurecore/src/azureResource/constants.ts | 1 + .../src/azureResource/resourceService.ts | 13 +-- .../src/azureResource/resourceTreeNode.ts | 16 +-- .../tree/subscriptionTreeNode.ts | 6 +- .../src/azureResource/tree/treeProvider.ts | 4 +- .../controllers/azureResourceController.ts | 62 ---------- .../src/controllers/controllerBase.ts | 34 ------ extensions/azurecore/src/extension.ts | 110 +++++++++++++----- .../azureResource/resourceService.test.ts | 3 +- .../azureResource/resourceTreeNode.test.ts | 25 ++-- .../tree/subscriptionTreeNode.test.ts | 27 ++--- 11 files changed, 134 insertions(+), 167 deletions(-) delete mode 100644 extensions/azurecore/src/controllers/azureResourceController.ts delete mode 100644 extensions/azurecore/src/controllers/controllerBase.ts diff --git a/extensions/azurecore/src/azureResource/constants.ts b/extensions/azurecore/src/azureResource/constants.ts index 09ab819749..d12722302a 100644 --- a/extensions/azurecore/src/azureResource/constants.ts +++ b/extensions/azurecore/src/azureResource/constants.ts @@ -16,6 +16,7 @@ export enum AzureResourceItemType { } export enum AzureResourceServiceNames { + resourceService = 'AzureResourceService', cacheService = 'AzureResourceCacheService', accountService = 'AzureResourceAccountService', subscriptionService = 'AzureResourceSubscriptionService', diff --git a/extensions/azurecore/src/azureResource/resourceService.ts b/extensions/azurecore/src/azureResource/resourceService.ts index aaf93039fa..90dd51111b 100644 --- a/extensions/azurecore/src/azureResource/resourceService.ts +++ b/extensions/azurecore/src/azureResource/resourceService.ts @@ -12,11 +12,11 @@ import { azureResource } from './azure-resource'; import { IAzureResourceNodeWithProviderId } from './interfaces'; export class AzureResourceService { - private constructor() { - } + private _areResourceProvidersLoaded: boolean = false; + private _resourceProviders: { [resourceProviderId: string]: azureResource.IAzureResourceProvider } = {}; + private _treeDataProviders: { [resourceProviderId: string]: azureResource.IAzureResourceTreeDataProvider } = {}; - public static getInstance(): AzureResourceService { - return AzureResourceService._instance; + public constructor() { } public async listResourceProviderIds(): Promise { @@ -121,9 +121,4 @@ export class AzureResourceService { this._treeDataProviders[resourceProvider.providerId] = resourceProvider.getTreeDataProvider(); } - private _areResourceProvidersLoaded: boolean = false; - private _resourceProviders: { [resourceProviderId: string]: azureResource.IAzureResourceProvider } = {}; - private _treeDataProviders: { [resourceProviderId: string]: azureResource.IAzureResourceTreeDataProvider } = {}; - - private static readonly _instance = new AzureResourceService(); } \ No newline at end of file diff --git a/extensions/azurecore/src/azureResource/resourceTreeNode.ts b/extensions/azurecore/src/azureResource/resourceTreeNode.ts index 3159c90047..a3b8b179c7 100644 --- a/extensions/azurecore/src/azureResource/resourceTreeNode.ts +++ b/extensions/azurecore/src/azureResource/resourceTreeNode.ts @@ -15,14 +15,19 @@ import { AzureResourceService } from './resourceService'; import { IAzureResourceNodeWithProviderId } from './interfaces'; import { AzureResourceMessageTreeNode } from './messageTreeNode'; import { AzureResourceErrorMessageUtil } from './utils'; +import { AppContext } from '../appContext'; +import { AzureResourceServiceNames } from './constants'; export class AzureResourceResourceTreeNode extends TreeNode { + private _resourceService: AzureResourceService; + public constructor( public readonly resourceNodeWithProviderId: IAzureResourceNodeWithProviderId, - parent: TreeNode + parent: TreeNode, + private appContext: AppContext ) { super(); - + this._resourceService = appContext.getService(AzureResourceServiceNames.resourceService); this.parent = parent; } @@ -36,12 +41,12 @@ export class AzureResourceResourceTreeNode extends TreeNode { const children = await this._resourceService.getChildren(this.resourceNodeWithProviderId.resourceProviderId, this.resourceNodeWithProviderId.resourceNode); if (children.length === 0) { - return [AzureResourceMessageTreeNode.create(AzureResourceResourceTreeNode.noResourcesLabel, this)]; + return [AzureResourceMessageTreeNode.create(localize('azure.resource.resourceTreeNode.noResourcesLabel', 'No Resources found'), this)]; } else { return children.map((child) => { // To make tree node's id unique, otherwise, treeModel.js would complain 'item already registered' child.resourceNode.treeItem.id = `${this.resourceNodeWithProviderId.resourceNode.treeItem.id}.${child.resourceNode.treeItem.id}`; - return new AzureResourceResourceTreeNode(child, this); + return new AzureResourceResourceTreeNode(child, this, this.appContext); }); } } catch (error) { @@ -73,7 +78,4 @@ export class AzureResourceResourceTreeNode extends TreeNode { return this.resourceNodeWithProviderId.resourceNode.treeItem.id; } - private _resourceService = AzureResourceService.getInstance(); - - private static readonly noResourcesLabel = localize('azure.resource.resourceTreeNode.noResourcesLabel', 'No Resources found.'); } \ No newline at end of file diff --git a/extensions/azurecore/src/azureResource/tree/subscriptionTreeNode.ts b/extensions/azurecore/src/azureResource/tree/subscriptionTreeNode.ts index 9177ca4f69..fb9f1bc420 100644 --- a/extensions/azurecore/src/azureResource/tree/subscriptionTreeNode.ts +++ b/extensions/azurecore/src/azureResource/tree/subscriptionTreeNode.ts @@ -15,7 +15,7 @@ import { azureResource } from '../azure-resource'; import { TreeNode } from '../treeNode'; import { IAzureResourceNodeWithProviderId } from '../interfaces'; import { AzureResourceContainerTreeNodeBase } from './baseTreeNodes'; -import { AzureResourceItemType } from '../constants'; +import { AzureResourceItemType, AzureResourceServiceNames } from '../constants'; import { IAzureResourceTreeChangeHandler } from './treeChangeHandler'; import { AzureResourceMessageTreeNode } from '../messageTreeNode'; import { AzureResourceErrorMessageUtil } from '../utils'; @@ -39,7 +39,7 @@ export class AzureResourceSubscriptionTreeNode extends AzureResourceContainerTre public async getChildren(): Promise { try { - const resourceService = AzureResourceService.getInstance(); + const resourceService = this.appContext.getService(AzureResourceServiceNames.resourceService); const children: IAzureResourceNodeWithProviderId[] = []; @@ -53,7 +53,7 @@ export class AzureResourceSubscriptionTreeNode extends AzureResourceContainerTre return children.map((child) => { // To make tree node's id unique, otherwise, treeModel.js would complain 'item already registered' child.resourceNode.treeItem.id = `${this._id}.${child.resourceNode.treeItem.id}`; - return new AzureResourceResourceTreeNode(child, this); + return new AzureResourceResourceTreeNode(child, this, this.appContext); }); } } catch (error) { diff --git a/extensions/azurecore/src/azureResource/tree/treeProvider.ts b/extensions/azurecore/src/azureResource/tree/treeProvider.ts index c0f99460c2..17de2cf079 100644 --- a/extensions/azurecore/src/azureResource/tree/treeProvider.ts +++ b/extensions/azurecore/src/azureResource/tree/treeProvider.ts @@ -22,9 +22,7 @@ import { IAzureResourceAccountService } from '../../azureResource/interfaces'; import { AzureResourceServiceNames } from '../constants'; export class AzureResourceTreeProvider implements TreeDataProvider, IAzureResourceTreeChangeHandler { - public constructor( - public readonly appContext: AppContext - ) { + public constructor(public readonly appContext: AppContext) { } public async getChildren(element?: TreeNode): Promise { diff --git a/extensions/azurecore/src/controllers/azureResourceController.ts b/extensions/azurecore/src/controllers/azureResourceController.ts deleted file mode 100644 index d1675b2173..0000000000 --- a/extensions/azurecore/src/controllers/azureResourceController.ts +++ /dev/null @@ -1,62 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import ControllerBase from './controllerBase'; -import { DidChangeAccountsParams, Account } from 'azdata'; - -import { - IAzureResourceCacheService, - IAzureResourceAccountService, - IAzureResourceSubscriptionService, - IAzureResourceSubscriptionFilterService, - IAzureResourceTenantService -} from '../azureResource/interfaces'; -import { AzureResourceServiceNames } from '../azureResource/constants'; -import { AzureResourceTreeProvider } from '../azureResource/tree/treeProvider'; -import { registerAzureResourceCommands } from '../azureResource/commands'; -import { AzureResourceAccountService } from '../azureResource/services/accountService'; -import { AzureResourceSubscriptionService } from '../azureResource/services/subscriptionService'; -import { AzureResourceSubscriptionFilterService } from '../azureResource/services/subscriptionFilterService'; -import { AzureResourceCacheService } from '../azureResource/services/cacheService'; -import { AzureResourceTenantService } from '../azureResource/services/tenantService'; - -import { registerAzureResourceDatabaseServerCommands } from '../azureResource/providers/databaseServer/commands'; -import { registerAzureResourceDatabaseCommands } from '../azureResource/providers/database/commands'; -import { equals } from '../azureResource/utils'; - -export default class AzureResourceController extends ControllerBase { - public activate(): Promise { - this.appContext.registerService(AzureResourceServiceNames.cacheService, new AzureResourceCacheService(this.extensionContext)); - this.appContext.registerService(AzureResourceServiceNames.accountService, new AzureResourceAccountService(this.apiWrapper)); - this.appContext.registerService(AzureResourceServiceNames.subscriptionService, new AzureResourceSubscriptionService()); - this.appContext.registerService(AzureResourceServiceNames.subscriptionFilterService, new AzureResourceSubscriptionFilterService(new AzureResourceCacheService(this.extensionContext))); - this.appContext.registerService(AzureResourceServiceNames.tenantService, new AzureResourceTenantService()); - - const azureResourceTree = new AzureResourceTreeProvider(this.appContext); - this.extensionContext.subscriptions.push(this.apiWrapper.registerTreeDataProvider('azureResourceExplorer', azureResourceTree)); - - let previousAccounts: Array = undefined; - this.appContext.getService(AzureResourceServiceNames.accountService).onDidChangeAccounts((e: DidChangeAccountsParams) => { - // the onDidChangeAccounts event will trigger in many cases where the accounts didn't actually change - // the notifyNodeChanged event triggers a refresh which triggers a getChildren which can trigger this callback - // this below check short-circuits the infinite callback loop - if (!equals(e.accounts, previousAccounts)) { - azureResourceTree.notifyNodeChanged(undefined); - } - previousAccounts = e.accounts; - }); - - registerAzureResourceCommands(this.appContext, azureResourceTree); - - registerAzureResourceDatabaseServerCommands(this.appContext); - - registerAzureResourceDatabaseCommands(this.appContext); - - return Promise.resolve(true); - } - - public deactivate(): void { - } -} diff --git a/extensions/azurecore/src/controllers/controllerBase.ts b/extensions/azurecore/src/controllers/controllerBase.ts deleted file mode 100644 index 15e31972b4..0000000000 --- a/extensions/azurecore/src/controllers/controllerBase.ts +++ /dev/null @@ -1,34 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 vscode from 'vscode'; - -import { AppContext } from '../appContext'; -import { ApiWrapper } from '../apiWrapper'; - -export default abstract class ControllerBase implements vscode.Disposable { - - public constructor(protected appContext: AppContext) { - } - - protected get apiWrapper(): ApiWrapper { - return this.appContext.apiWrapper; - } - - public get extensionContext(): vscode.ExtensionContext { - return this.appContext && this.appContext.extensionContext; - } - - abstract activate(): Promise; - - abstract deactivate(): void; - - public dispose(): void { - this.deactivate(); - } -} - diff --git a/extensions/azurecore/src/extension.ts b/extensions/azurecore/src/extension.ts index cf152569d6..aa232b20f6 100644 --- a/extensions/azurecore/src/extension.ts +++ b/extensions/azurecore/src/extension.ts @@ -8,10 +8,9 @@ import * as fs from 'fs'; import * as path from 'path'; import * as os from 'os'; import * as constants from './constants'; +import * as azdata from 'azdata'; -import AzureResourceController from './controllers/azureResourceController'; import { AppContext } from './appContext'; -import ControllerBase from './controllers/controllerBase'; import { ApiWrapper } from './apiWrapper'; import { AzureAccountProviderService } from './account-provider/azureAccountProviderService'; @@ -19,9 +18,21 @@ import { AzureResourceDatabaseServerProvider } from './azureResource/providers/d import { AzureResourceDatabaseServerService } from './azureResource/providers/databaseServer/databaseServerService'; import { AzureResourceDatabaseProvider } from './azureResource/providers/database/databaseProvider'; import { AzureResourceDatabaseService } from './azureResource/providers/database/databaseService'; +import { AzureResourceService } from './azureResource/resourceService'; +import { IAzureResourceCacheService, IAzureResourceAccountService, IAzureResourceSubscriptionService, IAzureResourceSubscriptionFilterService, IAzureResourceTenantService } from './azureResource/interfaces'; +import { AzureResourceServiceNames } from './azureResource/constants'; +import { AzureResourceAccountService } from './azureResource/services/accountService'; +import { AzureResourceSubscriptionService } from './azureResource/services/subscriptionService'; +import { AzureResourceSubscriptionFilterService } from './azureResource/services/subscriptionFilterService'; +import { AzureResourceCacheService } from './azureResource/services/cacheService'; +import { AzureResourceTenantService } from './azureResource/services/tenantService'; +import { registerAzureResourceCommands } from './azureResource/commands'; +import { registerAzureResourceDatabaseServerCommands } from './azureResource/providers/databaseServer/commands'; +import { registerAzureResourceDatabaseCommands } from './azureResource/providers/database/commands'; +import { AzureResourceTreeProvider } from './azureResource/tree/treeProvider'; +import { equals } from './azureResource/utils'; -let controllers: ControllerBase[] = []; - +let extensionContext: vscode.ExtensionContext; // The function is a duplicate of \src\paths.js. IT would be better to import path.js but it doesn't // work for now because the extension is running in different process. @@ -39,36 +50,30 @@ export function getDefaultLogLocation() { return path.join(getAppDataPath(), 'azuredatastudio'); } +function pushDisposable(disposable: vscode.Disposable): void { + extensionContext.subscriptions.push(disposable); +} // this method is called when your extension is activated // your extension is activated the very first time the command is executed -export function activate(extensionContext: vscode.ExtensionContext) { +export function activate(context: vscode.ExtensionContext) { + extensionContext = context; const apiWrapper = new ApiWrapper(); let appContext = new AppContext(extensionContext, apiWrapper); - let activations: Thenable[] = []; - // Create the folder for storing the token caches - let storagePath = path.join(getDefaultLogLocation(), constants.extensionName); - try { - if (!fs.existsSync(storagePath)) { - fs.mkdirSync(storagePath); - console.log('Initialized Azure account extension storage.'); - } - } catch (e) { - console.error(`Initialization of Azure account extension storage failed: ${e}`); - console.error('Azure accounts will not be available'); + let storagePath = findOrMakeStoragePath(); + if (!storagePath) { return undefined; } // Create the provider service and activate - const accountProviderService = new AzureAccountProviderService(extensionContext, storagePath); - extensionContext.subscriptions.push(accountProviderService); - accountProviderService.activate(); + initAzureAccountProvider(extensionContext, storagePath); - const azureResourceController = new AzureResourceController(appContext); - controllers.push(azureResourceController); - extensionContext.subscriptions.push(azureResourceController); - activations.push(azureResourceController.activate()); + registerAzureServices(appContext); + const azureResourceTree = new AzureResourceTreeProvider(appContext); + pushDisposable(apiWrapper.registerTreeDataProvider('azureResourceExplorer', azureResourceTree)); + registerAccountService(appContext, azureResourceTree); + registerCommands(appContext, azureResourceTree); return { provideResources() { @@ -80,9 +85,60 @@ export function activate(extensionContext: vscode.ExtensionContext) { }; } -// this method is called when your extension is deactivated -export function deactivate() { - for (let controller of controllers) { - controller.deactivate(); +// Create the folder for storing the token caches +function findOrMakeStoragePath() { + let storagePath = path.join(getDefaultLogLocation(), constants.extensionName); + try { + if (!fs.existsSync(storagePath)) { + fs.mkdirSync(storagePath); + console.log('Initialized Azure account extension storage.'); + } + } + catch (e) { + console.error(`Initialization of Azure account extension storage failed: ${e}`); + console.error('Azure accounts will not be available'); + } + return storagePath; +} + +async function initAzureAccountProvider(extensionContext: vscode.ExtensionContext, storagePath: string): Promise { + try { + const accountProviderService = new AzureAccountProviderService(extensionContext, storagePath); + extensionContext.subscriptions.push(accountProviderService); + await accountProviderService.activate(); + } catch (err) { + console.log('Unexpected error starting account provider: ' + err.message); } } + +function registerAzureServices(appContext: AppContext): void { + appContext.registerService(AzureResourceServiceNames.resourceService, new AzureResourceService()); + appContext.registerService(AzureResourceServiceNames.cacheService, new AzureResourceCacheService(extensionContext)); + appContext.registerService(AzureResourceServiceNames.subscriptionService, new AzureResourceSubscriptionService()); + appContext.registerService(AzureResourceServiceNames.subscriptionFilterService, new AzureResourceSubscriptionFilterService(new AzureResourceCacheService(extensionContext))); + appContext.registerService(AzureResourceServiceNames.tenantService, new AzureResourceTenantService()); +} +function registerAccountService(appContext: AppContext, azureResourceTree: AzureResourceTreeProvider): void { + let accountService = new AzureResourceAccountService(appContext.apiWrapper); + appContext.registerService(AzureResourceServiceNames.accountService, accountService); + let previousAccounts: Array = undefined; + accountService.onDidChangeAccounts((e: azdata.DidChangeAccountsParams) => { + // the onDidChangeAccounts event will trigger in many cases where the accounts didn't actually change + // the notifyNodeChanged event triggers a refresh which triggers a getChildren which can trigger this callback + // this below check short-circuits the infinite callback loop + if (!equals(e.accounts, previousAccounts)) { + azureResourceTree.notifyNodeChanged(undefined); + } + previousAccounts = e.accounts; + }); + +} + +function registerCommands(appContext: AppContext, azureResourceTree: AzureResourceTreeProvider): void { + registerAzureResourceCommands(appContext, azureResourceTree); + + registerAzureResourceDatabaseServerCommands(appContext); + + registerAzureResourceDatabaseCommands(appContext); +} + diff --git a/extensions/azurecore/src/test/azureResource/resourceService.test.ts b/extensions/azurecore/src/test/azureResource/resourceService.test.ts index b8f10817a5..898ffe4670 100644 --- a/extensions/azurecore/src/test/azureResource/resourceService.test.ts +++ b/extensions/azurecore/src/test/azureResource/resourceService.test.ts @@ -43,7 +43,7 @@ let mockResourceProvider1: TypeMoq.IMock; let mockResourceTreeDataProvider2: TypeMoq.IMock; let mockResourceProvider2: TypeMoq.IMock; -const resourceService: AzureResourceService = AzureResourceService.getInstance(); +let resourceService: AzureResourceService; describe('AzureResourceService.listResourceProviderIds', function(): void { beforeEach(() => { @@ -61,6 +61,7 @@ describe('AzureResourceService.listResourceProviderIds', function(): void { mockResourceProvider2.setup((o) => o.providerId).returns(() => 'mockResourceProvider2'); mockResourceProvider2.setup((o) => o.getTreeDataProvider()).returns(() => mockResourceTreeDataProvider2.object); + resourceService = new AzureResourceService(); resourceService.clearResourceProviders(); resourceService.areResourceProvidersLoaded = true; }); diff --git a/extensions/azurecore/src/test/azureResource/resourceTreeNode.test.ts b/extensions/azurecore/src/test/azureResource/resourceTreeNode.test.ts index b73f0a2368..8e75f7b1ca 100644 --- a/extensions/azurecore/src/test/azureResource/resourceTreeNode.test.ts +++ b/extensions/azurecore/src/test/azureResource/resourceTreeNode.test.ts @@ -14,8 +14,9 @@ import 'mocha'; import { azureResource } from '../../azureResource/azure-resource'; import { AzureResourceService } from '../../azureResource/resourceService'; import { AzureResourceResourceTreeNode } from '../../azureResource/resourceTreeNode'; - -const resourceService = AzureResourceService.getInstance(); +import { AppContext } from '../../appContext'; +import { ApiWrapper } from '../../apiWrapper'; +import { AzureResourceServiceNames } from '../../azureResource/constants'; // Mock test data const mockAccount: azdata.Account = { @@ -85,6 +86,8 @@ const mockResourceNodes: azureResource.IAzureResourceNode[] = [mockResourceNode1 let mockResourceTreeDataProvider: TypeMoq.IMock; let mockResourceProvider: TypeMoq.IMock; +let resourceService: AzureResourceService; +let appContext: AppContext; describe('AzureResourceResourceTreeNode.info', function(): void { beforeEach(() => { @@ -95,18 +98,20 @@ describe('AzureResourceResourceTreeNode.info', function(): void { mockResourceProvider = TypeMoq.Mock.ofType(); mockResourceProvider.setup((o) => o.providerId).returns(() => mockResourceProviderId); mockResourceProvider.setup((o) => o.getTreeDataProvider()).returns(() => mockResourceTreeDataProvider.object); - + resourceService = new AzureResourceService(); resourceService.clearResourceProviders(); resourceService.registerResourceProvider(mockResourceProvider.object); - resourceService.areResourceProvidersLoaded = true; + + appContext = new AppContext(undefined, new ApiWrapper()); + appContext.registerService(AzureResourceServiceNames.resourceService, resourceService); }); it('Should be correct when created.', async function(): Promise { const resourceTreeNode = new AzureResourceResourceTreeNode({ resourceProviderId: mockResourceProviderId, resourceNode: mockResourceRootNode - }, undefined); + }, undefined, appContext); should(resourceTreeNode.nodePathValue).equal(mockResourceRootNode.treeItem.id); @@ -133,17 +138,21 @@ describe('AzureResourceResourceTreeNode.getChildren', function(): void { mockResourceProvider.setup((o) => o.providerId).returns(() => mockResourceProviderId); mockResourceProvider.setup((o) => o.getTreeDataProvider()).returns(() => mockResourceTreeDataProvider.object); + resourceService = new AzureResourceService(); resourceService.clearResourceProviders(); resourceService.registerResourceProvider(mockResourceProvider.object); - resourceService.areResourceProvidersLoaded = true; + + appContext = new AppContext(undefined, new ApiWrapper()); + appContext.registerService(AzureResourceServiceNames.resourceService, resourceService); }); it('Should return resource nodes when it is container node.', async function(): Promise { const resourceTreeNode = new AzureResourceResourceTreeNode({ resourceProviderId: mockResourceProviderId, resourceNode: mockResourceRootNode - }, undefined); + }, + undefined, appContext); const children = await resourceTreeNode.getChildren(); @@ -173,7 +182,7 @@ describe('AzureResourceResourceTreeNode.getChildren', function(): void { const resourceTreeNode = new AzureResourceResourceTreeNode({ resourceProviderId: mockResourceProviderId, resourceNode: mockResourceNode1 - }, undefined); + }, undefined, appContext); const children = await resourceTreeNode.getChildren(); diff --git a/extensions/azurecore/src/test/azureResource/tree/subscriptionTreeNode.test.ts b/extensions/azurecore/src/test/azureResource/tree/subscriptionTreeNode.test.ts index 84c9236220..d0df58fbdb 100644 --- a/extensions/azurecore/src/test/azureResource/tree/subscriptionTreeNode.test.ts +++ b/extensions/azurecore/src/test/azureResource/tree/subscriptionTreeNode.test.ts @@ -23,7 +23,7 @@ import { IAzureResourceCacheService } from '../../../azureResource/interfaces'; import { generateGuid } from '../../../azureResource/utils'; // Mock services -let mockAppContext: AppContext; +let appContext: AppContext; let mockExtensionContext: TypeMoq.IMock; let mockApiWrapper: TypeMoq.IMock; @@ -60,7 +60,7 @@ let mockResourceProvider1: TypeMoq.IMock; let mockResourceTreeDataProvider2: TypeMoq.IMock; let mockResourceProvider2: TypeMoq.IMock; -const resourceService: AzureResourceService = AzureResourceService.getInstance(); +const resourceService: AzureResourceService = new AzureResourceService(); describe('AzureResourceSubscriptionTreeNode.info', function(): void { beforeEach(() => { @@ -68,10 +68,6 @@ describe('AzureResourceSubscriptionTreeNode.info', function(): void { mockApiWrapper = TypeMoq.Mock.ofType(); mockCacheService = TypeMoq.Mock.ofType(); - mockAppContext = new AppContext(mockExtensionContext.object, mockApiWrapper.object); - - mockAppContext.registerService(AzureResourceServiceNames.cacheService, mockCacheService.object); - mockCacheService.setup((o) => o.generateKey(TypeMoq.It.isAnyString())).returns(() => generateGuid()); mockTreeChangeHandler = TypeMoq.Mock.ofType(); @@ -93,12 +89,16 @@ describe('AzureResourceSubscriptionTreeNode.info', function(): void { resourceService.clearResourceProviders(); resourceService.registerResourceProvider(mockResourceProvider1.object); resourceService.registerResourceProvider(mockResourceProvider2.object); - resourceService.areResourceProvidersLoaded = true; + + appContext = new AppContext(mockExtensionContext.object, mockApiWrapper.object); + appContext.registerService(AzureResourceServiceNames.cacheService, mockCacheService.object); + appContext.registerService(AzureResourceServiceNames.resourceService, resourceService); + }); it('Should be correct when created.', async function(): Promise { - const subscriptionTreeNode = new AzureResourceSubscriptionTreeNode(mockAccount, mockSubscription, mockTenantId, mockAppContext, mockTreeChangeHandler.object, undefined); + const subscriptionTreeNode = new AzureResourceSubscriptionTreeNode(mockAccount, mockSubscription, mockTenantId, appContext, mockTreeChangeHandler.object, undefined); should(subscriptionTreeNode.nodePathValue).equal(`account_${mockAccount.key.accountId}.subscription_${mockSubscription.id}.tenant_${mockTenantId}`); @@ -121,9 +121,6 @@ describe('AzureResourceSubscriptionTreeNode.getChildren', function(): void { mockApiWrapper = TypeMoq.Mock.ofType(); mockCacheService = TypeMoq.Mock.ofType(); - mockAppContext = new AppContext(mockExtensionContext.object, mockApiWrapper.object); - mockAppContext.registerService(AzureResourceServiceNames.cacheService, mockCacheService.object); - mockCacheService.setup((o) => o.generateKey(TypeMoq.It.isAnyString())).returns(() => generateGuid()); mockTreeChangeHandler = TypeMoq.Mock.ofType(); @@ -145,12 +142,16 @@ describe('AzureResourceSubscriptionTreeNode.getChildren', function(): void { resourceService.clearResourceProviders(); resourceService.registerResourceProvider(mockResourceProvider1.object); resourceService.registerResourceProvider(mockResourceProvider2.object); - resourceService.areResourceProvidersLoaded = true; + + appContext = new AppContext(mockExtensionContext.object, mockApiWrapper.object); + appContext.registerService(AzureResourceServiceNames.cacheService, mockCacheService.object); + appContext.registerService(AzureResourceServiceNames.resourceService, resourceService); + }); it('Should return resource containers.', async function(): Promise { - const subscriptionTreeNode = new AzureResourceSubscriptionTreeNode(mockAccount, mockSubscription, mockTenantId, mockAppContext, mockTreeChangeHandler.object, undefined); + const subscriptionTreeNode = new AzureResourceSubscriptionTreeNode(mockAccount, mockSubscription, mockTenantId, appContext, mockTreeChangeHandler.object, undefined); const children = await subscriptionTreeNode.getChildren(); mockResourceTreeDataProvider1.verify((o) => o.getChildren(), TypeMoq.Times.once());