mirror of https://github.com/grafana/grafana
AzureMonitor: ResourceMonitor children refactor (#34591)
* AzureMonitor: Refactor children to be an arrayu * Add some resourcePickerData tests * update tests * some quick NestedResourceTable testspull/34631/head
parent
a337f70469
commit
1d3bcb0e90
@ -0,0 +1,80 @@ |
||||
import { AzureGraphResponse, RawAzureResourceGroupItem, RawAzureResourceItem } from '../types'; |
||||
|
||||
export const createMockARGResourceContainersResponse = (): AzureGraphResponse<RawAzureResourceGroupItem[]> => ({ |
||||
data: [ |
||||
{ |
||||
subscriptionURI: '/subscriptions/abc-123', |
||||
subscriptionName: 'Primary Subscription', |
||||
resourceGroupURI: '/subscriptions/abc-123/resourceGroups/prod', |
||||
resourceGroupName: 'Production', |
||||
}, |
||||
|
||||
{ |
||||
subscriptionURI: '/subscription/def-456', |
||||
subscriptionName: 'Dev Subscription', |
||||
resourceGroupURI: '/subscription/def-456/resourceGroups/dev', |
||||
resourceGroupName: 'Development', |
||||
}, |
||||
|
||||
{ |
||||
subscriptionURI: '/subscription/def-456', |
||||
subscriptionName: 'Dev Subscription', |
||||
resourceGroupURI: '/subscription/def-456/resourceGroups/test', |
||||
resourceGroupName: 'Test', |
||||
}, |
||||
|
||||
{ |
||||
subscriptionURI: '/subscriptions/abc-123', |
||||
subscriptionName: 'Primary Subscription', |
||||
resourceGroupURI: '/subscriptions/abc-123/resourceGroups/pre-prod', |
||||
resourceGroupName: 'Pre-production', |
||||
}, |
||||
|
||||
{ |
||||
subscriptionURI: '/subscription/def-456', |
||||
subscriptionName: 'Dev Subscription', |
||||
resourceGroupURI: '/subscription/def-456/resourceGroups/qa', |
||||
resourceGroupName: 'QA', |
||||
}, |
||||
], |
||||
}); |
||||
|
||||
export const createARGResourcesResponse = (): AzureGraphResponse<RawAzureResourceItem[]> => ({ |
||||
data: [ |
||||
{ |
||||
id: '/subscription/def-456/resourceGroups/dev/providers/Microsoft.Compute/virtualMachines/web-server', |
||||
name: 'web-server', |
||||
type: 'Microsoft.Compute/virtualMachines', |
||||
resourceGroup: 'dev', |
||||
subscriptionId: 'def-456', |
||||
location: 'northeurope', |
||||
}, |
||||
|
||||
{ |
||||
id: '/subscription/def-456/resourceGroups/dev/providers/Microsoft.Compute/disks/web-server_DataDisk', |
||||
name: 'web-server_DataDisk', |
||||
type: 'Microsoft.Compute/disks', |
||||
resourceGroup: 'dev', |
||||
subscriptionId: 'def-456', |
||||
location: 'northeurope', |
||||
}, |
||||
|
||||
{ |
||||
id: '/subscription/def-456/resourceGroups/dev/providers/Microsoft.Compute/virtualMachines/db-server', |
||||
name: 'db-server', |
||||
type: 'Microsoft.Compute/virtualMachines', |
||||
resourceGroup: 'dev', |
||||
subscriptionId: 'def-456', |
||||
location: 'northeurope', |
||||
}, |
||||
|
||||
{ |
||||
id: '/subscription/def-456/resourceGroups/dev/providers/Microsoft.Compute/disks/db-server_DataDisk', |
||||
name: 'db-server_DataDisk', |
||||
type: 'Microsoft.Compute/disks', |
||||
resourceGroup: 'dev', |
||||
subscriptionId: 'def-456', |
||||
location: 'northeurope', |
||||
}, |
||||
], |
||||
}); |
||||
@ -0,0 +1,24 @@ |
||||
import { DataSourcePluginMeta } from '@grafana/data'; |
||||
import { AzureDataSourceInstanceSettings } from '../types'; |
||||
|
||||
export const createMockInstanceSetttings = (): AzureDataSourceInstanceSettings => ({ |
||||
url: '/ds/1', |
||||
id: 1, |
||||
uid: 'abc', |
||||
type: 'azuremonitor', |
||||
meta: {} as DataSourcePluginMeta, |
||||
name: 'azure', |
||||
|
||||
jsonData: { |
||||
cloudName: 'azuremonitor', |
||||
azureAuthType: 'clientsecret', |
||||
|
||||
// monitor
|
||||
tenantId: 'abc-123', |
||||
clientId: 'def-456', |
||||
subscriptionId: 'ghi-789', |
||||
|
||||
// logs
|
||||
azureLogAnalyticsSameAs: true, |
||||
}, |
||||
}); |
||||
@ -0,0 +1,88 @@ |
||||
import { ResourceRowGroup, ResourceRowType } from '../components/ResourcePicker/types'; |
||||
|
||||
export const createMockResourcePickerRows = (): ResourceRowGroup => [ |
||||
{ |
||||
id: '/subscriptions/abc-123', |
||||
name: 'Primary Subscription', |
||||
type: ResourceRowType.Subscription, |
||||
typeLabel: 'Subscription', |
||||
children: [ |
||||
{ |
||||
id: '/subscriptions/abc-123/resourceGroups/prod', |
||||
name: 'Production', |
||||
type: ResourceRowType.ResourceGroup, |
||||
typeLabel: 'Resource Group', |
||||
children: [], |
||||
}, |
||||
{ |
||||
id: '/subscriptions/abc-123/resourceGroups/pre-prod', |
||||
name: 'Pre-production', |
||||
type: ResourceRowType.ResourceGroup, |
||||
typeLabel: 'Resource Group', |
||||
children: [], |
||||
}, |
||||
], |
||||
}, |
||||
|
||||
{ |
||||
id: '/subscriptions/def-456', |
||||
name: 'Dev Subscription', |
||||
type: ResourceRowType.Subscription, |
||||
typeLabel: 'Subscription', |
||||
children: [ |
||||
{ |
||||
id: '/subscriptions/def-456/resourceGroups/dev', |
||||
name: 'Development', |
||||
type: ResourceRowType.ResourceGroup, |
||||
typeLabel: 'Resource Group', |
||||
children: [ |
||||
{ |
||||
id: '/subscription/def-456/resourceGroups/dev/providers/Microsoft.Compute/virtualMachines/web-server', |
||||
name: 'web-server', |
||||
typeLabel: 'Microsoft.Compute/virtualMachines', |
||||
type: ResourceRowType.Resource, |
||||
location: 'northeurope', |
||||
}, |
||||
|
||||
{ |
||||
id: '/subscription/def-456/resourceGroups/dev/providers/Microsoft.Compute/disks/web-server_DataDisk', |
||||
name: 'web-server_DataDisk', |
||||
typeLabel: 'Microsoft.Compute/disks', |
||||
type: ResourceRowType.Resource, |
||||
location: 'northeurope', |
||||
}, |
||||
|
||||
{ |
||||
id: '/subscription/def-456/resourceGroups/dev/providers/Microsoft.Compute/virtualMachines/db-server', |
||||
name: 'db-server', |
||||
typeLabel: 'Microsoft.Compute/virtualMachines', |
||||
type: ResourceRowType.Resource, |
||||
location: 'northeurope', |
||||
}, |
||||
|
||||
{ |
||||
id: '/subscription/def-456/resourceGroups/dev/providers/Microsoft.Compute/disks/db-server_DataDisk', |
||||
name: 'db-server_DataDisk', |
||||
typeLabel: 'Microsoft.Compute/disks', |
||||
type: ResourceRowType.Resource, |
||||
location: 'northeurope', |
||||
}, |
||||
], |
||||
}, |
||||
{ |
||||
id: '/subscriptions/def-456/resourceGroups/test', |
||||
name: 'Test', |
||||
type: ResourceRowType.ResourceGroup, |
||||
typeLabel: 'Resource Group', |
||||
children: [], |
||||
}, |
||||
{ |
||||
id: '/subscriptions/def-456/resourceGroups/qa', |
||||
name: 'QA', |
||||
type: ResourceRowType.ResourceGroup, |
||||
typeLabel: 'Resource Group', |
||||
children: [], |
||||
}, |
||||
], |
||||
}, |
||||
]; |
||||
@ -0,0 +1,67 @@ |
||||
import { act, render, screen } from '@testing-library/react'; |
||||
import userEvent from '@testing-library/user-event'; |
||||
import React from 'react'; |
||||
import { createMockResourcePickerRows } from '../../__mocks__/resourcePickerRows'; |
||||
|
||||
import NestedResourceTable from './NestedResourceTable'; |
||||
import { findRow } from './utils'; |
||||
|
||||
describe('AzureMonitor NestedResourceTable', () => { |
||||
const noop: any = () => {}; |
||||
|
||||
it('renders subscriptions', () => { |
||||
const rows = createMockResourcePickerRows(); |
||||
|
||||
render(<NestedResourceTable rows={rows} selectedRows={[]} requestNestedRows={noop} onRowSelectedChange={noop} />); |
||||
|
||||
expect(screen.getByText('Primary Subscription')).toBeInTheDocument(); |
||||
expect(screen.getByText('Dev Subscription')).toBeInTheDocument(); |
||||
}); |
||||
|
||||
it('opens to the selected resource', () => { |
||||
const rows = createMockResourcePickerRows(); |
||||
const selected = findRow( |
||||
rows, |
||||
'/subscription/def-456/resourceGroups/dev/providers/Microsoft.Compute/disks/web-server_DataDisk' |
||||
); |
||||
|
||||
if (!selected) { |
||||
throw new Error("couldn't find row, test data stale"); |
||||
} |
||||
|
||||
render( |
||||
<NestedResourceTable rows={rows} selectedRows={[selected]} requestNestedRows={noop} onRowSelectedChange={noop} /> |
||||
); |
||||
|
||||
expect(screen.getByText('web-server_DataDisk')).toBeInTheDocument(); |
||||
}); |
||||
|
||||
it("expands resource groups when they're clicked", async () => { |
||||
const rows = createMockResourcePickerRows(); |
||||
const promise = Promise.resolve(); |
||||
const requestNestedRows = jest.fn().mockReturnValue(promise); |
||||
render( |
||||
<NestedResourceTable |
||||
rows={rows} |
||||
selectedRows={[]} |
||||
requestNestedRows={requestNestedRows} |
||||
onRowSelectedChange={noop} |
||||
/> |
||||
); |
||||
|
||||
const expandButton = screen.getAllByLabelText('Expand')[2]; |
||||
userEvent.click(expandButton); |
||||
|
||||
expect(requestNestedRows).toBeCalledWith( |
||||
expect.objectContaining({ |
||||
id: '/subscriptions/def-456/resourceGroups/dev', |
||||
name: 'Development', |
||||
typeLabel: 'Resource Group', |
||||
}) |
||||
); |
||||
|
||||
await act(() => promise); |
||||
|
||||
expect(screen.getByText('web-server')).toBeInTheDocument(); |
||||
}); |
||||
}); |
||||
@ -1,19 +1,16 @@ |
||||
export enum EntryType { |
||||
Collection, |
||||
SubCollection, |
||||
Resource, |
||||
export enum ResourceRowType { |
||||
Subscription = 'Subscription', |
||||
ResourceGroup = 'ResourceGroup', |
||||
Resource = 'Resource', |
||||
} |
||||
export interface Row { |
||||
|
||||
export interface ResourceRow { |
||||
id: string; |
||||
name: string; |
||||
type: EntryType; |
||||
type: ResourceRowType; |
||||
typeLabel: string; |
||||
subscriptionId: string; |
||||
location?: string; |
||||
children?: RowGroup; |
||||
resourceGroupName?: string; |
||||
children?: ResourceRowGroup; |
||||
} |
||||
|
||||
export interface RowGroup { |
||||
[subscriptionIdOrResourceGroupName: string]: Row; |
||||
} |
||||
export type ResourceRowGroup = ResourceRow[]; |
||||
|
||||
@ -0,0 +1,114 @@ |
||||
import { of } from 'rxjs'; |
||||
|
||||
import { createFetchResponse } from 'test/helpers/createFetchResponse'; |
||||
import { backendSrv } from 'app/core/services/backend_srv'; |
||||
|
||||
import ResourcePickerData from './resourcePickerData'; |
||||
import { |
||||
createMockARGResourceContainersResponse, |
||||
createARGResourcesResponse, |
||||
} from '../__mocks__/argResourcePickerResponse'; |
||||
import { ResourceRowType } from '../components/ResourcePicker/types'; |
||||
import { createMockInstanceSetttings } from '../__mocks__/instanceSettings'; |
||||
|
||||
jest.mock('@grafana/runtime', () => ({ |
||||
...((jest.requireActual('@grafana/runtime') as unknown) as object), |
||||
getBackendSrv: () => backendSrv, |
||||
})); |
||||
|
||||
const instanceSettings = createMockInstanceSetttings(); |
||||
|
||||
describe('AzureMonitor resourcePickerData', () => { |
||||
describe('getResourcePickerData', () => { |
||||
let fetchMock: jest.SpyInstance; |
||||
|
||||
beforeEach(() => { |
||||
fetchMock = jest.spyOn(backendSrv, 'fetch'); |
||||
fetchMock.mockImplementation(() => { |
||||
const data = createMockARGResourceContainersResponse(); |
||||
return of(createFetchResponse(data)); |
||||
}); |
||||
}); |
||||
|
||||
afterEach(() => fetchMock.mockReset()); |
||||
|
||||
it('calls ARG API', async () => { |
||||
const resourcePickerData = new ResourcePickerData(instanceSettings); |
||||
await resourcePickerData.getResourcePickerData(); |
||||
|
||||
expect(fetchMock).toHaveBeenCalled(); |
||||
const argQuery = fetchMock.mock.calls[0][0].data.query; |
||||
|
||||
expect(argQuery).toContain(`where type == 'microsoft.resources/subscriptions'`); |
||||
expect(argQuery).toContain(`where type == 'microsoft.resources/subscriptions/resourcegroups'`); |
||||
}); |
||||
|
||||
it('returns only subscriptions at the top level', async () => { |
||||
const resourcePickerData = new ResourcePickerData(instanceSettings); |
||||
const results = await resourcePickerData.getResourcePickerData(); |
||||
|
||||
expect(results.map((v) => v.id)).toEqual(['/subscriptions/abc-123', '/subscription/def-456']); |
||||
}); |
||||
|
||||
it('nests resource groups under their subscriptions', async () => { |
||||
const resourcePickerData = new ResourcePickerData(instanceSettings); |
||||
const results = await resourcePickerData.getResourcePickerData(); |
||||
|
||||
expect(results[0].children?.map((v) => v.id)).toEqual([ |
||||
'/subscriptions/abc-123/resourceGroups/prod', |
||||
'/subscriptions/abc-123/resourceGroups/pre-prod', |
||||
]); |
||||
|
||||
expect(results[1].children?.map((v) => v.id)).toEqual([ |
||||
'/subscription/def-456/resourceGroups/dev', |
||||
'/subscription/def-456/resourceGroups/test', |
||||
'/subscription/def-456/resourceGroups/qa', |
||||
]); |
||||
}); |
||||
}); |
||||
|
||||
describe('getResourcesForResourceGroup', () => { |
||||
let fetchMock: jest.SpyInstance; |
||||
|
||||
const resourceRow = { |
||||
id: '/subscription/def-456/resourceGroups/dev', |
||||
name: 'Dev', |
||||
type: ResourceRowType.ResourceGroup, |
||||
typeLabel: 'Resource group', |
||||
}; |
||||
|
||||
beforeEach(() => { |
||||
fetchMock = jest.spyOn(backendSrv, 'fetch'); |
||||
fetchMock.mockImplementation(() => { |
||||
const data = createARGResourcesResponse(); |
||||
return of(createFetchResponse(data)); |
||||
}); |
||||
}); |
||||
|
||||
afterEach(() => fetchMock.mockReset()); |
||||
|
||||
it('requests resources for the specified resource row', async () => { |
||||
const resourcePickerData = new ResourcePickerData(instanceSettings); |
||||
await resourcePickerData.getResourcesForResourceGroup(resourceRow); |
||||
|
||||
expect(fetchMock).toHaveBeenCalled(); |
||||
const argQuery = fetchMock.mock.calls[0][0].data.query; |
||||
|
||||
expect(argQuery).toContain(resourceRow.id); |
||||
}); |
||||
|
||||
it('returns formatted resources', async () => { |
||||
const resourcePickerData = new ResourcePickerData(instanceSettings); |
||||
const results = await resourcePickerData.getResourcesForResourceGroup(resourceRow); |
||||
|
||||
expect(results.map((v) => v.id)).toEqual([ |
||||
'/subscription/def-456/resourceGroups/dev/providers/Microsoft.Compute/virtualMachines/web-server', |
||||
'/subscription/def-456/resourceGroups/dev/providers/Microsoft.Compute/disks/web-server_DataDisk', |
||||
'/subscription/def-456/resourceGroups/dev/providers/Microsoft.Compute/virtualMachines/db-server', |
||||
'/subscription/def-456/resourceGroups/dev/providers/Microsoft.Compute/disks/db-server_DataDisk', |
||||
]); |
||||
|
||||
results.forEach((v) => expect(v.type).toEqual(ResourceRowType.Resource)); |
||||
}); |
||||
}); |
||||
}); |
||||
Loading…
Reference in new issue