mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-18 09:35:39 -05:00
Add arc tree data provider tests (#12758)
* Add arc tree data provider tests * Generic ResourceModel * no message * undo * Fix compile error
This commit is contained in:
77
extensions/arc/src/test/mocks/fakeAzdataApi.ts
Normal file
77
extensions/arc/src/test/mocks/fakeAzdataApi.ts
Normal file
@@ -0,0 +1,77 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as azdataExt from 'azdata-ext';
|
||||
|
||||
/**
|
||||
* Simple fake Azdata Api used to mock the API during tests
|
||||
*/
|
||||
export class FakeAzdataApi implements azdataExt.IAzdataApi {
|
||||
|
||||
public postgresInstances: azdataExt.PostgresServerListResult[] = [];
|
||||
public miaaInstances: azdataExt.SqlMiListResult[] = [];
|
||||
|
||||
//
|
||||
// API Implementation
|
||||
//
|
||||
public get arc() {
|
||||
const self = this;
|
||||
return {
|
||||
dc: {
|
||||
create(_namespace: string, _name: string, _connectivityMode: string, _resourceGroup: string, _location: string, _subscription: string, _profileName?: string, _storageClass?: string): Promise<azdataExt.AzdataOutput<void>> { throw new Error('Method not implemented.'); },
|
||||
endpoint: {
|
||||
async list(): Promise<azdataExt.AzdataOutput<azdataExt.DcEndpointListResult[]>> { return <any>{ result: [] }; }
|
||||
},
|
||||
config: {
|
||||
list(): Promise<azdataExt.AzdataOutput<azdataExt.DcConfigListResult[]>> { throw new Error('Method not implemented.'); },
|
||||
async show(): Promise<azdataExt.AzdataOutput<azdataExt.DcConfigShowResult>> { return <any>{ result: undefined! }; }
|
||||
}
|
||||
},
|
||||
postgres: {
|
||||
server: {
|
||||
delete(_name: string): Promise<azdataExt.AzdataOutput<void>> { throw new Error('Method not implemented.'); },
|
||||
async list(): Promise<azdataExt.AzdataOutput<azdataExt.PostgresServerListResult[]>> { return <any>{ result: self.postgresInstances }; },
|
||||
show(_name: string): Promise<azdataExt.AzdataOutput<azdataExt.PostgresServerShowResult>> { throw new Error('Method not implemented.'); },
|
||||
edit(
|
||||
_name: string,
|
||||
_args: {
|
||||
adminPassword?: boolean,
|
||||
coresLimit?: string,
|
||||
coresRequest?: string,
|
||||
engineSettings?: string,
|
||||
extensions?: string,
|
||||
memoryLimit?: string,
|
||||
memoryRequest?: string,
|
||||
noWait?: boolean,
|
||||
port?: number,
|
||||
replaceEngineSettings?: boolean,
|
||||
workers?: number
|
||||
},
|
||||
_additionalEnvVars?: { [key: string]: string }): Promise<azdataExt.AzdataOutput<void>> { throw new Error('Method not implemented.'); }
|
||||
}
|
||||
},
|
||||
sql: {
|
||||
mi: {
|
||||
delete(_name: string): Promise<azdataExt.AzdataOutput<void>> { throw new Error('Method not implemented.'); },
|
||||
async list(): Promise<azdataExt.AzdataOutput<azdataExt.SqlMiListResult[]>> { return <any>{ result: self.miaaInstances }; },
|
||||
show(_name: string): Promise<azdataExt.AzdataOutput<azdataExt.SqlMiShowResult>> { throw new Error('Method not implemented.'); }
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
getPath(): Promise<string> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
login(_endpoint: string, _username: string, _password: string): Promise<azdataExt.AzdataOutput<any>> {
|
||||
return <any>undefined;
|
||||
}
|
||||
version(): Promise<azdataExt.AzdataOutput<string>> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
getSemVersion(): any {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,16 +3,21 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { ControllerInfo } from 'arc';
|
||||
import { ControllerInfo, ResourceType } from 'arc';
|
||||
import 'mocha';
|
||||
import * as should from 'should';
|
||||
import * as TypeMoq from 'typemoq';
|
||||
import * as sinon from 'sinon';
|
||||
import { v4 as uuid } from 'uuid';
|
||||
import * as vscode from 'vscode';
|
||||
import * as azdataExt from 'azdata-ext';
|
||||
import { ControllerModel } from '../../../models/controllerModel';
|
||||
import { MiaaModel } from '../../../models/miaaModel';
|
||||
import { AzureArcTreeDataProvider } from '../../../ui/tree/azureArcTreeDataProvider';
|
||||
import { ControllerTreeNode } from '../../../ui/tree/controllerTreeNode';
|
||||
import { MiaaTreeNode } from '../../../ui/tree/miaaTreeNode';
|
||||
import { FakeControllerModel } from '../../mocks/fakeControllerModel';
|
||||
import { FakeAzdataApi } from '../../mocks/fakeAzdataApi';
|
||||
|
||||
describe('AzureArcTreeDataProvider tests', function (): void {
|
||||
let treeDataProvider: AzureArcTreeDataProvider;
|
||||
@@ -84,6 +89,27 @@ describe('AzureArcTreeDataProvider tests', function (): void {
|
||||
let children = await treeDataProvider.getChildren();
|
||||
should(children.length).equal(0, 'After loading we should have 0 children');
|
||||
});
|
||||
|
||||
it('should return all children of controller after loading', async function (): Promise<void> {
|
||||
const mockArcExtension = TypeMoq.Mock.ofType<vscode.Extension<any>>();
|
||||
const mockArcApi = TypeMoq.Mock.ofType<azdataExt.IExtension>();
|
||||
mockArcExtension.setup(x => x.exports).returns(() => {
|
||||
return mockArcApi.object;
|
||||
});
|
||||
const fakeAzdataApi = new FakeAzdataApi();
|
||||
fakeAzdataApi.postgresInstances = [{ name: 'pg1', state: '', workers: 0 }];
|
||||
fakeAzdataApi.miaaInstances = [{ name: 'miaa1', state: '', replicas: '', serverEndpoint: '' }];
|
||||
mockArcApi.setup(x => x.azdata).returns(() => fakeAzdataApi);
|
||||
|
||||
sinon.stub(vscode.extensions, 'getExtension').returns(mockArcExtension.object);
|
||||
const controllerModel = new ControllerModel(treeDataProvider, { id: uuid(), url: '127.0.0.1', name: 'my-arc', username: 'sa', rememberPassword: true, resources: [] }, 'mypassword');
|
||||
await treeDataProvider.addOrUpdateController(controllerModel, '');
|
||||
const controllerNode = treeDataProvider.getControllerNode(controllerModel);
|
||||
const children = await treeDataProvider.getChildren(controllerNode);
|
||||
should(children.filter(c => c.label === fakeAzdataApi.postgresInstances[0].name).length).equal(1, 'Should have a Postgres child');
|
||||
should(children.filter(c => c.label === fakeAzdataApi.miaaInstances[0].name).length).equal(1, 'Should have a MIAA child');
|
||||
should(children.length).equal(2, 'Should have excatly 2 children');
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeController', function (): void {
|
||||
@@ -104,4 +130,31 @@ describe('AzureArcTreeDataProvider tests', function (): void {
|
||||
should((await treeDataProvider.getChildren()).length).equal(0, 'Removing other node again should do nothing');
|
||||
});
|
||||
});
|
||||
|
||||
describe('openResourceDashboard', function (): void {
|
||||
it('Opening dashboard for nonexistent controller node throws', async function (): Promise<void> {
|
||||
const controllerModel = new ControllerModel(treeDataProvider, { id: uuid(), url: '127.0.0.1', name: 'my-arc', username: 'sa', rememberPassword: true, resources: [] });
|
||||
const openDashboardPromise = treeDataProvider.openResourceDashboard(controllerModel, ResourceType.sqlManagedInstances, '');
|
||||
await should(openDashboardPromise).be.rejected();
|
||||
});
|
||||
|
||||
it('Opening dashboard for nonexistent resource throws', async function (): Promise<void> {
|
||||
const controllerModel = new ControllerModel(treeDataProvider, { id: uuid(), url: '127.0.0.1', name: 'my-arc', username: 'sa', rememberPassword: true, resources: [] });
|
||||
await treeDataProvider.addOrUpdateController(controllerModel, '');
|
||||
const openDashboardPromise = treeDataProvider.openResourceDashboard(controllerModel, ResourceType.sqlManagedInstances, '');
|
||||
await should(openDashboardPromise).be.rejected();
|
||||
});
|
||||
|
||||
it('Opening dashboard for existing resource node succeeds', async function (): Promise<void> {
|
||||
const controllerModel = new ControllerModel(treeDataProvider, { id: uuid(), url: '127.0.0.1', name: 'my-arc', username: 'sa', rememberPassword: true, resources: [] });
|
||||
const miaaModel = new MiaaModel(controllerModel, { name: 'miaa-1', resourceType: ResourceType.sqlManagedInstances }, undefined!, treeDataProvider);
|
||||
await treeDataProvider.addOrUpdateController(controllerModel, '');
|
||||
const controllerNode = treeDataProvider.getControllerNode(controllerModel)!;
|
||||
const resourceNode = new MiaaTreeNode(miaaModel, controllerModel);
|
||||
sinon.stub(controllerNode, 'getResourceNode').returns(resourceNode);
|
||||
const showDashboardStub = sinon.stub(resourceNode, 'openDashboard');
|
||||
await treeDataProvider.openResourceDashboard(controllerModel, ResourceType.sqlManagedInstances, '');
|
||||
should(showDashboardStub.calledOnce).be.true('showDashboard should have been called exactly once');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -135,10 +135,14 @@ export class AzureArcTreeDataProvider implements vscode.TreeDataProvider<TreeNod
|
||||
if (resourceNode) {
|
||||
await resourceNode.openDashboard();
|
||||
} else {
|
||||
console.log(`Couldn't find resource node for ${name} (${resourceType})`);
|
||||
const errMsg = `Couldn't find resource node for ${name} (${resourceType})`;
|
||||
console.log(errMsg);
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
} else {
|
||||
console.log('Couldn\'t find controller node for opening dashboard');
|
||||
const errMsg = 'Couldn\'t find controller node for opening dashboard';
|
||||
console.log(errMsg);
|
||||
throw new Error(errMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import * as loc from '../../localizedConstants';
|
||||
import { ControllerModel, Registration } from '../../models/controllerModel';
|
||||
import { MiaaModel } from '../../models/miaaModel';
|
||||
import { PostgresModel } from '../../models/postgresModel';
|
||||
import { ResourceModel } from '../../models/resourceModel';
|
||||
import { ControllerDashboard } from '../dashboards/controller/controllerDashboard';
|
||||
import { AzureArcTreeDataProvider } from './azureArcTreeDataProvider';
|
||||
import { MiaaTreeNode } from './miaaTreeNode';
|
||||
@@ -24,7 +25,7 @@ import { TreeNode } from './treeNode';
|
||||
*/
|
||||
export class ControllerTreeNode extends TreeNode {
|
||||
|
||||
private _children: ResourceTreeNode[] = [];
|
||||
private _children: ResourceTreeNode<ResourceModel>[] = [];
|
||||
|
||||
constructor(public model: ControllerModel, private _context: vscode.ExtensionContext, private _treeDataProvider: AzureArcTreeDataProvider) {
|
||||
super(model.label, vscode.TreeItemCollapsibleState.Collapsed, ResourceType.dataControllers);
|
||||
@@ -69,14 +70,14 @@ export class ControllerTreeNode extends TreeNode {
|
||||
* @param resourceType The resourceType of the node
|
||||
* @param name The name of the node
|
||||
*/
|
||||
public getResourceNode(resourceType: string, name: string): ResourceTreeNode | undefined {
|
||||
public getResourceNode(resourceType: string, name: string): ResourceTreeNode<ResourceModel> | undefined {
|
||||
return this._children.find(c =>
|
||||
c.model?.info.resourceType === resourceType &&
|
||||
c.model.info.name === name);
|
||||
}
|
||||
|
||||
private updateChildren(registrations: Registration[]): void {
|
||||
const newChildren: ResourceTreeNode[] = [];
|
||||
const newChildren: ResourceTreeNode<ResourceModel>[] = [];
|
||||
registrations.forEach(registration => {
|
||||
if (!registration.instanceName) {
|
||||
console.warn('Registration is missing required name value, skipping');
|
||||
|
||||
@@ -8,15 +8,15 @@ import * as vscode from 'vscode';
|
||||
import { ControllerModel } from '../../models/controllerModel';
|
||||
import { MiaaModel } from '../../models/miaaModel';
|
||||
import { MiaaDashboard } from '../dashboards/miaa/miaaDashboard';
|
||||
import { TreeNode } from './treeNode';
|
||||
import { ResourceTreeNode } from './resourceTreeNode';
|
||||
|
||||
/**
|
||||
* The TreeNode for displaying a SQL Managed Instance on Azure Arc
|
||||
*/
|
||||
export class MiaaTreeNode extends TreeNode {
|
||||
export class MiaaTreeNode extends ResourceTreeNode<MiaaModel> {
|
||||
|
||||
constructor(public model: MiaaModel, private _controllerModel: ControllerModel) {
|
||||
super(model.info.name, vscode.TreeItemCollapsibleState.None, ResourceType.sqlManagedInstances);
|
||||
constructor(model: MiaaModel, private _controllerModel: ControllerModel) {
|
||||
super(model.info.name, vscode.TreeItemCollapsibleState.None, ResourceType.sqlManagedInstances, model);
|
||||
}
|
||||
|
||||
public async openDashboard(): Promise<void> {
|
||||
|
||||
@@ -13,14 +13,14 @@ import { ResourceTreeNode } from './resourceTreeNode';
|
||||
/**
|
||||
* The TreeNode for displaying an Postgres Server group
|
||||
*/
|
||||
export class PostgresTreeNode extends ResourceTreeNode {
|
||||
export class PostgresTreeNode extends ResourceTreeNode<PostgresModel> {
|
||||
|
||||
constructor(private _model: PostgresModel, private _controllerModel: ControllerModel, private _context: vscode.ExtensionContext) {
|
||||
super(_model.info.name, vscode.TreeItemCollapsibleState.None, ResourceType.postgresInstances, _model);
|
||||
constructor(model: PostgresModel, private _controllerModel: ControllerModel, private _context: vscode.ExtensionContext) {
|
||||
super(model.info.name, vscode.TreeItemCollapsibleState.None, ResourceType.postgresInstances, model);
|
||||
}
|
||||
|
||||
public async openDashboard(): Promise<void> {
|
||||
const postgresDashboard = new PostgresDashboard(this._context, this._controllerModel, this._model);
|
||||
const postgresDashboard = new PostgresDashboard(this._context, this._controllerModel, this.model);
|
||||
await postgresDashboard.showDashboard();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ import { TreeNode } from './treeNode';
|
||||
/**
|
||||
* A TreeNode belonging to a child of a Controller
|
||||
*/
|
||||
export abstract class ResourceTreeNode extends TreeNode {
|
||||
constructor(label: string, collapsibleState: vscode.TreeItemCollapsibleState, resourceType?: string, public model?: ResourceModel) {
|
||||
export abstract class ResourceTreeNode<M extends ResourceModel> extends TreeNode {
|
||||
constructor(label: string, collapsibleState: vscode.TreeItemCollapsibleState, resourceType: string, public model: M) {
|
||||
super(label, collapsibleState, resourceType);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user