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/qs": "^6.9.1",
"@types/request": "^2.48.1",
"@types/sinon": "^9.0.4",
"@types/ws": "^6.0.4",
"mocha": "^5.2.0",
"mocha-junit-reporter": "^1.17.0",
"mocha-multi-reporters": "^1.1.7",
"should": "^13.2.1",
"sinon": "^9.0.2",
"typemoq": "^2.1.0",
"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 { ApiWrapper } from './apiWrapper';
/**
* Global context for the application
@@ -12,9 +11,7 @@ import { ApiWrapper } from './apiWrapper';
export class AppContext {
private serviceMap: Map<string, any> = new Map();
constructor(public readonly extensionContext: vscode.ExtensionContext, public readonly apiWrapper: ApiWrapper) {
this.apiWrapper = apiWrapper || new ApiWrapper();
}
constructor(public readonly extensionContext: vscode.ExtensionContext) { }
public getService<T>(serviceName: string): 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.
*--------------------------------------------------------------------------------------------*/
import { window, QuickPickItem, env, Uri } from 'vscode';
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import { TokenCredentials } from '@azure/ms-rest-js';
import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
@@ -21,12 +20,12 @@ import { AzureResourceServiceNames } from './constants';
import { AzureAccount, Tenant } from '../account-provider/interfaces';
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 {
const enablePreviewFeatures = appContext.apiWrapper.getConfiguration('workbench').get('enablePreviewFeatures');
const enablePreviewFeatures = vscode.workspace.getConfiguration('workbench').get('enablePreviewFeatures');
if (!enablePreviewFeatures) {
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;
}
if (!node || !(node instanceof AzureResourceAccountTreeNode)) {
@@ -36,28 +35,28 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
const accountNode = node as AzureResourceAccountTreeNode;
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 listOfTenants = azureAccount.properties.tenants.map(t => t.displayName);
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;
}
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) {
// Don't show quickpick for a single option
tenant = azureAccount.properties.tenants[0];
} else {
const pickedTenant = await window.showQuickPick(listOfTenants, { canPickMany: false });
const pickedTenant = await vscode.window.showQuickPick(listOfTenants, { canPickMany: false });
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;
}
@@ -68,13 +67,13 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
await terminalService.getOrCreateCloudConsole(azureAccount, tenant, tokens);
} catch (ex) {
console.error(ex);
window.showErrorMessage(ex);
vscode.window.showErrorMessage(ex);
}
});
// 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)) {
return;
}
@@ -92,7 +91,7 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
const subscriptions = (await accountNode.getCachedSubscriptions()) || <azureResource.AzureResourceSubscription[]>[];
if (subscriptions.length === 0) {
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) {
const token = tokens[tenant.id].token;
@@ -119,7 +118,7 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
selectedSubscriptionIds.push(...subscriptions.map((subscription) => subscription.id));
}
interface AzureResourceSubscriptionQuickPickItem extends QuickPickItem {
interface AzureResourceSubscriptionQuickPickItem extends vscode.QuickPickItem {
subscription: azureResource.AzureResourceSubscription;
}
@@ -131,7 +130,7 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
};
}).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) {
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);
});
appContext.apiWrapper.registerCommand('azure.resource.signin', async (node?: TreeNode) => {
appContext.apiWrapper.executeCommand('workbench.actions.modal.linkedAccount');
vscode.commands.registerCommand('azure.resource.signin', async (node?: TreeNode) => {
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) {
return;
}
@@ -161,13 +160,13 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
}
// Ensure connection is saved to the Connections list, then open connection dialog
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) {
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 (
!connectionProfile.azureResourceId ||
@@ -178,6 +177,6 @@ export function registerAzureResourceCommands(appContext: AppContext, tree: Azur
}
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 { Account, DidChangeAccountsParams } from 'azdata';
import { Event } from 'vscode';
import { Account } from 'azdata';
import { azureResource } from './azure-resource';
import { AzureAccount, AzureAccountSecurityToken, Tenant } from '../account-provider/interfaces';
export interface IAzureResourceAccountService {
getAccounts(): Promise<Account[]>;
readonly onDidChangeAccounts: Event<DidChangeAccountsParams>;
}
export interface IAzureResourceSubscriptionService {
getSubscriptions(account: Account, credential: msRest.ServiceClientCredentials): Promise<azureResource.AzureResourceSubscription[]>;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -9,7 +9,6 @@ import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
import { AzureResourceItemType } from '../../constants';
import { ApiWrapper } from '../../../apiWrapper';
import { generateGuid } from '../../utils';
import { IAzureResourceService } from '../../interfaces';
import { ResourceTreeDataProviderBase } from '../resourceTreeDataProviderBase';
@@ -21,10 +20,9 @@ export class PostgresServerTreeDataProvider extends ResourceTreeDataProviderBase
public constructor(
databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>,
apiWrapper: ApiWrapper,
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 { azureResource } from '../azure-resource';
import { ApiWrapper } from '../../apiWrapper';
import { IAzureResourceService } from '../interfaces';
import { AzureResourceErrorMessageUtil } from '../utils';
import { ResourceGraphClient } from '@azure/arm-resourcegraph';
export abstract class ResourceTreeDataProviderBase<T extends azureResource.AzureResource> implements azureResource.IAzureResourceTreeDataProvider {
public constructor(
protected _resourceService: IAzureResourceService<T>,
protected _apiWrapper: ApiWrapper
) {
public constructor(protected _resourceService: IAzureResourceService<T>) {
}
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[]> {
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 resources: T[] = await this._resourceService.getResources(element.subscription, credential, element.account) || <T[]>[];

View File

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

View File

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

View File

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

View File

@@ -9,7 +9,6 @@ import * as nls from 'vscode-nls';
const localize = nls.loadMessageBundle();
import { AzureResourceItemType } from '../../constants';
import { ApiWrapper } from '../../../apiWrapper';
import { generateGuid } from '../../utils';
import { IAzureResourceService } from '../../interfaces';
import { ResourceTreeDataProviderBase } from '../resourceTreeDataProviderBase';
@@ -21,10 +20,9 @@ export class SqlInstanceArcTreeDataProvider extends ResourceTreeDataProviderBase
public constructor(
databaseServerService: IAzureResourceService<azureResource.AzureResourceDatabaseServer>,
apiWrapper: ApiWrapper,
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.
*--------------------------------------------------------------------------------------------*/
import { TreeItem, TreeItemCollapsibleState } from 'vscode';
import { Account, NodeInfo, AzureResource } from 'azdata';
import * as vscode from 'vscode';
import * as azdata from 'azdata';
import { TokenCredentials } from '@azure/ms-rest-js';
import * as nls from 'vscode-nls';
@@ -24,7 +24,7 @@ import { IAzureResourceSubscriptionService, IAzureResourceSubscriptionFilterServ
export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNodeBase {
public constructor(
public readonly account: Account,
public readonly account: azdata.Account,
appContext: AppContext,
treeChangeHandler: IAzureResourceTreeChangeHandler
) {
@@ -42,7 +42,7 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
public async getChildren(): Promise<TreeNode[]> {
try {
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) {
try {
@@ -99,7 +99,7 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
}
} catch (error) {
if (error instanceof AzureResourceCredentialError) {
this.appContext.apiWrapper.executeCommand('azure.resource.signin');
vscode.commands.executeCommand('azure.resource.signin');
}
return [AzureResourceMessageTreeNode.create(AzureResourceErrorMessageUtil.getErrorMessage(error), this)];
}
@@ -109,8 +109,8 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
return this.getCache<azureResource.AzureResourceSubscription[]>();
}
public getTreeItem(): TreeItem | Promise<TreeItem> {
const item = new TreeItem(this._label, TreeItemCollapsibleState.Collapsed);
public getTreeItem(): vscode.TreeItem | Promise<vscode.TreeItem> {
const item = new vscode.TreeItem(this._label, vscode.TreeItemCollapsibleState.Collapsed);
item.id = this._id;
item.contextValue = AzureResourceItemType.account;
item.iconPath = {
@@ -120,7 +120,7 @@ export class AzureResourceAccountTreeNode extends AzureResourceContainerTreeNode
return item;
}
public getNodeInfo(): NodeInfo {
public getNodeInfo(): azdata.NodeInfo {
return {
label: this._label,
isLeaf: false,

View File

@@ -3,7 +3,7 @@
* 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 { AppContext } from '../../appContext';
import * as nls from 'vscode-nls';
@@ -16,41 +16,29 @@ import { AzureResourceMessageTreeNode } from '../messageTreeNode';
import { AzureResourceContainerTreeNodeBase } from './baseTreeNodes';
import { AzureResourceErrorMessageUtil, equals } from '../utils';
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;
private accountService: IAzureResourceAccountService;
private accounts: azdata.Account[];
private _onDidChangeTreeData = new EventEmitter<TreeNode>();
private _onDidChangeTreeData = new vscode.EventEmitter<TreeNode>();
private loadingAccountsPromise: Promise<void>;
public constructor(public readonly appContext: AppContext) {
if (appContext) {
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
let accounts = await this.accountService.getAccounts();
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 notifyNodeChanged event triggers a refresh which triggers a getChildren which can trigger this callback
// this below check short-circuits the infinite callback loop
this.setSystemInitialized();
if (!equals(accounts, this.accounts)) {
this.accounts = accounts;
this.notifyNodeChanged(undefined);
}
});
}
public constructor(private readonly appContext: AppContext) {
azdata.accounts.onDidChangeAccounts(async (e: azdata.DidChangeAccountsParams) => {
// This event sends it per provider, we need to make sure we get all the azure related accounts
let accounts = await azdata.accounts.getAllAccounts();
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 notifyNodeChanged event triggers a refresh which triggers a getChildren which can trigger this callback
// this below check short-circuits the infinite callback loop
this.setSystemInitialized();
if (!equals(accounts, this.accounts)) {
this.accounts = accounts;
this.notifyNodeChanged(undefined);
}
});
}
public async getChildren(element?: TreeNode): Promise<TreeNode[]> {
@@ -78,7 +66,7 @@ export class AzureResourceTreeProvider implements TreeDataProvider<TreeNode>, IA
private async loadAccounts(): Promise<void> {
try {
this.accounts = await this.appContext.getService<IAzureResourceAccountService>(AzureResourceServiceNames.accountService).getAccounts();
this.accounts = await azdata.accounts.getAllAccounts();
// System has been initialized
this.setSystemInitialized();
this._onDidChangeTreeData.fire(undefined);
@@ -93,7 +81,7 @@ export class AzureResourceTreeProvider implements TreeDataProvider<TreeNode>, IA
this.loadingAccountsPromise = undefined;
}
public get onDidChangeTreeData(): Event<TreeNode> {
public get onDidChangeTreeData(): vscode.Event<TreeNode> {
return this._onDidChangeTreeData.event;
}
@@ -111,7 +99,7 @@ export class AzureResourceTreeProvider implements TreeDataProvider<TreeNode>, IA
this._onDidChangeTreeData.fire(node);
}
public getTreeItem(element: TreeNode): TreeItem | Thenable<TreeItem> {
public getTreeItem(element: TreeNode): vscode.TreeItem | Thenable<vscode.TreeItem> {
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 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; }) => {
try {
const token = tokens[tenant.id].token;

View File

@@ -10,7 +10,6 @@ import * as path from 'path';
import * as os from 'os';
import { AppContext } from './appContext';
import { ApiWrapper } from './apiWrapper';
import { AzureAccountProviderService } from './account-provider/azureAccountProviderService';
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 { AzureResourceDatabaseService } from './azureResource/providers/database/databaseService';
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 { AzureResourceAccountService } from './azureResource/services/accountService';
import { AzureResourceSubscriptionService } from './azureResource/services/subscriptionService';
import { AzureResourceSubscriptionFilterService } from './azureResource/services/subscriptionFilterService';
import { AzureResourceCacheService } from './azureResource/services/cacheService';
@@ -41,6 +39,7 @@ import * as azurecore from './azurecore';
import * as azureResourceUtils from './azureResource/utils';
import * as utils from './utils';
import * as loc from './localizedConstants';
import * as constants from './constants';
import { AzureResourceGroupService } from './azureResource/providers/resourceGroup/resourceGroupService';
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
export async function activate(context: vscode.ExtensionContext): Promise<azurecore.IExtension> {
extensionContext = context;
const apiWrapper = new ApiWrapper();
let appContext = new AppContext(extensionContext, apiWrapper);
let appContext = new AppContext(extensionContext);
let storagePath = await findOrMakeStoragePath();
if (!storagePath) {
return undefined;
}
updatePiiLoggingLevel(apiWrapper);
updatePiiLoggingLevel();
// Create the provider service and activate
initAzureAccountProvider(extensionContext, storagePath).catch((err) => console.log(err));
registerAzureServices(appContext);
const azureResourceTree = new AzureResourceTreeProvider(appContext);
pushDisposable(apiWrapper.registerTreeDataProvider('azureResourceExplorer', azureResourceTree));
pushDisposable(apiWrapper.onDidChangeConfiguration(e => onDidChangeConfiguration(e, apiWrapper), this));
pushDisposable(vscode.window.registerTreeDataProvider('azureResourceExplorer', azureResourceTree));
pushDisposable(vscode.workspace.onDidChangeConfiguration(e => onDidChangeConfiguration(e), this));
registerAzureResourceCommands(appContext, azureResourceTree);
return {
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); },
provideResources(): azureResource.IAzureResourceProvider[] {
const arcFeaturedEnabled = apiWrapper.getExtensionConfiguration().get('enableArcFeatures');
const arcFeaturedEnabled = vscode.workspace.getConfiguration(constants.extensionConfigSectionName).get('enableArcFeatures');
const providers: azureResource.IAzureResourceProvider[] = [
new AzureResourceDatabaseServerProvider(new AzureResourceDatabaseServerService(), apiWrapper, extensionContext),
new AzureResourceDatabaseProvider(new AzureResourceDatabaseService(), apiWrapper, extensionContext),
new SqlInstanceProvider(new SqlInstanceResourceService(), apiWrapper, extensionContext),
new PostgresServerProvider(new PostgresServerService(), apiWrapper, extensionContext),
new AzureResourceDatabaseServerProvider(new AzureResourceDatabaseServerService(), extensionContext),
new AzureResourceDatabaseProvider(new AzureResourceDatabaseService(), extensionContext),
new SqlInstanceProvider(new SqlInstanceResourceService(), extensionContext),
new PostgresServerProvider(new PostgresServerService(), extensionContext),
];
if (arcFeaturedEnabled) {
providers.push(
new SqlInstanceArcProvider(new SqlInstanceArcResourceService(), apiWrapper, extensionContext),
new PostgresServerArcProvider(new PostgresServerArcService(), apiWrapper, extensionContext)
new SqlInstanceArcProvider(new SqlInstanceArcResourceService(), extensionContext),
new PostgresServerArcProvider(new PostgresServerArcService(), extensionContext)
);
}
return providers;
@@ -152,7 +150,6 @@ async function initAzureAccountProvider(extensionContext: vscode.ExtensionContex
function registerAzureServices(appContext: AppContext): void {
appContext.registerService<AzureResourceService>(AzureResourceServiceNames.resourceService, new AzureResourceService());
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<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService, new AzureResourceSubscriptionService());
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));
}
async function onDidChangeConfiguration(e: vscode.ConfigurationChangeEvent, apiWrapper: ApiWrapper): Promise<void> {
async function onDidChangeConfiguration(e: vscode.ConfigurationChangeEvent): Promise<void> {
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) {
await apiWrapper.executeCommand('workbench.action.reloadWindow');
await vscode.commands.executeCommand('workbench.action.reloadWindow');
}
return;
}
if (e.affectsConfiguration('azure.piiLogging')) {
updatePiiLoggingLevel(apiWrapper);
updatePiiLoggingLevel();
}
}
function updatePiiLoggingLevel(apiWrapper: ApiWrapper) {
const piiLogging: boolean = apiWrapper.getExtensionConfiguration().get('piiLogging');
function updatePiiLoggingLevel() {
const piiLogging: boolean = vscode.workspace.getConfiguration(constants.extensionConfigSectionName).get('piiLogging');
Logger.piiLogging = piiLogging;
}

View File

@@ -7,10 +7,10 @@ import * as should from 'should';
import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import * as sinon from 'sinon';
import 'mocha';
import { azureResource } from '../../../../azureResource/azure-resource';
import { ApiWrapper } from '../../../../apiWrapper';
import { AzureResourceDatabaseTreeDataProvider } from '../../../../azureResource/providers/database/databaseTreeDataProvider';
import { AzureResourceItemType } from '../../../../azureResource/constants';
import { IAzureResourceService } from '../../../../azureResource/interfaces';
@@ -19,7 +19,6 @@ import settings from '../../../../account-provider/providerSettings';
// Mock services
let mockDatabaseService: TypeMoq.IMock<IAzureResourceService<azureResource.AzureResourceDatabase>>;
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>;
// Mock test data
@@ -88,12 +87,11 @@ const mockDatabases: azureResource.AzureResourceDatabase[] = [
describe('AzureResourceDatabaseTreeDataProvider.info', function (): void {
beforeEach(() => {
mockDatabaseService = TypeMoq.Mock.ofType<IAzureResourceService<azureResource.AzureResourceDatabase>>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
});
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);
should(treeItem.id).equal(mockResourceRootNode.treeItem.id);
@@ -106,16 +104,19 @@ describe('AzureResourceDatabaseTreeDataProvider.info', function (): void {
describe('AzureResourceDatabaseTreeDataProvider.getChildren', function (): void {
beforeEach(() => {
mockDatabaseService = TypeMoq.Mock.ofType<IAzureResourceService<azureResource.AzureResourceDatabase>>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
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));
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> {
const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockApiWrapper.object, mockExtensionContext.object);
const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockExtensionContext.object);
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> {
const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockApiWrapper.object, mockExtensionContext.object);
const treeDataProvider = new AzureResourceDatabaseTreeDataProvider(mockDatabaseService.object, mockExtensionContext.object);
const children = await treeDataProvider.getChildren(mockResourceRootNode);

View File

@@ -7,17 +7,16 @@ import * as should from 'should';
import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import * as sinon from 'sinon';
import 'mocha';
import { azureResource } from '../../../../azureResource/azure-resource';
import { ApiWrapper } from '../../../../apiWrapper';
import { AzureResourceDatabaseServerTreeDataProvider } from '../../../../azureResource/providers/databaseServer/databaseServerTreeDataProvider';
import { AzureResourceItemType } from '../../../../azureResource/constants';
import { IAzureResourceService } from '../../../../azureResource/interfaces';
// Mock services
let mockDatabaseServerService: TypeMoq.IMock<IAzureResourceService<azureResource.AzureResourceDatabaseServer>>;
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>;
import settings from '../../../../account-provider/providerSettings';
import { AzureAccount } from '../../../../account-provider/interfaces';
@@ -88,12 +87,11 @@ const mockDatabaseServers: azureResource.AzureResourceDatabaseServer[] = [
describe('AzureResourceDatabaseServerTreeDataProvider.info', function (): void {
beforeEach(() => {
mockDatabaseServerService = TypeMoq.Mock.ofType<IAzureResourceService<azureResource.AzureResourceDatabaseServer>>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
});
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);
should(treeItem.id).equal(mockResourceRootNode.treeItem.id);
@@ -106,16 +104,19 @@ describe('AzureResourceDatabaseServerTreeDataProvider.info', function (): void {
describe('AzureResourceDatabaseServerTreeDataProvider.getChildren', function (): void {
beforeEach(() => {
mockDatabaseServerService = TypeMoq.Mock.ofType<IAzureResourceService<azureResource.AzureResourceDatabaseServer>>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
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));
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> {
const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockApiWrapper.object, mockExtensionContext.object);
const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockExtensionContext.object);
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> {
const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockApiWrapper.object, mockExtensionContext.object);
const treeDataProvider = new AzureResourceDatabaseServerTreeDataProvider(mockDatabaseServerService.object, mockExtensionContext.object);
const children = await treeDataProvider.getChildren(mockResourceRootNode);

View File

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

View File

@@ -7,6 +7,7 @@ import * as should from 'should';
import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import * as sinon from 'sinon';
import 'mocha';
import { TokenCredentials } from '@azure/ms-rest-js';
import { AppContext } from '../../../appContext';
@@ -23,18 +24,16 @@ import { AzureResourceAccountTreeNode } from '../../../azureResource/tree/accoun
import { AzureResourceSubscriptionTreeNode } from '../../../azureResource/tree/subscriptionTreeNode';
import { AzureResourceItemType, AzureResourceServiceNames } from '../../../azureResource/constants';
import { AzureResourceMessageTreeNode } from '../../../azureResource/messageTreeNode';
import { ApiWrapper } from '../../../apiWrapper';
import { generateGuid } from '../../../azureResource/utils';
// Mock services
let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>;
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
let mockCacheService: TypeMoq.IMock<IAzureResourceCacheService>;
let mockSubscriptionService: TypeMoq.IMock<IAzureResourceSubscriptionService>;
let mockSubscriptionFilterService: TypeMoq.IMock<IAzureResourceSubscriptionFilterService>;
let mockTenantService: TypeMoq.IMock<IAzureResourceTenantService>;
let mockAppContext: AppContext;
let getSecurityTokenStub: sinon.SinonStub;
let mockTreeChangeHandler: TypeMoq.IMock<IAzureResourceTreeChangeHandler>;
// Mock test data
@@ -91,7 +90,6 @@ let mockSubscriptionCache: azureResource.AzureResourceSubscription[] = [];
describe('AzureResourceAccountTreeNode.info', function (): void {
beforeEach(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>();
mockSubscriptionService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionService>();
mockSubscriptionFilterService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionFilterService>();
@@ -101,19 +99,23 @@ describe('AzureResourceAccountTreeNode.info', function (): void {
mockSubscriptionCache = [];
mockAppContext = new AppContext(mockExtensionContext.object, mockApiWrapper.object);
mockAppContext = new AppContext(mockExtensionContext.object);
mockAppContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, mockCacheService.object);
mockAppContext.registerService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService, mockSubscriptionService.object);
mockAppContext.registerService<IAzureResourceSubscriptionFilterService>(AzureResourceServiceNames.subscriptionFilterService, mockSubscriptionFilterService.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.get(TypeMoq.It.isAnyString())).returns(() => mockSubscriptionCache);
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));
});
afterEach(function (): void {
sinon.restore();
});
it('Should be correct when created.', async function (): Promise<void> {
const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockAppContext, mockTreeChangeHandler.object);
@@ -179,7 +181,6 @@ describe('AzureResourceAccountTreeNode.info', function (): void {
describe('AzureResourceAccountTreeNode.getChildren', function (): void {
beforeEach(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>();
mockSubscriptionService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionService>();
mockSubscriptionFilterService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionFilterService>();
@@ -189,19 +190,23 @@ describe('AzureResourceAccountTreeNode.getChildren', function (): void {
mockSubscriptionCache = [];
mockAppContext = new AppContext(mockExtensionContext.object, mockApiWrapper.object);
mockAppContext = new AppContext(mockExtensionContext.object);
mockAppContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, mockCacheService.object);
mockAppContext.registerService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService, mockSubscriptionService.object);
mockAppContext.registerService<IAzureResourceSubscriptionFilterService>(AzureResourceServiceNames.subscriptionFilterService, mockSubscriptionFilterService.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.get(TypeMoq.It.isAnyString())).returns(() => mockSubscriptionCache);
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));
});
afterEach(function (): void {
sinon.restore();
});
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));
mockSubscriptionFilterService.setup((o) => o.getSelectedSubscriptions(mockAccount)).returns(() => Promise.resolve([]));
@@ -300,7 +305,7 @@ describe('AzureResourceAccountTreeNode.getChildren', function (): void {
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());
mockSubscriptionFilterService.verify((o) => o.getSelectedSubscriptions(mockAccount), TypeMoq.Times.once());
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 {
beforeEach(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
mockCacheService = TypeMoq.Mock.ofType<IAzureResourceCacheService>();
mockSubscriptionService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionService>();
mockSubscriptionFilterService = TypeMoq.Mock.ofType<IAzureResourceSubscriptionFilterService>();
@@ -327,19 +331,23 @@ describe('AzureResourceAccountTreeNode.clearCache', function (): void {
mockSubscriptionCache = [];
mockAppContext = new AppContext(mockExtensionContext.object, mockApiWrapper.object);
mockAppContext = new AppContext(mockExtensionContext.object);
mockAppContext.registerService<IAzureResourceCacheService>(AzureResourceServiceNames.cacheService, mockCacheService.object);
mockAppContext.registerService<IAzureResourceSubscriptionService>(AzureResourceServiceNames.subscriptionService, mockSubscriptionService.object);
mockAppContext.registerService<IAzureResourceSubscriptionFilterService>(AzureResourceServiceNames.subscriptionFilterService, mockSubscriptionFilterService.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.get(TypeMoq.It.isAnyString())).returns(() => mockSubscriptionCache);
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));
});
afterEach(function (): void {
sinon.restore();
});
it('Should clear cache.', async function (): Promise<void> {
const accountTreeNode = new AzureResourceAccountTreeNode(mockAccount, mockAppContext, mockTreeChangeHandler.object);
accountTreeNode.clearCache();

View File

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

View File

@@ -7,11 +7,11 @@ import * as vscode from 'vscode';
import * as should from 'should';
import * as TypeMoq from 'typemoq';
import * as azdata from 'azdata';
import * as sinon from 'sinon';
import 'mocha';
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 { AzureResourceAccountTreeNode } from '../../../azureResource/tree/accountTreeNode';
import { AzureResourceAccountNotSignedInTreeNode } from '../../../azureResource/tree/accountNotSignedInTreeNode';
@@ -22,9 +22,7 @@ import { generateGuid } from '../../../azureResource/utils';
let mockAppContext: AppContext;
let mockExtensionContext: TypeMoq.IMock<vscode.ExtensionContext>;
let mockApiWrapper: TypeMoq.IMock<ApiWrapper>;
let mockCacheService: TypeMoq.IMock<IAzureResourceCacheService>;
let mockAccountService: TypeMoq.IMock<IAzureResourceAccountService>;
// Mock test data
const mockAccount1: azdata.Account = {
@@ -60,27 +58,28 @@ const mockAccounts = [mockAccount1, mockAccount2];
describe('AzureResourceTreeProvider.getChildren', function (): void {
beforeEach(() => {
mockExtensionContext = TypeMoq.Mock.ofType<vscode.ExtensionContext>();
mockApiWrapper = TypeMoq.Mock.ofType<ApiWrapper>();
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<IAzureResourceAccountService>(AzureResourceServiceNames.accountService, mockAccountService.object);
mockCacheService.setup((o) => o.generateKey(TypeMoq.It.isAnyString())).returns(() => generateGuid());
});
afterEach(function(): void {
sinon.restore();
});
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);
await treeProvider.getChildren(undefined); // Load account promise
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.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> {
mockAccountService.setup((o) => o.getAccounts()).returns(() => Promise.resolve(undefined));
sinon.stub(azdata.accounts, 'getAllAccounts').returns(Promise.resolve(undefined));
const treeProvider = new AzureResourceTreeProvider(mockAppContext);
treeProvider.isSystemInitialized = true;

View File

@@ -222,6 +222,42 @@
resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd"
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@*":
version "0.12.2"
resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8"
@@ -264,6 +300,18 @@
"@types/tough-cookie" "*"
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@*":
version "2.3.6"
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"
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:
version "1.4.4"
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"
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:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
@@ -777,6 +835,11 @@ json5@^2.1.2:
dependencies:
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@*:
version "5.4.0"
resolved "https://registry.yarnpkg.com/keytar/-/keytar-5.4.0.tgz#71d8209e7dd2fe99008c243791350a6bd6ceab67"
@@ -785,6 +848,11 @@ keytar@*:
nan "2.14.0"
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:
version "4.17.15"
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"
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:
version "2.15.0"
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"
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:
version "4.0.1"
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"
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:
version "0.5.7"
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"
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:
version "2.1.0"
resolved "https://registry.yarnpkg.com/typemoq/-/typemoq-2.1.0.tgz#4452ce360d92cf2a1a180f0c29de2803f87af1e8"