Remove AzureCore ApiWrapper (#11335)

This commit is contained in:
Charles Gagnon
2020-07-13 18:11:54 -07:00
committed by GitHub
parent 9e6056968b
commit cbf3cd7445
30 changed files with 246 additions and 439 deletions

View File

@@ -276,11 +276,13 @@
"@types/node": "^12.11.7", "@types/node": "^12.11.7",
"@types/qs": "^6.9.1", "@types/qs": "^6.9.1",
"@types/request": "^2.48.1", "@types/request": "^2.48.1",
"@types/sinon": "^9.0.4",
"@types/ws": "^6.0.4", "@types/ws": "^6.0.4",
"mocha": "^5.2.0", "mocha": "^5.2.0",
"mocha-junit-reporter": "^1.17.0", "mocha-junit-reporter": "^1.17.0",
"mocha-multi-reporters": "^1.1.7", "mocha-multi-reporters": "^1.1.7",
"should": "^13.2.1", "should": "^13.2.1",
"sinon": "^9.0.2",
"typemoq": "^2.1.0", "typemoq": "^2.1.0",
"vscodetestcover": "^1.0.9" "vscodetestcover": "^1.0.9"
} }

View File

@@ -1,220 +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 * as vscode from 'vscode';
import * as azdata from 'azdata';
import * as constants from './constants';
/**
* Wrapper class to act as a facade over VSCode and Data APIs and allow us to test / mock callbacks into
* this API from our code
*
* @export
*/
export class ApiWrapper {
// Data APIs
public registerConnectionProvider(provider: azdata.ConnectionProvider): vscode.Disposable {
return azdata.dataprotocol.registerConnectionProvider(provider);
}
public registerObjectExplorerProvider(provider: azdata.ObjectExplorerProvider): vscode.Disposable {
return azdata.dataprotocol.registerObjectExplorerProvider(provider);
}
public registerTaskServicesProvider(provider: azdata.TaskServicesProvider): vscode.Disposable {
return azdata.dataprotocol.registerTaskServicesProvider(provider);
}
public registerFileBrowserProvider(provider: azdata.FileBrowserProvider): vscode.Disposable {
return azdata.dataprotocol.registerFileBrowserProvider(provider);
}
public registerCapabilitiesServiceProvider(provider: azdata.CapabilitiesProvider): vscode.Disposable {
return azdata.dataprotocol.registerCapabilitiesServiceProvider(provider);
}
public registerModelViewProvider(widgetId: string, handler: (modelView: azdata.ModelView) => void): void {
return azdata.ui.registerModelViewProvider(widgetId, handler);
}
public registerWebviewProvider(widgetId: string, handler: (webview: azdata.DashboardWebview) => void): void {
return azdata.dashboard.registerWebviewProvider(widgetId, handler);
}
public createDialog(title: string): azdata.window.Dialog {
return azdata.window.createModelViewDialog(title);
}
public openDialog(dialog: azdata.window.Dialog): void {
return azdata.window.openDialog(dialog);
}
public closeDialog(dialog: azdata.window.Dialog): void {
return azdata.window.closeDialog(dialog);
}
public registerTaskHandler(taskId: string, handler: (profile: azdata.IConnectionProfile) => void): void {
azdata.tasks.registerTask(taskId, handler);
}
public startBackgroundOperation(operationInfo: azdata.BackgroundOperationInfo): void {
azdata.tasks.startBackgroundOperation(operationInfo);
}
public getActiveConnections(): Thenable<azdata.connection.Connection[]> {
return azdata.connection.getActiveConnections();
}
public getCurrentConnection(): Thenable<azdata.connection.ConnectionProfile> {
return azdata.connection.getCurrentConnection();
}
public createModelViewEditor(title: string, options?: azdata.ModelViewEditorOptions): azdata.workspace.ModelViewEditor {
return azdata.workspace.createModelViewEditor(title, options);
}
// VSCode APIs
public createTerminal(name?: string, shellPath?: string, shellArgs?: string[]): vscode.Terminal {
return vscode.window.createTerminal(name, shellPath, shellArgs);
}
public createTerminalWithOptions(options: vscode.TerminalOptions): vscode.Terminal {
return vscode.window.createTerminal(options);
}
public executeCommand(command: string, ...rest: any[]): Thenable<any> {
return vscode.commands.executeCommand(command, ...rest);
}
public getFilePathRelativeToWorkspace(uri: vscode.Uri): string {
return vscode.workspace.asRelativePath(uri);
}
public getWorkspaceFolders(): readonly vscode.WorkspaceFolder[] {
return vscode.workspace.workspaceFolders;
}
public getWorkspacePathFromUri(uri: vscode.Uri): string | undefined {
let workspaceFolder = vscode.workspace.getWorkspaceFolder(uri);
return workspaceFolder ? workspaceFolder.uri.fsPath : undefined;
}
public registerCommand(command: string, callback: (...args: any[]) => any, thisArg?: any): vscode.Disposable {
return vscode.commands.registerCommand(command, callback, thisArg);
}
public registerDocumentOpenHandler(handler: (doc: vscode.TextDocument) => any): vscode.Disposable {
return vscode.workspace.onDidOpenTextDocument(handler);
}
public registerTreeDataProvider<T>(viewId: string, treeDataProvider: vscode.TreeDataProvider<T>): vscode.Disposable {
return vscode.window.registerTreeDataProvider(viewId, treeDataProvider);
}
public setCommandContext(key: string, value: any): Thenable<any> {
return vscode.commands.executeCommand(constants.BuiltInCommands.SetContext, key, value);
}
/**
* Get the configuration for a extensionName
* @param extensionName The string name of the extension to get the configuration for
* @param resource The optional URI, as a URI object or a string, to use to get resource-scoped configurations
*/
public getConfiguration(extensionName?: string, resource?: vscode.Uri | string): vscode.WorkspaceConfiguration {
if (typeof resource === 'string') {
try {
resource = this.parseUri(resource);
} catch (e) {
resource = undefined;
}
}
return vscode.workspace.getConfiguration(extensionName, resource as vscode.Uri);
}
public getExtensionConfiguration(): vscode.WorkspaceConfiguration {
return this.getConfiguration(constants.extensionConfigSectionName);
}
public get onDidChangeConfiguration(): vscode.Event<vscode.ConfigurationChangeEvent> {
return vscode.workspace.onDidChangeConfiguration;
}
/**
* Parse uri
*/
public parseUri(uri: string): vscode.Uri {
return vscode.Uri.parse(uri);
}
public showOpenDialog(options: vscode.OpenDialogOptions): Thenable<vscode.Uri[] | undefined> {
return vscode.window.showOpenDialog(options);
}
public showSaveDialog(options: vscode.SaveDialogOptions): Thenable<vscode.Uri> {
return vscode.window.showSaveDialog(options);
}
public showTextDocument(document: vscode.TextDocument, column?: vscode.ViewColumn, preserveFocus?: boolean, preview?: boolean): Thenable<vscode.TextEditor> {
let options: vscode.TextDocumentShowOptions = {
viewColumn: column,
preserveFocus: preserveFocus,
preview: preview
};
return vscode.window.showTextDocument(document, options);
}
public showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined> {
return vscode.window.showErrorMessage(message, ...items);
}
public showWarningMessage(message: string, ...items: string[]): Thenable<string | undefined> {
return vscode.window.showWarningMessage(message, ...items);
}
public showInformationMessage(message: string, ...items: string[]): Thenable<string | undefined> {
return vscode.window.showInformationMessage(message, ...items);
}
public createStatusBarItem(alignment?: vscode.StatusBarAlignment, priority?: number): vscode.StatusBarItem {
return vscode.window.createStatusBarItem(alignment, priority);
}
public get workspaceFolders(): readonly vscode.WorkspaceFolder[] {
return vscode.workspace.workspaceFolders;
}
public createOutputChannel(name: string): vscode.OutputChannel {
return vscode.window.createOutputChannel(name);
}
public createWizardPage(title: string): azdata.window.WizardPage {
return azdata.window.createWizardPage(title);
}
public registerCompletionItemProvider(selector: vscode.DocumentSelector, provider: vscode.CompletionItemProvider, ...triggerCharacters: string[]): vscode.Disposable {
return vscode.languages.registerCompletionItemProvider(selector, provider, ...triggerCharacters);
}
public createTab(title: string): azdata.window.DialogTab {
return azdata.window.createTab(title);
}
// Account APIs
public getAllAccounts(): Thenable<azdata.Account[]> {
return azdata.accounts.getAllAccounts();
}
public getSecurityToken(account: azdata.Account, resource: azdata.AzureResource): Thenable<{ [key: string]: any }> {
return azdata.accounts.getSecurityToken(account, resource);
}
public readonly onDidChangeAccounts = azdata.accounts.onDidChangeAccounts;
// Connection APIs
public openConnectionDialog(providers: string[], initialConnectionProfile?: azdata.IConnectionProfile, connectionCompletionOptions?: azdata.IConnectionCompletionOptions): Thenable<azdata.connection.Connection> {
return azdata.connection.openConnectionDialog(providers, initialConnectionProfile, connectionCompletionOptions);
}
}

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { ApiWrapper } from './apiWrapper';
/** /**
* Global context for the application * Global context for the application
@@ -12,9 +11,7 @@ import { ApiWrapper } from './apiWrapper';
export class AppContext { export class AppContext {
private serviceMap: Map<string, any> = new Map(); private serviceMap: Map<string, any> = new Map();
constructor(public readonly extensionContext: vscode.ExtensionContext, public readonly apiWrapper: ApiWrapper) { constructor(public readonly extensionContext: vscode.ExtensionContext) { }
this.apiWrapper = apiWrapper || new ApiWrapper();
}
public getService<T>(serviceName: string): T { public getService<T>(serviceName: string): T {
return this.serviceMap.get(serviceName) as T; return this.serviceMap.get(serviceName) as T;

View File

@@ -3,9 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { window, QuickPickItem, env, Uri } from 'vscode';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { TokenCredentials } from '@azure/ms-rest-js'; import { TokenCredentials } from '@azure/ms-rest-js';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
@@ -21,12 +20,12 @@ import { AzureResourceServiceNames } from './constants';
import { AzureAccount, Tenant } from '../account-provider/interfaces'; import { AzureAccount, Tenant } from '../account-provider/interfaces';
export function registerAzureResourceCommands(appContext: AppContext, tree: AzureResourceTreeProvider): void { export function registerAzureResourceCommands(appContext: AppContext, tree: AzureResourceTreeProvider): void {
appContext.apiWrapper.registerCommand('azure.resource.startterminal', async (node?: TreeNode) => { vscode.commands.registerCommand('azure.resource.startterminal', async (node?: TreeNode) => {
try { try {
const enablePreviewFeatures = appContext.apiWrapper.getConfiguration('workbench').get('enablePreviewFeatures'); const enablePreviewFeatures = vscode.workspace.getConfiguration('workbench').get('enablePreviewFeatures');
if (!enablePreviewFeatures) { if (!enablePreviewFeatures) {
const msg = localize('azure.cloudTerminalPreview', "You must enable preview features in order to use Azure Cloud Shell."); const msg = localize('azure.cloudTerminalPreview', "You must enable preview features in order to use Azure Cloud Shell.");
appContext.apiWrapper.showInformationMessage(msg); vscode.window.showInformationMessage(msg);
return; return;
} }
if (!node || !(node instanceof AzureResourceAccountTreeNode)) { if (!node || !(node instanceof AzureResourceAccountTreeNode)) {
@@ -36,28 +35,28 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
const accountNode = node as AzureResourceAccountTreeNode; const accountNode = node as AzureResourceAccountTreeNode;
const azureAccount = accountNode.account as AzureAccount; const azureAccount = accountNode.account as AzureAccount;
const tokens = await appContext.apiWrapper.getSecurityToken(azureAccount, azdata.AzureResource.MicrosoftResourceManagement); const tokens = await azdata.accounts.getSecurityToken(azureAccount, azdata.AzureResource.MicrosoftResourceManagement);
const terminalService = appContext.getService<IAzureTerminalService>(AzureResourceServiceNames.terminalService); const terminalService = appContext.getService<IAzureTerminalService>(AzureResourceServiceNames.terminalService);
const listOfTenants = azureAccount.properties.tenants.map(t => t.displayName); const listOfTenants = azureAccount.properties.tenants.map(t => t.displayName);
if (listOfTenants.length === 0) { if (listOfTenants.length === 0) {
window.showErrorMessage(localize('azure.noTenants', "A tenant is required for this feature. Your Azure subscription seems to have no tenants.")); vscode.window.showErrorMessage(localize('azure.noTenants', "A tenant is required for this feature. Your Azure subscription seems to have no tenants."));
return; return;
} }
let tenant: Tenant; let tenant: Tenant;
window.setStatusBarMessage(localize('azure.startingCloudShell', "Starting cloud shell…"), 5000); vscode.window.setStatusBarMessage(localize('azure.startingCloudShell', "Starting cloud shell…"), 5000);
if (listOfTenants.length === 1) { if (listOfTenants.length === 1) {
// Don't show quickpick for a single option // Don't show quickpick for a single option
tenant = azureAccount.properties.tenants[0]; tenant = azureAccount.properties.tenants[0];
} else { } else {
const pickedTenant = await window.showQuickPick(listOfTenants, { canPickMany: false }); const pickedTenant = await vscode.window.showQuickPick(listOfTenants, { canPickMany: false });
if (!pickedTenant) { if (!pickedTenant) {
window.showErrorMessage(localize('azure.mustPickTenant', "You must select a tenant for this feature to work.")); vscode.window.showErrorMessage(localize('azure.mustPickTenant', "You must select a tenant for this feature to work."));
return; return;
} }
@@ -68,13 +67,13 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
await terminalService.getOrCreateCloudConsole(azureAccount, tenant, tokens); await terminalService.getOrCreateCloudConsole(azureAccount, tenant, tokens);
} catch (ex) { } catch (ex) {
console.error(ex); console.error(ex);
window.showErrorMessage(ex); vscode.window.showErrorMessage(ex);
} }
}); });
// Resource Tree commands // Resource Tree commands
appContext.apiWrapper.registerCommand('azure.resource.selectsubscriptions', async (node?: TreeNode) => { vscode.commands.registerCommand('azure.resource.selectsubscriptions', async (node?: TreeNode) => {
if (!(node instanceof AzureResourceAccountTreeNode)) { if (!(node instanceof AzureResourceAccountTreeNode)) {
return; return;
} }
@@ -92,7 +91,7 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
const subscriptions = (await accountNode.getCachedSubscriptions()) || <azureResource.AzureResourceSubscription[]>[]; const subscriptions = (await accountNode.getCachedSubscriptions()) || <azureResource.AzureResourceSubscription[]>[];
if (subscriptions.length === 0) { if (subscriptions.length === 0) {
try { try {
const tokens = await this.servicePool.apiWrapper.getSecurityToken(account, azdata.AzureResource.ResourceManagement); const tokens = await azdata.accounts.getSecurityToken(account, azdata.AzureResource.ResourceManagement);
for (const tenant of account.properties.tenants) { for (const tenant of account.properties.tenants) {
const token = tokens[tenant.id].token; const token = tokens[tenant.id].token;
@@ -119,7 +118,7 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
selectedSubscriptionIds.push(...subscriptions.map((subscription) => subscription.id)); selectedSubscriptionIds.push(...subscriptions.map((subscription) => subscription.id));
} }
interface AzureResourceSubscriptionQuickPickItem extends QuickPickItem { interface AzureResourceSubscriptionQuickPickItem extends vscode.QuickPickItem {
subscription: azureResource.AzureResourceSubscription; subscription: azureResource.AzureResourceSubscription;
} }
@@ -131,7 +130,7 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
}; };
}).sort((a, b) => a.label.localeCompare(b.label)); }).sort((a, b) => a.label.localeCompare(b.label));
const selectedSubscriptionQuickPickItems = await window.showQuickPick(subscriptionQuickPickItems, { canPickMany: true }); const selectedSubscriptionQuickPickItems = await vscode.window.showQuickPick(subscriptionQuickPickItems, { canPickMany: true });
if (selectedSubscriptionQuickPickItems && selectedSubscriptionQuickPickItems.length > 0) { if (selectedSubscriptionQuickPickItems && selectedSubscriptionQuickPickItems.length > 0) {
await tree.refresh(node, false); await tree.refresh(node, false);
@@ -140,17 +139,17 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
} }
}); });
appContext.apiWrapper.registerCommand('azure.resource.refreshall', () => tree.notifyNodeChanged(undefined)); vscode.commands.registerCommand('azure.resource.refreshall', () => tree.notifyNodeChanged(undefined));
appContext.apiWrapper.registerCommand('azure.resource.refresh', async (node?: TreeNode) => { vscode.commands.registerCommand('azure.resource.refresh', async (node?: TreeNode) => {
await tree.refresh(node, true); await tree.refresh(node, true);
}); });
appContext.apiWrapper.registerCommand('azure.resource.signin', async (node?: TreeNode) => { vscode.commands.registerCommand('azure.resource.signin', async (node?: TreeNode) => {
appContext.apiWrapper.executeCommand('workbench.actions.modal.linkedAccount'); vscode.commands.executeCommand('workbench.actions.modal.linkedAccount');
}); });
appContext.apiWrapper.registerCommand('azure.resource.connectsqlserver', async (node?: TreeNode) => { vscode.commands.registerCommand('azure.resource.connectsqlserver', async (node?: TreeNode) => {
if (!node) { if (!node) {
return; return;
} }
@@ -161,13 +160,13 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
} }
// Ensure connection is saved to the Connections list, then open connection dialog // Ensure connection is saved to the Connections list, then open connection dialog
let connectionProfile = Object.assign({}, treeItem.payload, { saveProfile: true }); let connectionProfile = Object.assign({}, treeItem.payload, { saveProfile: true });
const conn = await appContext.apiWrapper.openConnectionDialog(undefined, connectionProfile, { saveConnection: true, showDashboard: true }); const conn = await azdata.connection.openConnectionDialog(undefined, connectionProfile, { saveConnection: true, showDashboard: true });
if (conn) { if (conn) {
appContext.apiWrapper.executeCommand('workbench.view.connections'); vscode.commands.executeCommand('workbench.view.connections');
} }
}); });
appContext.apiWrapper.registerCommand('azure.resource.openInAzurePortal', async (connectionProfile: azdata.IConnectionProfile) => { vscode.commands.registerCommand('azure.resource.openInAzurePortal', async (connectionProfile: azdata.IConnectionProfile) => {
if ( if (
!connectionProfile.azureResourceId || !connectionProfile.azureResourceId ||
@@ -178,6 +177,6 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
} }
const urlToOpen = `${connectionProfile.azurePortalEndpoint}//${connectionProfile.azureTenantId}/#resource/${connectionProfile.azureResourceId}`; const urlToOpen = `${connectionProfile.azurePortalEndpoint}//${connectionProfile.azureTenantId}/#resource/${connectionProfile.azureResourceId}`;
env.openExternal(Uri.parse(urlToOpen)); vscode.env.openExternal(vscode.Uri.parse(urlToOpen));
}); });
} }

View File

@@ -5,17 +5,11 @@
import * as msRest from '@azure/ms-rest-js'; import * as msRest from '@azure/ms-rest-js';
import { Account, DidChangeAccountsParams } from 'azdata'; import { Account } from 'azdata';
import { Event } from 'vscode';
import { azureResource } from './azure-resource'; import { azureResource } from './azure-resource';
import { AzureAccount, AzureAccountSecurityToken, Tenant } from '../account-provider/interfaces'; import { AzureAccount, AzureAccountSecurityToken, Tenant } from '../account-provider/interfaces';
export interface IAzureResourceAccountService {
getAccounts(): Promise<Account[]>;
readonly onDidChangeAccounts: Event<DidChangeAccountsParams>;
}
export interface IAzureResourceSubscriptionService { export interface IAzureResourceSubscriptionService {
getSubscriptions(account: Account, credential: msRest.ServiceClientCredentials): Promise<azureResource.AzureResourceSubscription[]>; getSubscriptions(account: Account, credential: msRest.ServiceClientCredentials): Promise<azureResource.AzureResourceSubscription[]>;
} }

View File

@@ -5,7 +5,6 @@
import { ExtensionContext } from 'vscode'; import { ExtensionContext } from 'vscode';
import { ApiWrapper } from '../../../apiWrapper';
import { azureResource } from '../../azure-resource'; import { azureResource } from '../../azure-resource';
import { AzureResourceDatabaseTreeDataProvider } from './databaseTreeDataProvider'; import { AzureResourceDatabaseTreeDataProvider } from './databaseTreeDataProvider';
@@ -14,13 +13,12 @@ import { IAzureResourceService } from '../../interfaces';
export class AzureResourceDatabaseProvider implements azureResource.IAzureResourceProvider { export class AzureResourceDatabaseProvider implements azureResource.IAzureResourceProvider {
public constructor( public constructor(
private _databaseService: IAzureResourceService<azureResource.AzureResourceDatabase>, private _databaseService: IAzureResourceService<azureResource.AzureResourceDatabase>,
private _apiWrapper: ApiWrapper,
private _extensionContext: ExtensionContext private _extensionContext: ExtensionContext
) { ) {
} }
public getTreeDataProvider(): azureResource.IAzureResourceTreeDataProvider { public getTreeDataProvider(): azureResource.IAzureResourceTreeDataProvider {
return new AzureResourceDatabaseTreeDataProvider(this._databaseService, this._apiWrapper, this._extensionContext); return new AzureResourceDatabaseTreeDataProvider(this._databaseService, this._extensionContext);
} }
public get providerId(): string { public get providerId(): string {

View File

@@ -10,7 +10,6 @@ const localize = nls.loadMessageBundle();
import { azureResource } from '../../azure-resource'; import { azureResource } from '../../azure-resource';
import { AzureResourceItemType } from '../../../azureResource/constants'; import { AzureResourceItemType } from '../../../azureResource/constants';
import { ApiWrapper } from '../../../apiWrapper';
import { generateGuid } from '../../utils'; import { generateGuid } from '../../utils';
import { IAzureResourceService } from '../../interfaces'; import { IAzureResourceService } from '../../interfaces';
import { ResourceTreeDataProviderBase } from '../resourceTreeDataProviderBase'; import { ResourceTreeDataProviderBase } from '../resourceTreeDataProviderBase';
@@ -22,10 +21,9 @@ export class AzureResourceDatabaseTreeDataProvider extends ResourceTreeDataProvi
public constructor( public constructor(
databaseService: IAzureResourceService<azureResource.AzureResourceDatabase>, databaseService: IAzureResourceService<azureResource.AzureResourceDatabase>,
apiWrapper: ApiWrapper,
private _extensionContext: ExtensionContext private _extensionContext: ExtensionContext
) { ) {
super(databaseService, apiWrapper); super(databaseService);
} }
protected getTreeItemForResource(database: azureResource.AzureResourceDatabase, account: Account): TreeItem { protected getTreeItemForResource(database: azureResource.AzureResourceDatabase, account: Account): TreeItem {
return { return {

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { ExtensionContext } from 'vscode'; import { ExtensionContext } from 'vscode';
import { ApiWrapper } from '../../../apiWrapper';
import { azureResource } from '../../azure-resource'; import { azureResource } from '../../azure-resource';
import { IAzureResourceService } from '../../interfaces'; import { IAzureResourceService } from '../../interfaces';
@@ -13,13 +12,12 @@ import { AzureResourceDatabaseServerTreeDataProvider } from './databaseServerTre
export class AzureResourceDatabaseServerProvider implements azureResource.IAzureResourceProvider { export class AzureResourceDatabaseServerProvider implements azureResource.IAzureResourceProvider {
public constructor( public constructor(
private _databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>, private _databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>,
private _apiWrapper: ApiWrapper,
private _extensionContext: ExtensionContext private _extensionContext: ExtensionContext
) { ) {
} }
public getTreeDataProvider(): azureResource.IAzureResourceTreeDataProvider { public getTreeDataProvider(): azureResource.IAzureResourceTreeDataProvider {
return new AzureResourceDatabaseServerTreeDataProvider(this._databaseServerService, this._apiWrapper, this._extensionContext); return new AzureResourceDatabaseServerTreeDataProvider(this._databaseServerService, this._extensionContext);
} }
public get providerId(): string { public get providerId(): string {

View File

@@ -9,7 +9,6 @@ import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
import { AzureResourceItemType } from '../../../azureResource/constants'; import { AzureResourceItemType } from '../../../azureResource/constants';
import { ApiWrapper } from '../../../apiWrapper';
import { generateGuid } from '../../utils'; import { generateGuid } from '../../utils';
import { IAzureResourceService } from '../../interfaces'; import { IAzureResourceService } from '../../interfaces';
import { ResourceTreeDataProviderBase } from '../resourceTreeDataProviderBase'; import { ResourceTreeDataProviderBase } from '../resourceTreeDataProviderBase';
@@ -21,10 +20,9 @@ export class AzureResourceDatabaseServerTreeDataProvider extends ResourceTreeDat
public constructor( public constructor(
databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>, databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>,
apiWrapper: ApiWrapper,
private _extensionContext: ExtensionContext private _extensionContext: ExtensionContext
) { ) {
super(databaseServerService, apiWrapper); super(databaseServerService);
} }

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { ExtensionContext } from 'vscode'; import { ExtensionContext } from 'vscode';
import { ApiWrapper } from '../../../apiWrapper';
import { azureResource } from '../../azure-resource'; import { azureResource } from '../../azure-resource';
import { IAzureResourceService } from '../../interfaces'; import { IAzureResourceService } from '../../interfaces';
@@ -13,13 +12,12 @@ import { PostgresServerArcTreeDataProvider as PostgresServerArcTreeDataProvider
export class PostgresServerArcProvider implements azureResource.IAzureResourceProvider { export class PostgresServerArcProvider implements azureResource.IAzureResourceProvider {
public constructor( public constructor(
private _databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>, private _databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>,
private _apiWrapper: ApiWrapper,
private _extensionContext: ExtensionContext private _extensionContext: ExtensionContext
) { ) {
} }
public getTreeDataProvider(): azureResource.IAzureResourceTreeDataProvider { public getTreeDataProvider(): azureResource.IAzureResourceTreeDataProvider {
return new PostgresServerArcTreeDataProvider(this._databaseServerService, this._apiWrapper, this._extensionContext); return new PostgresServerArcTreeDataProvider(this._databaseServerService, this._extensionContext);
} }
public get providerId(): string { public get providerId(): string {

View File

@@ -9,7 +9,6 @@ import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
import { AzureResourceItemType } from '../../constants'; import { AzureResourceItemType } from '../../constants';
import { ApiWrapper } from '../../../apiWrapper';
import { generateGuid } from '../../utils'; import { generateGuid } from '../../utils';
import { IAzureResourceService } from '../../interfaces'; import { IAzureResourceService } from '../../interfaces';
import { ResourceTreeDataProviderBase } from '../resourceTreeDataProviderBase'; import { ResourceTreeDataProviderBase } from '../resourceTreeDataProviderBase';
@@ -21,10 +20,9 @@ export class PostgresServerArcTreeDataProvider extends ResourceTreeDataProviderB
public constructor( public constructor(
databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>, databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>,
apiWrapper: ApiWrapper,
private _extensionContext: ExtensionContext private _extensionContext: ExtensionContext
) { ) {
super(databaseServerService, apiWrapper); super(databaseServerService);
} }

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { ExtensionContext } from 'vscode'; import { ExtensionContext } from 'vscode';
import { ApiWrapper } from '../../../apiWrapper';
import { azureResource } from '../../azure-resource'; import { azureResource } from '../../azure-resource';
import { IAzureResourceService } from '../../interfaces'; import { IAzureResourceService } from '../../interfaces';
@@ -13,13 +12,12 @@ import { PostgresServerTreeDataProvider as PostgresServerTreeDataProvider } from
export class PostgresServerProvider implements azureResource.IAzureResourceProvider { export class PostgresServerProvider implements azureResource.IAzureResourceProvider {
public constructor( public constructor(
private _databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>, private _databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>,
private _apiWrapper: ApiWrapper,
private _extensionContext: ExtensionContext private _extensionContext: ExtensionContext
) { ) {
} }
public getTreeDataProvider(): azureResource.IAzureResourceTreeDataProvider { public getTreeDataProvider(): azureResource.IAzureResourceTreeDataProvider {
return new PostgresServerTreeDataProvider(this._databaseServerService, this._apiWrapper, this._extensionContext); return new PostgresServerTreeDataProvider(this._databaseServerService, this._extensionContext);
} }
public get providerId(): string { public get providerId(): string {

View File

@@ -9,7 +9,6 @@ import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
import { AzureResourceItemType } from '../../constants'; import { AzureResourceItemType } from '../../constants';
import { ApiWrapper } from '../../../apiWrapper';
import { generateGuid } from '../../utils'; import { generateGuid } from '../../utils';
import { IAzureResourceService } from '../../interfaces'; import { IAzureResourceService } from '../../interfaces';
import { ResourceTreeDataProviderBase } from '../resourceTreeDataProviderBase'; import { ResourceTreeDataProviderBase } from '../resourceTreeDataProviderBase';
@@ -21,10 +20,9 @@ export class PostgresServerTreeDataProvider extends ResourceTreeDataProviderBase
public constructor( public constructor(
databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>, databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>,
apiWrapper: ApiWrapper,
private _extensionContext: ExtensionContext private _extensionContext: ExtensionContext
) { ) {
super(databaseServerService, apiWrapper); super(databaseServerService);
} }

View File

@@ -7,17 +7,13 @@ import * as azdata from 'azdata';
import * as msRest from '@azure/ms-rest-js'; import * as msRest from '@azure/ms-rest-js';
import { azureResource } from '../azure-resource'; import { azureResource } from '../azure-resource';
import { ApiWrapper } from '../../apiWrapper';
import { IAzureResourceService } from '../interfaces'; import { IAzureResourceService } from '../interfaces';
import { AzureResourceErrorMessageUtil } from '../utils'; import { AzureResourceErrorMessageUtil } from '../utils';
import { ResourceGraphClient } from '@azure/arm-resourcegraph'; import { ResourceGraphClient } from '@azure/arm-resourcegraph';
export abstract class ResourceTreeDataProviderBase<T extends azureResource.AzureResource> implements azureResource.IAzureResourceTreeDataProvider { export abstract class ResourceTreeDataProviderBase<T extends azureResource.AzureResource> implements azureResource.IAzureResourceTreeDataProvider {
public constructor( public constructor(protected _resourceService: IAzureResourceService<T>) {
protected _resourceService: IAzureResourceService<T>,
protected _apiWrapper: ApiWrapper
) {
} }
public getTreeItem(element: azureResource.IAzureResourceNode): azdata.TreeItem | Thenable<azdata.TreeItem> { public getTreeItem(element: azureResource.IAzureResourceNode): azdata.TreeItem | Thenable<azdata.TreeItem> {
@@ -45,7 +41,7 @@ export abstract class ResourceTreeDataProviderBase<T extends azureResource.Azure
} }
private async getResources(element: azureResource.IAzureResourceNode): Promise<T[]> { private async getResources(element: azureResource.IAzureResourceNode): Promise<T[]> {
const tokens = await this._apiWrapper.getSecurityToken(element.account, azdata.AzureResource.ResourceManagement); const tokens = await azdata.accounts.getSecurityToken(element.account, azdata.AzureResource.ResourceManagement);
const credential = new msRest.TokenCredentials(tokens[element.tenantId].token, tokens[element.tenantId].tokenType); const credential = new msRest.TokenCredentials(tokens[element.tenantId].token, tokens[element.tenantId].tokenType);
const resources: T[] = await this._resourceService.getResources(element.subscription, credential, element.account) || <T[]>[]; const resources: T[] = await this._resourceService.getResources(element.subscription, credential, element.account) || <T[]>[];

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { ExtensionContext } from 'vscode'; import { ExtensionContext } from 'vscode';
import { ApiWrapper } from '../../../apiWrapper';
import { azureResource } from '../../azure-resource'; import { azureResource } from '../../azure-resource';
import { IAzureResourceService } from '../../interfaces'; import { IAzureResourceService } from '../../interfaces';
@@ -13,13 +12,12 @@ import { SqlInstanceTreeDataProvider as SqlInstanceTreeDataProvider } from './sq
export class SqlInstanceProvider implements azureResource.IAzureResourceProvider { export class SqlInstanceProvider implements azureResource.IAzureResourceProvider {
public constructor( public constructor(
private _service: IAzureResourceService<azureResource.AzureResourceDatabaseServer>, private _service: IAzureResourceService<azureResource.AzureResourceDatabaseServer>,
private _apiWrapper: ApiWrapper,
private _extensionContext: ExtensionContext private _extensionContext: ExtensionContext
) { ) {
} }
public getTreeDataProvider(): azureResource.IAzureResourceTreeDataProvider { public getTreeDataProvider(): azureResource.IAzureResourceTreeDataProvider {
return new SqlInstanceTreeDataProvider(this._service, this._apiWrapper, this._extensionContext); return new SqlInstanceTreeDataProvider(this._service, this._extensionContext);
} }
public get providerId(): string { public get providerId(): string {

View File

@@ -9,7 +9,6 @@ import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
import { AzureResourceItemType } from '../../constants'; import { AzureResourceItemType } from '../../constants';
import { ApiWrapper } from '../../../apiWrapper';
import { generateGuid } from '../../utils'; import { generateGuid } from '../../utils';
import { IAzureResourceService } from '../../interfaces'; import { IAzureResourceService } from '../../interfaces';
import { ResourceTreeDataProviderBase } from '../resourceTreeDataProviderBase'; import { ResourceTreeDataProviderBase } from '../resourceTreeDataProviderBase';
@@ -21,10 +20,9 @@ export class SqlInstanceTreeDataProvider extends ResourceTreeDataProviderBase<az
public constructor( public constructor(
databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>, databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>,
apiWrapper: ApiWrapper,
private _extensionContext: ExtensionContext private _extensionContext: ExtensionContext
) { ) {
super(databaseServerService, apiWrapper); super(databaseServerService);
} }

View File

@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { ExtensionContext } from 'vscode'; import { ExtensionContext } from 'vscode';
import { ApiWrapper } from '../../../apiWrapper';
import { azureResource } from '../../azure-resource'; import { azureResource } from '../../azure-resource';
import { IAzureResourceService } from '../../interfaces'; import { IAzureResourceService } from '../../interfaces';
@@ -13,13 +12,12 @@ import { SqlInstanceArcTreeDataProvider as SqlInstanceArcTreeDataProvider } from
export class SqlInstanceArcProvider implements azureResource.IAzureResourceProvider { export class SqlInstanceArcProvider implements azureResource.IAzureResourceProvider {
public constructor( public constructor(
private _service: IAzureResourceService<azureResource.AzureResourceDatabaseServer>, private _service: IAzureResourceService<azureResource.AzureResourceDatabaseServer>,
private _apiWrapper: ApiWrapper,
private _extensionContext: ExtensionContext private _extensionContext: ExtensionContext
) { ) {
} }
public getTreeDataProvider(): azureResource.IAzureResourceTreeDataProvider { public getTreeDataProvider(): azureResource.IAzureResourceTreeDataProvider {
return new SqlInstanceArcTreeDataProvider(this._service, this._apiWrapper, this._extensionContext); return new SqlInstanceArcTreeDataProvider(this._service, this._extensionContext);
} }
public get providerId(): string { public get providerId(): string {

View File

@@ -9,7 +9,6 @@ import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle(); const localize = nls.loadMessageBundle();
import { AzureResourceItemType } from '../../constants'; import { AzureResourceItemType } from '../../constants';
import { ApiWrapper } from '../../../apiWrapper';
import { generateGuid } from '../../utils'; import { generateGuid } from '../../utils';
import { IAzureResourceService } from '../../interfaces'; import { IAzureResourceService } from '../../interfaces';
import { ResourceTreeDataProviderBase } from '../resourceTreeDataProviderBase'; import { ResourceTreeDataProviderBase } from '../resourceTreeDataProviderBase';
@@ -21,10 +20,9 @@ export class SqlInstanceArcTreeDataProvider extends ResourceTreeDataProviderBase
public constructor( public constructor(
databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>, databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>,
apiWrapper: ApiWrapper,
private _extensionContext: ExtensionContext private _extensionContext: ExtensionContext
) { ) {
super(databaseServerService, apiWrapper); super(databaseServerService);
} }

View File

@@ -1,30 +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 { Event } from 'vscode';
import { Account, DidChangeAccountsParams } from 'azdata';
import { ApiWrapper } from '../../apiWrapper';
import { IAzureResourceAccountService } from '../interfaces';
export class AzureResourceAccountService implements IAzureResourceAccountService {
public constructor(
apiWrapper: ApiWrapper
) {
this._apiWrapper = apiWrapper;
this._onDidChangeAccounts = this._apiWrapper.onDidChangeAccounts;
}
public async getAccounts(): Promise<Account[]> {
return await this._apiWrapper.getAllAccounts();
}
public get onDidChangeAccounts(): Event<DidChangeAccountsParams> {
return this._onDidChangeAccounts;
}
private _apiWrapper: ApiWrapper = undefined;
private _onDidChangeAccounts: Event<DidChangeAccountsParams> = undefined;
}

View File

@@ -3,8 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { TreeItem, TreeItemCollapsibleState } from 'vscode'; import * as vscode from 'vscode';
import { Account, NodeInfo, AzureResource } from 'azdata'; import * as azdata from 'azdata';
import { TokenCredentials } from '@azure/ms-rest-js'; import { TokenCredentials } from '@azure/ms-rest-js';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
@@ -24,7 +24,7 @@ import { IAzureResourceSubscriptionService, IAzureResourceSubscriptionFilterServ
export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNodeBase { export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNodeBase {
public constructor( public constructor(
public readonly account: Account, public readonly account: azdata.Account,
appContext: AppContext, appContext: AppContext,
treeChangeHandler: IAzureResourceTreeChangeHandler treeChangeHandler: IAzureResourceTreeChangeHandler
) { ) {
@@ -42,7 +42,7 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
public async getChildren(): Promise<TreeNode[]> { public async getChildren(): Promise<TreeNode[]> {
try { try {
let subscriptions: azureResource.AzureResourceSubscription[] = []; let subscriptions: azureResource.AzureResourceSubscription[] = [];
const tokens = await this.appContext.apiWrapper.getSecurityToken(this.account, AzureResource.ResourceManagement); const tokens = await azdata.accounts.getSecurityToken(this.account, azdata.AzureResource.ResourceManagement);
if (this._isClearingCache) { if (this._isClearingCache) {
try { try {
@@ -99,7 +99,7 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
} }
} catch (error) { } catch (error) {
if (error instanceof AzureResourceCredentialError) { if (error instanceof AzureResourceCredentialError) {
this.appContext.apiWrapper.executeCommand('azure.resource.signin'); vscode.commands.executeCommand('azure.resource.signin');
} }
return [AzureResourceMessageTreeNode.create(AzureResourceErrorMessageUtil.getErrorMessage(error), this)]; return [AzureResourceMessageTreeNode.create(AzureResourceErrorMessageUtil.getErrorMessage(error), this)];
} }
@@ -109,8 +109,8 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
return this.getCache<azureResource.AzureResourceSubscription[]>(); return this.getCache<azureResource.AzureResourceSubscription[]>();
} }
public getTreeItem(): TreeItem | Promise<TreeItem> { public getTreeItem(): vscode.TreeItem | Promise<vscode.TreeItem> {
const item = new TreeItem(this._label, TreeItemCollapsibleState.Collapsed); const item = new vscode.TreeItem(this._label, vscode.TreeItemCollapsibleState.Collapsed);
item.id = this._id; item.id = this._id;
item.contextValue = AzureResourceItemType.account; item.contextValue = AzureResourceItemType.account;
item.iconPath = { item.iconPath = {
@@ -120,7 +120,7 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
return item; return item;
} }
public getNodeInfo(): NodeInfo { public getNodeInfo(): azdata.NodeInfo {
return { return {
label: this._label, label: this._label,
isLeaf: false, isLeaf: false,

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information. * Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { TreeDataProvider, EventEmitter, Event, TreeItem } from 'vscode'; import * as vscode from 'vscode';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import { AppContext } from '../../appContext'; import { AppContext } from '../../appContext';
import * as nls from 'vscode-nls'; import * as nls from 'vscode-nls';
@@ -16,30 +16,19 @@ import { AzureResourceMessageTreeNode } from '../messageTreeNode';
import { AzureResourceContainerTreeNodeBase } from './baseTreeNodes'; import { AzureResourceContainerTreeNodeBase } from './baseTreeNodes';
import { AzureResourceErrorMessageUtil, equals } from '../utils'; import { AzureResourceErrorMessageUtil, equals } from '../utils';
import { IAzureResourceTreeChangeHandler } from './treeChangeHandler'; import { IAzureResourceTreeChangeHandler } from './treeChangeHandler';
import { IAzureResourceAccountService } from '../../azureResource/interfaces';
import { AzureResourceServiceNames } from '../constants';
export class AzureResourceTreeProvider implements TreeDataProvider<TreeNode>, IAzureResourceTreeChangeHandler { export class AzureResourceTreeProvider implements vscode.TreeDataProvider<TreeNode>, IAzureResourceTreeChangeHandler {
public isSystemInitialized: boolean = false; public isSystemInitialized: boolean = false;
private accountService: IAzureResourceAccountService;
private accounts: azdata.Account[]; private accounts: azdata.Account[];
private _onDidChangeTreeData = new EventEmitter<TreeNode>(); private _onDidChangeTreeData = new vscode.EventEmitter<TreeNode>();
private loadingAccountsPromise: Promise<void>; private loadingAccountsPromise: Promise<void>;
public constructor(public readonly appContext: AppContext) { public constructor(private readonly appContext: AppContext) {
if (appContext) { azdata.accounts.onDidChangeAccounts(async (e: azdata.DidChangeAccountsParams) => {
this.hookAccountService(appContext);
}
}
private hookAccountService(appContext: AppContext): void {
this.accountService = appContext.getService<IAzureResourceAccountService>(AzureResourceServiceNames.accountService);
if (this.accountService) {
this.accountService.onDidChangeAccounts(async (e: azdata.DidChangeAccountsParams) => {
// This event sends it per provider, we need to make sure we get all the azure related accounts // This event sends it per provider, we need to make sure we get all the azure related accounts
let accounts = await this.accountService.getAccounts(); let accounts = await azdata.accounts.getAllAccounts();
accounts = accounts.filter(a => a.key.providerId.startsWith('azure')); accounts = accounts.filter(a => a.key.providerId.startsWith('azure'));
// the onDidChangeAccounts event will trigger in many cases where the accounts didn't actually change // 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 // the notifyNodeChanged event triggers a refresh which triggers a getChildren which can trigger this callback
@@ -51,7 +40,6 @@ export class AzureResourceTreeProvider implements TreeDataProvider<TreeNode>, IA
} }
}); });
} }
}
public async getChildren(element?: TreeNode): Promise<TreeNode[]> { public async getChildren(element?: TreeNode): Promise<TreeNode[]> {
if (element) { if (element) {
@@ -78,7 +66,7 @@ export class AzureResourceTreeProvider implements TreeDataProvider<TreeNode>, IA
private async loadAccounts(): Promise<void> { private async loadAccounts(): Promise<void> {
try { try {
this.accounts = await this.appContext.getService<IAzureResourceAccountService>(AzureResourceServiceNames.accountService).getAccounts(); this.accounts = await azdata.accounts.getAllAccounts();
// System has been initialized // System has been initialized
this.setSystemInitialized(); this.setSystemInitialized();
this._onDidChangeTreeData.fire(undefined); this._onDidChangeTreeData.fire(undefined);
@@ -93,7 +81,7 @@ export class AzureResourceTreeProvider implements TreeDataProvider<TreeNode>, IA
this.loadingAccountsPromise = undefined; this.loadingAccountsPromise = undefined;
} }
public get onDidChangeTreeData(): Event<TreeNode> { public get onDidChangeTreeData(): vscode.Event<TreeNode> {
return this._onDidChangeTreeData.event; return this._onDidChangeTreeData.event;
} }
@@ -111,7 +99,7 @@ export class AzureResourceTreeProvider implements TreeDataProvider<TreeNode>, IA
this._onDidChangeTreeData.fire(node); this._onDidChangeTreeData.fire(node);
} }
public getTreeItem(element: TreeNode): TreeItem | Thenable<TreeItem> { public getTreeItem(element: TreeNode): vscode.TreeItem | Thenable<vscode.TreeItem> {
return element.getTreeItem(); return element.getTreeItem();
} }
} }

View File

@@ -151,7 +151,7 @@ export async function getSubscriptions(appContext: AppContext, account?: azdata.
} }
const subscriptionService = appContext.getService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService); const subscriptionService = appContext.getService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService);
const tokens = await appContext.apiWrapper.getSecurityToken(account, azdata.AzureResource.ResourceManagement); const tokens = await azdata.accounts.getSecurityToken(account, azdata.AzureResource.ResourceManagement);
await Promise.all(account.properties.tenants.map(async (tenant: { id: string | number; }) => { await Promise.all(account.properties.tenants.map(async (tenant: { id: string | number; }) => {
try { try {
const token = tokens[tenant.id].token; const token = tokens[tenant.id].token;

View File

@@ -10,7 +10,6 @@ import * as path from 'path';
import * as os from 'os'; import * as os from 'os';
import { AppContext } from './appContext'; import { AppContext } from './appContext';
import { ApiWrapper } from './apiWrapper';
import { AzureAccountProviderService } from './account-provider/azureAccountProviderService'; import { AzureAccountProviderService } from './account-provider/azureAccountProviderService';
import { AzureResourceDatabaseServerProvider } from './azureResource/providers/databaseServer/databaseServerProvider'; import { AzureResourceDatabaseServerProvider } from './azureResource/providers/databaseServer/databaseServerProvider';
@@ -18,9 +17,8 @@ import { AzureResourceDatabaseServerService } from './azureResource/providers/da
import { AzureResourceDatabaseProvider } from './azureResource/providers/database/databaseProvider'; import { AzureResourceDatabaseProvider } from './azureResource/providers/database/databaseProvider';
import { AzureResourceDatabaseService } from './azureResource/providers/database/databaseService'; import { AzureResourceDatabaseService } from './azureResource/providers/database/databaseService';
import { AzureResourceService } from './azureResource/resourceService'; import { AzureResourceService } from './azureResource/resourceService';
import { IAzureResourceCacheService, IAzureResourceAccountService, IAzureResourceSubscriptionService, IAzureResourceSubscriptionFilterService, IAzureResourceTenantService, IAzureTerminalService } from './azureResource/interfaces'; import { IAzureResourceCacheService, IAzureResourceSubscriptionService, IAzureResourceSubscriptionFilterService, IAzureResourceTenantService, IAzureTerminalService } from './azureResource/interfaces';
import { AzureResourceServiceNames } from './azureResource/constants'; import { AzureResourceServiceNames } from './azureResource/constants';
import { AzureResourceAccountService } from './azureResource/services/accountService';
import { AzureResourceSubscriptionService } from './azureResource/services/subscriptionService'; import { AzureResourceSubscriptionService } from './azureResource/services/subscriptionService';
import { AzureResourceSubscriptionFilterService } from './azureResource/services/subscriptionFilterService'; import { AzureResourceSubscriptionFilterService } from './azureResource/services/subscriptionFilterService';
import { AzureResourceCacheService } from './azureResource/services/cacheService'; import { AzureResourceCacheService } from './azureResource/services/cacheService';
@@ -41,6 +39,7 @@ import * as azurecore from './azurecore';
import * as azureResourceUtils from './azureResource/utils'; import * as azureResourceUtils from './azureResource/utils';
import * as utils from './utils'; import * as utils from './utils';
import * as loc from './localizedConstants'; import * as loc from './localizedConstants';
import * as constants from './constants';
import { AzureResourceGroupService } from './azureResource/providers/resourceGroup/resourceGroupService'; import { AzureResourceGroupService } from './azureResource/providers/resourceGroup/resourceGroupService';
import { Logger } from './utils/Logger'; import { Logger } from './utils/Logger';
@@ -70,39 +69,38 @@ function pushDisposable(disposable: vscode.Disposable): void {
// your extension is activated the very first time the command is executed // your extension is activated the very first time the command is executed
export async function activate(context: vscode.ExtensionContext): Promise<azurecore.IExtension> { export async function activate(context: vscode.ExtensionContext): Promise<azurecore.IExtension> {
extensionContext = context; extensionContext = context;
const apiWrapper = new ApiWrapper(); let appContext = new AppContext(extensionContext);
let appContext = new AppContext(extensionContext, apiWrapper);
let storagePath = await findOrMakeStoragePath(); let storagePath = await findOrMakeStoragePath();
if (!storagePath) { if (!storagePath) {
return undefined; return undefined;
} }
updatePiiLoggingLevel(apiWrapper); updatePiiLoggingLevel();
// Create the provider service and activate // Create the provider service and activate
initAzureAccountProvider(extensionContext, storagePath).catch((err) => console.log(err)); initAzureAccountProvider(extensionContext, storagePath).catch((err) => console.log(err));
registerAzureServices(appContext); registerAzureServices(appContext);
const azureResourceTree = new AzureResourceTreeProvider(appContext); const azureResourceTree = new AzureResourceTreeProvider(appContext);
pushDisposable(apiWrapper.registerTreeDataProvider('azureResourceExplorer', azureResourceTree)); pushDisposable(vscode.window.registerTreeDataProvider('azureResourceExplorer', azureResourceTree));
pushDisposable(apiWrapper.onDidChangeConfiguration(e => onDidChangeConfiguration(e, apiWrapper), this)); pushDisposable(vscode.workspace.onDidChangeConfiguration(e => onDidChangeConfiguration(e), this));
registerAzureResourceCommands(appContext, azureResourceTree); registerAzureResourceCommands(appContext, azureResourceTree);
return { return {
getSubscriptions(account?: azdata.Account, ignoreErrors?: boolean): Thenable<azurecore.GetSubscriptionsResult> { return azureResourceUtils.getSubscriptions(appContext, account, ignoreErrors); }, getSubscriptions(account?: azdata.Account, ignoreErrors?: boolean): Thenable<azurecore.GetSubscriptionsResult> { return azureResourceUtils.getSubscriptions(appContext, account, ignoreErrors); },
getResourceGroups(account?: azdata.Account, subscription?: azureResource.AzureResourceSubscription, ignoreErrors?: boolean): Thenable<azurecore.GetResourceGroupsResult> { return azureResourceUtils.getResourceGroups(appContext, account, subscription, ignoreErrors); }, getResourceGroups(account?: azdata.Account, subscription?: azureResource.AzureResourceSubscription, ignoreErrors?: boolean): Thenable<azurecore.GetResourceGroupsResult> { return azureResourceUtils.getResourceGroups(appContext, account, subscription, ignoreErrors); },
provideResources(): azureResource.IAzureResourceProvider[] { provideResources(): azureResource.IAzureResourceProvider[] {
const arcFeaturedEnabled = apiWrapper.getExtensionConfiguration().get('enableArcFeatures'); const arcFeaturedEnabled = vscode.workspace.getConfiguration(constants.extensionConfigSectionName).get('enableArcFeatures');
const providers: azureResource.IAzureResourceProvider[] = [ const providers: azureResource.IAzureResourceProvider[] = [
new AzureResourceDatabaseServerProvider(new AzureResourceDatabaseServerService(), apiWrapper, extensionContext), new AzureResourceDatabaseServerProvider(new AzureResourceDatabaseServerService(), extensionContext),
new AzureResourceDatabaseProvider(new AzureResourceDatabaseService(), apiWrapper, extensionContext), new AzureResourceDatabaseProvider(new AzureResourceDatabaseService(), extensionContext),
new SqlInstanceProvider(new SqlInstanceResourceService(), apiWrapper, extensionContext), new SqlInstanceProvider(new SqlInstanceResourceService(), extensionContext),
new PostgresServerProvider(new PostgresServerService(), apiWrapper, extensionContext), new PostgresServerProvider(new PostgresServerService(), extensionContext),
]; ];
if (arcFeaturedEnabled) { if (arcFeaturedEnabled) {
providers.push( providers.push(
new SqlInstanceArcProvider(new SqlInstanceArcResourceService(), apiWrapper, extensionContext), new SqlInstanceArcProvider(new SqlInstanceArcResourceService(), extensionContext),
new PostgresServerArcProvider(new PostgresServerArcService(), apiWrapper, extensionContext) new PostgresServerArcProvider(new PostgresServerArcService(), extensionContext)
); );
} }
return providers; return providers;
@@ -152,7 +150,6 @@ async function initAzureAccountProvider(extensionContext: vscode.ExtensionContex
function registerAzureServices(appContext: AppContext): void { function registerAzureServices(appContext: AppContext): void {
appContext.registerService<AzureResourceService>(AzureResourceServiceNames.resourceService, new AzureResourceService()); appContext.registerService<AzureResourceService>(AzureResourceServiceNames.resourceService, new AzureResourceService());
appContext.registerService<AzureResourceGroupService>(AzureResourceServiceNames.resourceGroupService, new AzureResourceGroupService()); appContext.registerService<AzureResourceGroupService>(AzureResourceServiceNames.resourceGroupService, new AzureResourceGroupService());
appContext.registerService<IAzureResourceAccountService>(AzureResourceServiceNames.accountService, new AzureResourceAccountService(appContext.apiWrapper));
appContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, new AzureResourceCacheService(extensionContext)); appContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, new AzureResourceCacheService(extensionContext));
appContext.registerService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService, new AzureResourceSubscriptionService()); appContext.registerService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService, new AzureResourceSubscriptionService());
appContext.registerService<IAzureResourceSubscriptionFilterService>(AzureResourceServiceNames.subscriptionFilterService, new AzureResourceSubscriptionFilterService(new AzureResourceCacheService(extensionContext))); appContext.registerService<IAzureResourceSubscriptionFilterService>(AzureResourceServiceNames.subscriptionFilterService, new AzureResourceSubscriptionFilterService(new AzureResourceCacheService(extensionContext)));
@@ -160,21 +157,21 @@ function registerAzureServices(appContext: AppContext): void {
appContext.registerService<IAzureTerminalService>(AzureResourceServiceNames.terminalService, new AzureTerminalService(extensionContext)); appContext.registerService<IAzureTerminalService>(AzureResourceServiceNames.terminalService, new AzureTerminalService(extensionContext));
} }
async function onDidChangeConfiguration(e: vscode.ConfigurationChangeEvent, apiWrapper: ApiWrapper): Promise<void> { async function onDidChangeConfiguration(e: vscode.ConfigurationChangeEvent): Promise<void> {
if (e.affectsConfiguration('azure.enableArcFeatures')) { if (e.affectsConfiguration('azure.enableArcFeatures')) {
const response = await apiWrapper.showInformationMessage(loc.requiresReload, loc.reload); const response = await vscode.window.showInformationMessage(loc.requiresReload, loc.reload);
if (response === loc.reload) { if (response === loc.reload) {
await apiWrapper.executeCommand('workbench.action.reloadWindow'); await vscode.commands.executeCommand('workbench.action.reloadWindow');
} }
return; return;
} }
if (e.affectsConfiguration('azure.piiLogging')) { if (e.affectsConfiguration('azure.piiLogging')) {
updatePiiLoggingLevel(apiWrapper); updatePiiLoggingLevel();
} }
} }
function updatePiiLoggingLevel(apiWrapper: ApiWrapper) { function updatePiiLoggingLevel() {
const piiLogging: boolean = apiWrapper.getExtensionConfiguration().get('piiLogging'); const piiLogging: boolean = vscode.workspace.getConfiguration(constants.extensionConfigSectionName).get('piiLogging');
Logger.piiLogging = piiLogging; Logger.piiLogging = piiLogging;
} }

View File

@@ -7,10 +7,10 @@ import * as should from 'should';
import * as TypeMoq from 'typemoq'; import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as sinon from 'sinon';
import 'mocha'; import 'mocha';
import { azureResource } from '../../../../azureResource/azure-resource'; import { azureResource } from '../../../../azureResource/azure-resource';
import { ApiWrapper } from '../../../../apiWrapper';
import { AzureResourceDatabaseTreeDataProvider } from '../../../../azureResource/providers/database/databaseTreeDataProvider'; import { AzureResourceDatabaseTreeDataProvider } from '../../../../azureResource/providers/database/databaseTreeDataProvider';
import { AzureResourceItemType } from '../../../../azureResource/constants'; import { AzureResourceItemType } from '../../../../azureResource/constants';
import { IAzureResourceService } from '../../../../azureResource/interfaces'; import { IAzureResourceService } from '../../../../azureResource/interfaces';
@@ -19,7 +19,6 @@ import settings from '../../../../account-provider/providerSettings';
// Mock services // Mock services
let mockDatabaseService: TypeMoq.IMock<IAzureResourceService<azureResource.AzureResourceDatabase>>; let mockDatabaseService: TypeMoq.IMock<IAzureResourceService<azureResource.AzureResourceDatabase>>;
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>; let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>;
// Mock test data // Mock test data
@@ -88,12 +87,11 @@ const mockDatabases: azureResource.AzureResourceDatabase[] = [
describe('AzureResourceDatabaseTreeDataProvider.info', function (): void { describe('AzureResourceDatabaseTreeDataProvider.info', function (): void {
beforeEach(() => { beforeEach(() => {
mockDatabaseService = TypeMoq.Mock.ofType<IAzureResourceService<azureResource.AzureResourceDatabase>>(); mockDatabaseService = TypeMoq.Mock.ofType<IAzureResourceService<azureResource.AzureResourceDatabase>>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>(); mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
}); });
it('Should be correct when created.', async function (): Promise<void> { it('Should be correct when created.', async function (): Promise<void> {
const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockApiWrapper.object, mockExtensionContext.object); const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockExtensionContext.object);
const treeItem = await treeDataProvider.getTreeItem(mockResourceRootNode); const treeItem = await treeDataProvider.getTreeItem(mockResourceRootNode);
should(treeItem.id).equal(mockResourceRootNode.treeItem.id); should(treeItem.id).equal(mockResourceRootNode.treeItem.id);
@@ -106,16 +104,19 @@ describe('AzureResourceDatabaseTreeDataProvider.info', function (): void {
describe('AzureResourceDatabaseTreeDataProvider.getChildren', function (): void { describe('AzureResourceDatabaseTreeDataProvider.getChildren', function (): void {
beforeEach(() => { beforeEach(() => {
mockDatabaseService = TypeMoq.Mock.ofType<IAzureResourceService<azureResource.AzureResourceDatabase>>(); mockDatabaseService = TypeMoq.Mock.ofType<IAzureResourceService<azureResource.AzureResourceDatabase>>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>(); mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockApiWrapper.setup((o) => o.getSecurityToken(mockAccount, azdata.AzureResource.ResourceManagement)).returns(() => Promise.resolve(mockTokens)); sinon.stub(azdata.accounts, 'getSecurityToken').returns(Promise.resolve(mockTokens));
mockDatabaseService.setup((o) => o.getResources(mockSubscription, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(mockDatabases)); mockDatabaseService.setup((o) => o.getResources(mockSubscription, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(mockDatabases));
mockExtensionContext.setup((o) => o.asAbsolutePath(TypeMoq.It.isAnyString())).returns(() => TypeMoq.It.isAnyString()); mockExtensionContext.setup((o) => o.asAbsolutePath(TypeMoq.It.isAnyString())).returns(() => TypeMoq.It.isAnyString());
}); });
afterEach(function (): void {
sinon.restore();
});
it('Should return container node when element is undefined.', async function (): Promise<void> { it('Should return container node when element is undefined.', async function (): Promise<void> {
const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockApiWrapper.object, mockExtensionContext.object); const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockExtensionContext.object);
const children = await treeDataProvider.getChildren(); const children = await treeDataProvider.getChildren();
@@ -133,7 +134,7 @@ describe('AzureResourceDatabaseTreeDataProvider.getChildren', function (): void
}); });
it('Should return resource nodes when it is container node.', async function (): Promise<void> { it('Should return resource nodes when it is container node.', async function (): Promise<void> {
const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockApiWrapper.object, mockExtensionContext.object); const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockExtensionContext.object);
const children = await treeDataProvider.getChildren(mockResourceRootNode); const children = await treeDataProvider.getChildren(mockResourceRootNode);

View File

@@ -7,17 +7,16 @@ import * as should from 'should';
import * as TypeMoq from 'typemoq'; import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as sinon from 'sinon';
import 'mocha'; import 'mocha';
import { azureResource } from '../../../../azureResource/azure-resource'; import { azureResource } from '../../../../azureResource/azure-resource';
import { ApiWrapper } from '../../../../apiWrapper';
import { AzureResourceDatabaseServerTreeDataProvider } from '../../../../azureResource/providers/databaseServer/databaseServerTreeDataProvider'; import { AzureResourceDatabaseServerTreeDataProvider } from '../../../../azureResource/providers/databaseServer/databaseServerTreeDataProvider';
import { AzureResourceItemType } from '../../../../azureResource/constants'; import { AzureResourceItemType } from '../../../../azureResource/constants';
import { IAzureResourceService } from '../../../../azureResource/interfaces'; import { IAzureResourceService } from '../../../../azureResource/interfaces';
// Mock services // Mock services
let mockDatabaseServerService: TypeMoq.IMock<IAzureResourceService<azureResource.AzureResourceDatabaseServer>>; let mockDatabaseServerService: TypeMoq.IMock<IAzureResourceService<azureResource.AzureResourceDatabaseServer>>;
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>; let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>;
import settings from '../../../../account-provider/providerSettings'; import settings from '../../../../account-provider/providerSettings';
import { AzureAccount } from '../../../../account-provider/interfaces'; import { AzureAccount } from '../../../../account-provider/interfaces';
@@ -88,12 +87,11 @@ const mockDatabaseServers: azureResource.AzureResourceDatabaseServer[] = [
describe('AzureResourceDatabaseServerTreeDataProvider.info', function (): void { describe('AzureResourceDatabaseServerTreeDataProvider.info', function (): void {
beforeEach(() => { beforeEach(() => {
mockDatabaseServerService = TypeMoq.Mock.ofType<IAzureResourceService<azureResource.AzureResourceDatabaseServer>>(); mockDatabaseServerService = TypeMoq.Mock.ofType<IAzureResourceService<azureResource.AzureResourceDatabaseServer>>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>(); mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
}); });
it('Should be correct when created.', async function (): Promise<void> { it('Should be correct when created.', async function (): Promise<void> {
const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockApiWrapper.object, mockExtensionContext.object); const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockExtensionContext.object);
const treeItem = await treeDataProvider.getTreeItem(mockResourceRootNode); const treeItem = await treeDataProvider.getTreeItem(mockResourceRootNode);
should(treeItem.id).equal(mockResourceRootNode.treeItem.id); should(treeItem.id).equal(mockResourceRootNode.treeItem.id);
@@ -106,16 +104,19 @@ describe('AzureResourceDatabaseServerTreeDataProvider.info', function (): void {
describe('AzureResourceDatabaseServerTreeDataProvider.getChildren', function (): void { describe('AzureResourceDatabaseServerTreeDataProvider.getChildren', function (): void {
beforeEach(() => { beforeEach(() => {
mockDatabaseServerService = TypeMoq.Mock.ofType<IAzureResourceService<azureResource.AzureResourceDatabaseServer>>(); mockDatabaseServerService = TypeMoq.Mock.ofType<IAzureResourceService<azureResource.AzureResourceDatabaseServer>>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>(); mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockApiWrapper.setup((o) => o.getSecurityToken(mockAccount, azdata.AzureResource.ResourceManagement)).returns(() => Promise.resolve(mockTokens)); sinon.stub(azdata.accounts, 'getSecurityToken').returns(Promise.resolve(mockTokens));
mockDatabaseServerService.setup((o) => o.getResources(mockSubscription, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(mockDatabaseServers)); mockDatabaseServerService.setup((o) => o.getResources(mockSubscription, TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(mockDatabaseServers));
mockExtensionContext.setup((o) => o.asAbsolutePath(TypeMoq.It.isAnyString())).returns(() => TypeMoq.It.isAnyString()); mockExtensionContext.setup((o) => o.asAbsolutePath(TypeMoq.It.isAnyString())).returns(() => TypeMoq.It.isAnyString());
}); });
afterEach(function (): void {
sinon.restore();
});
it('Should return container node when element is undefined.', async function (): Promise<void> { it('Should return container node when element is undefined.', async function (): Promise<void> {
const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockApiWrapper.object, mockExtensionContext.object); const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockExtensionContext.object);
const children = await treeDataProvider.getChildren(); const children = await treeDataProvider.getChildren();
@@ -133,7 +134,7 @@ describe('AzureResourceDatabaseServerTreeDataProvider.getChildren', function ():
}); });
it('Should return resource nodes when it is container node.', async function (): Promise<void> { it('Should return resource nodes when it is container node.', async function (): Promise<void> {
const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockApiWrapper.object, mockExtensionContext.object); const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockExtensionContext.object);
const children = await treeDataProvider.getChildren(mockResourceRootNode); const children = await treeDataProvider.getChildren(mockResourceRootNode);

View File

@@ -12,7 +12,6 @@ import { azureResource } from '../../azureResource/azure-resource';
import { AzureResourceService } from '../../azureResource/resourceService'; import { AzureResourceService } from '../../azureResource/resourceService';
import { AzureResourceResourceTreeNode } from '../../azureResource/resourceTreeNode'; import { AzureResourceResourceTreeNode } from '../../azureResource/resourceTreeNode';
import { AppContext } from '../../appContext'; import { AppContext } from '../../appContext';
import { ApiWrapper } from '../../apiWrapper';
import { AzureResourceServiceNames } from '../../azureResource/constants'; import { AzureResourceServiceNames } from '../../azureResource/constants';
import settings from '../../account-provider/providerSettings'; import settings from '../../account-provider/providerSettings';
import { AzureAccount } from '../../account-provider/interfaces'; import { AzureAccount } from '../../account-provider/interfaces';
@@ -106,7 +105,7 @@ describe('AzureResourceResourceTreeNode.info', function (): void {
resourceService.registerResourceProvider(mockResourceProvider.object); resourceService.registerResourceProvider(mockResourceProvider.object);
resourceService.areResourceProvidersLoaded = true; resourceService.areResourceProvidersLoaded = true;
appContext = new AppContext(undefined, new ApiWrapper()); appContext = new AppContext(undefined);
appContext.registerService(AzureResourceServiceNames.resourceService, resourceService); appContext.registerService(AzureResourceServiceNames.resourceService, resourceService);
}); });
@@ -146,7 +145,7 @@ describe('AzureResourceResourceTreeNode.getChildren', function (): void {
resourceService.registerResourceProvider(mockResourceProvider.object); resourceService.registerResourceProvider(mockResourceProvider.object);
resourceService.areResourceProvidersLoaded = true; resourceService.areResourceProvidersLoaded = true;
appContext = new AppContext(undefined, new ApiWrapper()); appContext = new AppContext(undefined);
appContext.registerService(AzureResourceServiceNames.resourceService, resourceService); appContext.registerService(AzureResourceServiceNames.resourceService, resourceService);
}); });

View File

@@ -7,6 +7,7 @@ import * as should from 'should';
import * as TypeMoq from 'typemoq'; import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import * as sinon from 'sinon';
import 'mocha'; import 'mocha';
import { TokenCredentials } from '@azure/ms-rest-js'; import { TokenCredentials } from '@azure/ms-rest-js';
import { AppContext } from '../../../appContext'; import { AppContext } from '../../../appContext';
@@ -23,18 +24,16 @@ import { AzureResourceAccountTreeNode } from '../../../azureResource/tree/accoun
import { AzureResourceSubscriptionTreeNode } from '../../../azureResource/tree/subscriptionTreeNode'; import { AzureResourceSubscriptionTreeNode } from '../../../azureResource/tree/subscriptionTreeNode';
import { AzureResourceItemType, AzureResourceServiceNames } from '../../../azureResource/constants'; import { AzureResourceItemType, AzureResourceServiceNames } from '../../../azureResource/constants';
import { AzureResourceMessageTreeNode } from '../../../azureResource/messageTreeNode'; import { AzureResourceMessageTreeNode } from '../../../azureResource/messageTreeNode';
import { ApiWrapper } from '../../../apiWrapper';
import { generateGuid } from '../../../azureResource/utils'; import { generateGuid } from '../../../azureResource/utils';
// Mock services // Mock services
let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>; let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>;
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
let mockCacheService: TypeMoq.IMock<IAzureResourceCacheService>; let mockCacheService: TypeMoq.IMock<IAzureResourceCacheService>;
let mockSubscriptionService: TypeMoq.IMock<IAzureResourceSubscriptionService>; let mockSubscriptionService: TypeMoq.IMock<IAzureResourceSubscriptionService>;
let mockSubscriptionFilterService: TypeMoq.IMock<IAzureResourceSubscriptionFilterService>; let mockSubscriptionFilterService: TypeMoq.IMock<IAzureResourceSubscriptionFilterService>;
let mockTenantService: TypeMoq.IMock<IAzureResourceTenantService>; let mockTenantService: TypeMoq.IMock<IAzureResourceTenantService>;
let mockAppContext: AppContext; let mockAppContext: AppContext;
let getSecurityTokenStub: sinon.SinonStub;
let mockTreeChangeHandler: TypeMoq.IMock<IAzureResourceTreeChangeHandler>; let mockTreeChangeHandler: TypeMoq.IMock<IAzureResourceTreeChangeHandler>;
// Mock test data // Mock test data
@@ -91,7 +90,6 @@ let mockSubscriptionCache: azureResource.AzureResourceSubscription[] = [];
describe('AzureResourceAccountTreeNode.info', function (): void { describe('AzureResourceAccountTreeNode.info', function (): void {
beforeEach(() => { beforeEach(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>(); mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>(); mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>();
mockSubscriptionService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionService>(); mockSubscriptionService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionService>();
mockSubscriptionFilterService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionFilterService>(); mockSubscriptionFilterService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionFilterService>();
@@ -101,19 +99,23 @@ describe('AzureResourceAccountTreeNode.info', function (): void {
mockSubscriptionCache = []; mockSubscriptionCache = [];
mockAppContext = new AppContext(mockExtensionContext.object, mockApiWrapper.object); mockAppContext = new AppContext(mockExtensionContext.object);
mockAppContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, mockCacheService.object); mockAppContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, mockCacheService.object);
mockAppContext.registerService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService, mockSubscriptionService.object); mockAppContext.registerService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService, mockSubscriptionService.object);
mockAppContext.registerService<IAzureResourceSubscriptionFilterService>(AzureResourceServiceNames.subscriptionFilterService, mockSubscriptionFilterService.object); mockAppContext.registerService<IAzureResourceSubscriptionFilterService>(AzureResourceServiceNames.subscriptionFilterService, mockSubscriptionFilterService.object);
mockAppContext.registerService<IAzureResourceTenantService>(AzureResourceServiceNames.tenantService, mockTenantService.object); mockAppContext.registerService<IAzureResourceTenantService>(AzureResourceServiceNames.tenantService, mockTenantService.object);
mockApiWrapper.setup((o) => o.getSecurityToken(mockAccount, azdata.AzureResource.ResourceManagement)).returns(() => Promise.resolve(mockTokens)); getSecurityTokenStub = sinon.stub(azdata.accounts, 'getSecurityToken').returns(Promise.resolve(mockTokens));
mockCacheService.setup((o) => o.generateKey(TypeMoq.It.isAnyString())).returns(() => generateGuid()); mockCacheService.setup((o) => o.generateKey(TypeMoq.It.isAnyString())).returns(() => generateGuid());
mockCacheService.setup((o) => o.get(TypeMoq.It.isAnyString())).returns(() => mockSubscriptionCache); mockCacheService.setup((o) => o.get(TypeMoq.It.isAnyString())).returns(() => mockSubscriptionCache);
mockCacheService.setup((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => mockSubscriptionCache = mockSubscriptions); mockCacheService.setup((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => mockSubscriptionCache = mockSubscriptions);
mockTenantService.setup((o) => o.getTenantId(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(mockTenantId)); mockTenantService.setup((o) => o.getTenantId(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(mockTenantId));
}); });
afterEach(function (): void {
sinon.restore();
});
it('Should be correct when created.', async function (): Promise<void> { it('Should be correct when created.', async function (): Promise<void> {
const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockAppContext, mockTreeChangeHandler.object); const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockAppContext, mockTreeChangeHandler.object);
@@ -179,7 +181,6 @@ describe('AzureResourceAccountTreeNode.info', function (): void {
describe('AzureResourceAccountTreeNode.getChildren', function (): void { describe('AzureResourceAccountTreeNode.getChildren', function (): void {
beforeEach(() => { beforeEach(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>(); mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>(); mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>();
mockSubscriptionService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionService>(); mockSubscriptionService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionService>();
mockSubscriptionFilterService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionFilterService>(); mockSubscriptionFilterService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionFilterService>();
@@ -189,19 +190,23 @@ describe('AzureResourceAccountTreeNode.getChildren', function (): void {
mockSubscriptionCache = []; mockSubscriptionCache = [];
mockAppContext = new AppContext(mockExtensionContext.object, mockApiWrapper.object); mockAppContext = new AppContext(mockExtensionContext.object);
mockAppContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, mockCacheService.object); mockAppContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, mockCacheService.object);
mockAppContext.registerService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService, mockSubscriptionService.object); mockAppContext.registerService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService, mockSubscriptionService.object);
mockAppContext.registerService<IAzureResourceSubscriptionFilterService>(AzureResourceServiceNames.subscriptionFilterService, mockSubscriptionFilterService.object); mockAppContext.registerService<IAzureResourceSubscriptionFilterService>(AzureResourceServiceNames.subscriptionFilterService, mockSubscriptionFilterService.object);
mockAppContext.registerService<IAzureResourceTenantService>(AzureResourceServiceNames.tenantService, mockTenantService.object); mockAppContext.registerService<IAzureResourceTenantService>(AzureResourceServiceNames.tenantService, mockTenantService.object);
mockApiWrapper.setup((o) => o.getSecurityToken(mockAccount, azdata.AzureResource.ResourceManagement)).returns(() => Promise.resolve(mockTokens)); sinon.stub(azdata.accounts, 'getSecurityToken').returns(Promise.resolve(mockTokens));
mockCacheService.setup((o) => o.generateKey(TypeMoq.It.isAnyString())).returns(() => generateGuid()); mockCacheService.setup((o) => o.generateKey(TypeMoq.It.isAnyString())).returns(() => generateGuid());
mockCacheService.setup((o) => o.get(TypeMoq.It.isAnyString())).returns(() => mockSubscriptionCache); mockCacheService.setup((o) => o.get(TypeMoq.It.isAnyString())).returns(() => mockSubscriptionCache);
mockCacheService.setup((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => mockSubscriptionCache = mockSubscriptions); mockCacheService.setup((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => mockSubscriptionCache = mockSubscriptions);
mockTenantService.setup((o) => o.getTenantId(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(mockTenantId)); mockTenantService.setup((o) => o.getTenantId(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(mockTenantId));
}); });
afterEach(function (): void {
sinon.restore();
});
it('Should load subscriptions from scratch and update cache when it is clearing cache.', async function (): Promise<void> { it('Should load subscriptions from scratch and update cache when it is clearing cache.', async function (): Promise<void> {
mockSubscriptionService.setup((o) => o.getSubscriptions(mockAccount, mockCredential)).returns(() => Promise.resolve(mockSubscriptions)); mockSubscriptionService.setup((o) => o.getSubscriptions(mockAccount, mockCredential)).returns(() => Promise.resolve(mockSubscriptions));
mockSubscriptionFilterService.setup((o) => o.getSelectedSubscriptions(mockAccount)).returns(() => Promise.resolve([])); mockSubscriptionFilterService.setup((o) => o.getSelectedSubscriptions(mockAccount)).returns(() => Promise.resolve([]));
@@ -300,7 +305,7 @@ describe('AzureResourceAccountTreeNode.getChildren', function (): void {
const children = await accountTreeNode.getChildren(); const children = await accountTreeNode.getChildren();
mockApiWrapper.verify((o) => o.getSecurityToken(mockAccount, azdata.AzureResource.ResourceManagement), TypeMoq.Times.once()); should(getSecurityTokenStub.calledOnce).be.true('getSecurityToken should have been called exactly once');
mockSubscriptionService.verify((o) => o.getSubscriptions(mockAccount, mockCredential), TypeMoq.Times.once()); mockSubscriptionService.verify((o) => o.getSubscriptions(mockAccount, mockCredential), TypeMoq.Times.once());
mockSubscriptionFilterService.verify((o) => o.getSelectedSubscriptions(mockAccount), TypeMoq.Times.once()); mockSubscriptionFilterService.verify((o) => o.getSelectedSubscriptions(mockAccount), TypeMoq.Times.once());
mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.never()); mockCacheService.verify((o) => o.get(TypeMoq.It.isAnyString()), TypeMoq.Times.never());
@@ -317,7 +322,6 @@ describe('AzureResourceAccountTreeNode.getChildren', function (): void {
describe('AzureResourceAccountTreeNode.clearCache', function (): void { describe('AzureResourceAccountTreeNode.clearCache', function (): void {
beforeEach(() => { beforeEach(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>(); mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>(); mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>();
mockSubscriptionService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionService>(); mockSubscriptionService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionService>();
mockSubscriptionFilterService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionFilterService>(); mockSubscriptionFilterService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionFilterService>();
@@ -327,19 +331,23 @@ describe('AzureResourceAccountTreeNode.clearCache', function (): void {
mockSubscriptionCache = []; mockSubscriptionCache = [];
mockAppContext = new AppContext(mockExtensionContext.object, mockApiWrapper.object); mockAppContext = new AppContext(mockExtensionContext.object);
mockAppContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, mockCacheService.object); mockAppContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, mockCacheService.object);
mockAppContext.registerService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService, mockSubscriptionService.object); mockAppContext.registerService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService, mockSubscriptionService.object);
mockAppContext.registerService<IAzureResourceSubscriptionFilterService>(AzureResourceServiceNames.subscriptionFilterService, mockSubscriptionFilterService.object); mockAppContext.registerService<IAzureResourceSubscriptionFilterService>(AzureResourceServiceNames.subscriptionFilterService, mockSubscriptionFilterService.object);
mockAppContext.registerService<IAzureResourceTenantService>(AzureResourceServiceNames.tenantService, mockTenantService.object); mockAppContext.registerService<IAzureResourceTenantService>(AzureResourceServiceNames.tenantService, mockTenantService.object);
mockApiWrapper.setup((o,) => o.getSecurityToken(mockAccount, azdata.AzureResource.ResourceManagement)).returns(() => Promise.resolve(mockTokens)); sinon.stub(azdata.accounts, 'getSecurityToken').returns(Promise.resolve(mockTokens));
mockCacheService.setup((o) => o.generateKey(TypeMoq.It.isAnyString())).returns(() => generateGuid()); mockCacheService.setup((o) => o.generateKey(TypeMoq.It.isAnyString())).returns(() => generateGuid());
mockCacheService.setup((o) => o.get(TypeMoq.It.isAnyString())).returns(() => mockSubscriptionCache); mockCacheService.setup((o) => o.get(TypeMoq.It.isAnyString())).returns(() => mockSubscriptionCache);
mockCacheService.setup((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => mockSubscriptionCache = mockSubscriptions); mockCacheService.setup((o) => o.update(TypeMoq.It.isAnyString(), TypeMoq.It.isAny())).returns(() => mockSubscriptionCache = mockSubscriptions);
mockTenantService.setup((o) => o.getTenantId(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(mockTenantId)); mockTenantService.setup((o) => o.getTenantId(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(() => Promise.resolve(mockTenantId));
}); });
afterEach(function (): void {
sinon.restore();
});
it('Should clear cache.', async function (): Promise<void> { it('Should clear cache.', async function (): Promise<void> {
const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockAppContext, mockTreeChangeHandler.object); const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockAppContext, mockTreeChangeHandler.object);
accountTreeNode.clearCache(); accountTreeNode.clearCache();

View File

@@ -9,7 +9,6 @@ import * as azdata from 'azdata';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import 'mocha'; import 'mocha';
import { AppContext } from '../../../appContext'; import { AppContext } from '../../../appContext';
import { ApiWrapper } from '../../../apiWrapper';
import { azureResource } from '../../../azureResource/azure-resource'; import { azureResource } from '../../../azureResource/azure-resource';
import { IAzureResourceTreeChangeHandler } from '../../../azureResource/tree/treeChangeHandler'; import { IAzureResourceTreeChangeHandler } from '../../../azureResource/tree/treeChangeHandler';
@@ -24,7 +23,6 @@ import { generateGuid } from '../../../azureResource/utils';
let appContext: AppContext; let appContext: AppContext;
let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>; let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>;
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
let mockCacheService: TypeMoq.IMock<IAzureResourceCacheService>; let mockCacheService: TypeMoq.IMock<IAzureResourceCacheService>;
let mockTreeChangeHandler: TypeMoq.IMock<IAzureResourceTreeChangeHandler>; let mockTreeChangeHandler: TypeMoq.IMock<IAzureResourceTreeChangeHandler>;
@@ -63,7 +61,6 @@ const resourceService: AzureResourceService = new AzureResourceService();
describe('AzureResourceSubscriptionTreeNode.info', function(): void { describe('AzureResourceSubscriptionTreeNode.info', function(): void {
beforeEach(() => { beforeEach(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>(); mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>(); mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>();
mockCacheService.setup((o) => o.generateKey(TypeMoq.It.isAnyString())).returns(() => generateGuid()); mockCacheService.setup((o) => o.generateKey(TypeMoq.It.isAnyString())).returns(() => generateGuid());
@@ -89,7 +86,7 @@ describe('AzureResourceSubscriptionTreeNode.info', function(): void {
resourceService.registerResourceProvider(mockResourceProvider2.object); resourceService.registerResourceProvider(mockResourceProvider2.object);
resourceService.areResourceProvidersLoaded = true; resourceService.areResourceProvidersLoaded = true;
appContext = new AppContext(mockExtensionContext.object, mockApiWrapper.object); appContext = new AppContext(mockExtensionContext.object);
appContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, mockCacheService.object); appContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, mockCacheService.object);
appContext.registerService(AzureResourceServiceNames.resourceService, resourceService); appContext.registerService(AzureResourceServiceNames.resourceService, resourceService);
@@ -116,7 +113,6 @@ describe('AzureResourceSubscriptionTreeNode.info', function(): void {
describe('AzureResourceSubscriptionTreeNode.getChildren', function(): void { describe('AzureResourceSubscriptionTreeNode.getChildren', function(): void {
beforeEach(() => { beforeEach(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>(); mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>(); mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>();
mockCacheService.setup((o) => o.generateKey(TypeMoq.It.isAnyString())).returns(() => generateGuid()); mockCacheService.setup((o) => o.generateKey(TypeMoq.It.isAnyString())).returns(() => generateGuid());
@@ -142,7 +138,7 @@ describe('AzureResourceSubscriptionTreeNode.getChildren', function(): void {
resourceService.registerResourceProvider(mockResourceProvider2.object); resourceService.registerResourceProvider(mockResourceProvider2.object);
resourceService.areResourceProvidersLoaded = true; resourceService.areResourceProvidersLoaded = true;
appContext = new AppContext(mockExtensionContext.object, mockApiWrapper.object); appContext = new AppContext(mockExtensionContext.object);
appContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, mockCacheService.object); appContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, mockCacheService.object);
appContext.registerService(AzureResourceServiceNames.resourceService, resourceService); appContext.registerService(AzureResourceServiceNames.resourceService, resourceService);

View File

@@ -7,11 +7,11 @@ import * as vscode from 'vscode';
import * as should from 'should'; import * as should from 'should';
import * as TypeMoq from 'typemoq'; import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata'; import * as azdata from 'azdata';
import * as sinon from 'sinon';
import 'mocha'; import 'mocha';
import { AppContext } from '../../../appContext'; import { AppContext } from '../../../appContext';
import { ApiWrapper } from '../../../apiWrapper';
import { IAzureResourceCacheService, IAzureResourceAccountService } from '../../../azureResource/interfaces'; import { IAzureResourceCacheService } from '../../../azureResource/interfaces';
import { AzureResourceTreeProvider } from '../../../azureResource/tree/treeProvider'; import { AzureResourceTreeProvider } from '../../../azureResource/tree/treeProvider';
import { AzureResourceAccountTreeNode } from '../../../azureResource/tree/accountTreeNode'; import { AzureResourceAccountTreeNode } from '../../../azureResource/tree/accountTreeNode';
import { AzureResourceAccountNotSignedInTreeNode } from '../../../azureResource/tree/accountNotSignedInTreeNode'; import { AzureResourceAccountNotSignedInTreeNode } from '../../../azureResource/tree/accountNotSignedInTreeNode';
@@ -22,9 +22,7 @@ import { generateGuid } from '../../../azureResource/utils';
let mockAppContext: AppContext; let mockAppContext: AppContext;
let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>; let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>;
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
let mockCacheService: TypeMoq.IMock<IAzureResourceCacheService>; let mockCacheService: TypeMoq.IMock<IAzureResourceCacheService>;
let mockAccountService: TypeMoq.IMock<IAzureResourceAccountService>;
// Mock test data // Mock test data
const mockAccount1: azdata.Account = { const mockAccount1: azdata.Account = {
@@ -60,27 +58,28 @@ const mockAccounts = [mockAccount1, mockAccount2];
describe('AzureResourceTreeProvider.getChildren', function (): void { describe('AzureResourceTreeProvider.getChildren', function (): void {
beforeEach(() => { beforeEach(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>(); mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>(); mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>();
mockAccountService = TypeMoq.Mock.ofType<IAzureResourceAccountService>();
mockAppContext = new AppContext(mockExtensionContext.object, mockApiWrapper.object); mockAppContext = new AppContext(mockExtensionContext.object);
mockAppContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, mockCacheService.object); mockAppContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, mockCacheService.object);
mockAppContext.registerService<IAzureResourceAccountService>(AzureResourceServiceNames.accountService, mockAccountService.object);
mockCacheService.setup((o) => o.generateKey(TypeMoq.It.isAnyString())).returns(() => generateGuid()); mockCacheService.setup((o) => o.generateKey(TypeMoq.It.isAnyString())).returns(() => generateGuid());
}); });
afterEach(function(): void {
sinon.restore();
});
it('Should load accounts.', async function (): Promise<void> { it('Should load accounts.', async function (): Promise<void> {
mockAccountService.setup((o) => o.getAccounts()).returns(() => Promise.resolve(mockAccounts)); const getAllAccountsStub = sinon.stub(azdata.accounts, 'getAllAccounts').returns(Promise.resolve(mockAccounts));
const treeProvider = new AzureResourceTreeProvider(mockAppContext); const treeProvider = new AzureResourceTreeProvider(mockAppContext);
await treeProvider.getChildren(undefined); // Load account promise await treeProvider.getChildren(undefined); // Load account promise
const children = await treeProvider.getChildren(undefined); // Actual accounts const children = await treeProvider.getChildren(undefined); // Actual accounts
mockAccountService.verify((o) => o.getAccounts(), TypeMoq.Times.once()); should(getAllAccountsStub.calledOnce).be.true('getAllAccounts should have been called exactly once');
should(children).Array(); should(children).Array();
should(children.length).equal(mockAccounts.length); should(children.length).equal(mockAccounts.length);
@@ -94,7 +93,7 @@ describe('AzureResourceTreeProvider.getChildren', function (): void {
}); });
it('Should handle when there is no accounts.', async function (): Promise<void> { it('Should handle when there is no accounts.', async function (): Promise<void> {
mockAccountService.setup((o) => o.getAccounts()).returns(() => Promise.resolve(undefined)); sinon.stub(azdata.accounts, 'getAllAccounts').returns(Promise.resolve(undefined));
const treeProvider = new AzureResourceTreeProvider(mockAppContext); const treeProvider = new AzureResourceTreeProvider(mockAppContext);
treeProvider.isSystemInitialized = true; treeProvider.isSystemInitialized = true;

View File

@@ -222,6 +222,42 @@
resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd"
integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==
"@sinonjs/commons@^1", "@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.7.2":
version "1.8.0"
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.0.tgz#c8d68821a854c555bba172f3b06959a0039b236d"
integrity sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q==
dependencies:
type-detect "4.0.8"
"@sinonjs/fake-timers@^6.0.0", "@sinonjs/fake-timers@^6.0.1":
version "6.0.1"
resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40"
integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==
dependencies:
"@sinonjs/commons" "^1.7.0"
"@sinonjs/formatio@^5.0.1":
version "5.0.1"
resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-5.0.1.tgz#f13e713cb3313b1ab965901b01b0828ea6b77089"
integrity sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==
dependencies:
"@sinonjs/commons" "^1"
"@sinonjs/samsam" "^5.0.2"
"@sinonjs/samsam@^5.0.2", "@sinonjs/samsam@^5.0.3":
version "5.0.3"
resolved "https://registry.yarnpkg.com/@sinonjs/samsam/-/samsam-5.0.3.tgz#86f21bdb3d52480faf0892a480c9906aa5a52938"
integrity sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==
dependencies:
"@sinonjs/commons" "^1.6.0"
lodash.get "^4.4.2"
type-detect "^4.0.8"
"@sinonjs/text-encoding@^0.7.1":
version "0.7.1"
resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5"
integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==
"@types/caseless@*": "@types/caseless@*":
version "0.12.2" version "0.12.2"
resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8"
@@ -264,6 +300,18 @@
"@types/tough-cookie" "*" "@types/tough-cookie" "*"
form-data "^2.5.0" form-data "^2.5.0"
"@types/sinon@^9.0.4":
version "9.0.4"
resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-9.0.4.tgz#e934f904606632287a6e7f7ab0ce3f08a0dad4b1"
integrity sha512-sJmb32asJZY6Z2u09bl0G2wglSxDlROlAejCjsnor+LzBMz17gu8IU7vKC/vWDnv9zEq2wqADHVXFjf4eE8Gdw==
dependencies:
"@types/sinonjs__fake-timers" "*"
"@types/sinonjs__fake-timers@*":
version "6.0.1"
resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz#681df970358c82836b42f989188d133e218c458e"
integrity sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA==
"@types/tough-cookie@*": "@types/tough-cookie@*":
version "2.3.6" version "2.3.6"
resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-2.3.6.tgz#c880579e087d7a0db13777ff8af689f4ffc7b0d5" resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-2.3.6.tgz#c880579e087d7a0db13777ff8af689f4ffc7b0d5"
@@ -531,6 +579,11 @@ diff@3.5.0:
resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12"
integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==
diff@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
end-of-stream@^1.1.0, end-of-stream@^1.4.1: end-of-stream@^1.1.0, end-of-stream@^1.4.1:
version "1.4.4" version "1.4.4"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
@@ -697,6 +750,11 @@ is-fullwidth-code-point@^2.0.0:
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
isarray@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=
isarray@~1.0.0: isarray@~1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
@@ -777,6 +835,11 @@ json5@^2.1.2:
dependencies: dependencies:
minimist "^1.2.5" minimist "^1.2.5"
just-extend@^4.0.2:
version "4.1.0"
resolved "https://registry.yarnpkg.com/just-extend/-/just-extend-4.1.0.tgz#7278a4027d889601640ee0ce0e5a00b992467da4"
integrity sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==
keytar@*: keytar@*:
version "5.4.0" version "5.4.0"
resolved "https://registry.yarnpkg.com/keytar/-/keytar-5.4.0.tgz#71d8209e7dd2fe99008c243791350a6bd6ceab67" resolved "https://registry.yarnpkg.com/keytar/-/keytar-5.4.0.tgz#71d8209e7dd2fe99008c243791350a6bd6ceab67"
@@ -785,6 +848,11 @@ keytar@*:
nan "2.14.0" nan "2.14.0"
prebuild-install "5.3.3" prebuild-install "5.3.3"
lodash.get@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
lodash@^4.16.4, lodash@^4.17.13, lodash@^4.17.4: lodash@^4.16.4, lodash@^4.17.13, lodash@^4.17.4:
version "4.17.15" version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
@@ -923,6 +991,17 @@ napi-build-utils@^1.0.1:
resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806"
integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==
nise@^4.0.1:
version "4.0.4"
resolved "https://registry.yarnpkg.com/nise/-/nise-4.0.4.tgz#d73dea3e5731e6561992b8f570be9e363c4512dd"
integrity sha512-bTTRUNlemx6deJa+ZyoCUTRvH3liK5+N6VQZ4NIw90AgDXY6iPnsqplNFf6STcj+ePk0H/xqxnP75Lr0J0Fq3A==
dependencies:
"@sinonjs/commons" "^1.7.0"
"@sinonjs/fake-timers" "^6.0.0"
"@sinonjs/text-encoding" "^0.7.1"
just-extend "^4.0.2"
path-to-regexp "^1.7.0"
node-abi@^2.7.0: node-abi@^2.7.0:
version "2.15.0" version "2.15.0"
resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.15.0.tgz#51d55cc711bd9e4a24a572ace13b9231945ccb10" resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.15.0.tgz#51d55cc711bd9e4a24a572ace13b9231945ccb10"
@@ -972,6 +1051,13 @@ path-parse@^1.0.6:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
path-to-regexp@^1.7.0:
version "1.8.0"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
dependencies:
isarray "0.0.1"
pify@^4.0.1: pify@^4.0.1:
version "4.0.1" version "4.0.1"
resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
@@ -1170,6 +1256,19 @@ simple-get@^3.0.3:
once "^1.3.1" once "^1.3.1"
simple-concat "^1.0.0" simple-concat "^1.0.0"
sinon@^9.0.2:
version "9.0.2"
resolved "https://registry.yarnpkg.com/sinon/-/sinon-9.0.2.tgz#b9017e24633f4b1c98dfb6e784a5f0509f5fd85d"
integrity sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==
dependencies:
"@sinonjs/commons" "^1.7.2"
"@sinonjs/fake-timers" "^6.0.1"
"@sinonjs/formatio" "^5.0.1"
"@sinonjs/samsam" "^5.0.3"
diff "^4.0.2"
nise "^4.0.1"
supports-color "^7.1.0"
source-map@^0.5.0: source-map@^0.5.0:
version "0.5.7" version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
@@ -1307,6 +1406,11 @@ tunnel@0.0.6:
resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c"
integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==
type-detect@4.0.8, type-detect@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
typemoq@^2.1.0: typemoq@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/typemoq/-/typemoq-2.1.0.tgz#4452ce360d92cf2a1a180f0c29de2803f87af1e8" resolved "https://registry.yarnpkg.com/typemoq/-/typemoq-2.1.0.tgz#4452ce360d92cf2a1a180f0c29de2803f87af1e8"