Files
grafana/public/app/features/alerting/unified/components/rule-viewer/RuleViewer.test.tsx

280 lines
10 KiB
TypeScript
Raw Normal View History

import { within } from '@testing-library/react';
import { render, waitFor, screen, userEvent } from 'test/test-utils';
2024-01-23 15:04:12 +01:00
import { byText, byRole } from 'testing-library-selector';
import { setPluginExtensionsHook } from '@grafana/runtime';
import { setupMswServer } from 'app/features/alerting/unified/mockApi';
import { setFolderAccessControl } from 'app/features/alerting/unified/mocks/server/configure';
import { AlertManagerDataSourceJsonData } from 'app/plugins/datasource/alertmanager/types';
2024-01-23 15:04:12 +01:00
import { AccessControlAction } from 'app/types';
import { CombinedRule, RuleIdentifier } from 'app/types/unified-alerting';
import {
getCloudRule,
getGrafanaRule,
grantUserPermissions,
mockDataSource,
mockPluginLinkExtension,
} from '../../mocks';
import { grafanaRulerRule } from '../../mocks/grafanaRulerApi';
import { setupDataSources } from '../../testSetup/datasources';
import { Annotation } from '../../utils/constants';
Alerting: Add RBAC logic for silences creation (#87322) * Remove role requirement for editing silence (instead handled by silence editor displaying error) * Send query params for metadata/access control silence logic * Add new access control types to enum * Add folder-specific checks for silences * Remove filtering in alert manager picker * fix flakey rule viewer test and update permissions helper * Use `returnTo` in rule viewer page * Fix incorrect display of duration * Clean up some mock server behaviour in rule details tests * Tweak styles for silences alerts table * Remove alertmanager picker from silences drawer * Add error if user cannot edit a silence * Show alert rule name in silences table and consume RBAC logic * Update mocks to include RBAC access control logic * Update silences tests * Update silences type to include access control info * Update comment for missing alertmanager * Update mock handlers and query param logic * Tweak query params again * Update access control mock * Revert AM picker fix as user may not have access to Grafana AM * Swap ternary order * Change text for no alert rule targeted * Don't show error alert from RTKQ query and remove alert instance preview in case of error * Add missing translations * Fix test adding missing mock for getting alert rule * Add missing translations in SilencesTable * Add translations autogenerated files * fix allowing edit silence in external alert manager --------- Co-authored-by: Sonia Aguilar <soniaaguilarpeiron@gmail.com> Co-authored-by: Yuri Tseretyan <yuriy.tseretyan@grafana.com>
2024-06-05 20:09:26 +01:00
import { DataSourceType } from '../../utils/datasource';
import * as ruleId from '../../utils/rule-id';
2024-01-23 15:04:12 +01:00
import { AlertRuleProvider } from './RuleContext';
import RuleViewer from './RuleViewer';
2024-01-23 15:04:12 +01:00
// metadata and interactive elements
const ELEMENTS = {
loading: byText(/Loading rule/i),
metadata: {
summary: (text: string) => byText(text),
runbook: (url: string) => byRole('link', { name: url }),
dashboardAndPanel: byRole('link', { name: 'View panel' }),
evaluationInterval: (interval: string) => byText(`Every ${interval}`),
label: ([key, value]: [string, string]) => byRole('listitem', { name: `${key}: ${value}` }),
},
actions: {
edit: byRole('link', { name: 'Edit' }),
more: {
button: byRole('button', { name: /More/i }),
actions: {
silence: byRole('menuitem', { name: /Silence/i }),
2024-01-23 15:04:12 +01:00
duplicate: byRole('menuitem', { name: /Duplicate/i }),
copyLink: byRole('menuitem', { name: /Copy link/i }),
export: byRole('menuitem', { name: /Export/i }),
delete: byRole('menuitem', { name: /Delete/i }),
},
pluginActions: {
sloDashboard: byRole('menuitem', { name: /SLO dashboard/i }),
declareIncident: byRole('link', { name: /Declare incident/i }),
assertsWorkbench: byRole('menuitem', { name: /Open workbench/i }),
},
2024-01-23 15:04:12 +01:00
},
},
};
setupMswServer();
setupDataSources(mockDataSource({ type: DataSourceType.Prometheus, name: 'mimir-1' }));
setPluginExtensionsHook(() => ({
extensions: [
mockPluginLinkExtension({ pluginId: 'grafana-slo-app', title: 'SLO dashboard', path: '/a/grafana-slo-app' }),
mockPluginLinkExtension({
pluginId: 'grafana-asserts-app',
title: 'Open workbench',
path: '/a/grafana-asserts-app',
}),
],
isLoading: false,
}));
Alerting: Add RBAC logic for silences creation (#87322) * Remove role requirement for editing silence (instead handled by silence editor displaying error) * Send query params for metadata/access control silence logic * Add new access control types to enum * Add folder-specific checks for silences * Remove filtering in alert manager picker * fix flakey rule viewer test and update permissions helper * Use `returnTo` in rule viewer page * Fix incorrect display of duration * Clean up some mock server behaviour in rule details tests * Tweak styles for silences alerts table * Remove alertmanager picker from silences drawer * Add error if user cannot edit a silence * Show alert rule name in silences table and consume RBAC logic * Update mocks to include RBAC access control logic * Update silences tests * Update silences type to include access control info * Update comment for missing alertmanager * Update mock handlers and query param logic * Tweak query params again * Update access control mock * Revert AM picker fix as user may not have access to Grafana AM * Swap ternary order * Change text for no alert rule targeted * Don't show error alert from RTKQ query and remove alert instance preview in case of error * Add missing translations * Fix test adding missing mock for getting alert rule * Add missing translations in SilencesTable * Add translations autogenerated files * fix allowing edit silence in external alert manager --------- Co-authored-by: Sonia Aguilar <soniaaguilarpeiron@gmail.com> Co-authored-by: Yuri Tseretyan <yuriy.tseretyan@grafana.com>
2024-06-05 20:09:26 +01:00
/**
* "Grants" permissions via contextSrv mock, and additionally sets folder access control
* API response to match
*/
const grantPermissionsHelper = (permissions: AccessControlAction[]) => {
const permissionsHash = permissions.reduce((hash, permission) => ({ ...hash, [permission]: true }), {});
grantUserPermissions(permissions);
setFolderAccessControl(permissionsHash);
};
const openSilenceDrawer = async () => {
const user = userEvent.setup();
await user.click(ELEMENTS.actions.more.button.get());
await user.click(ELEMENTS.actions.more.actions.silence.get());
await screen.findByText(/Configure silences/i);
};
beforeAll(() => {
Alerting: Add RBAC logic for silences creation (#87322) * Remove role requirement for editing silence (instead handled by silence editor displaying error) * Send query params for metadata/access control silence logic * Add new access control types to enum * Add folder-specific checks for silences * Remove filtering in alert manager picker * fix flakey rule viewer test and update permissions helper * Use `returnTo` in rule viewer page * Fix incorrect display of duration * Clean up some mock server behaviour in rule details tests * Tweak styles for silences alerts table * Remove alertmanager picker from silences drawer * Add error if user cannot edit a silence * Show alert rule name in silences table and consume RBAC logic * Update mocks to include RBAC access control logic * Update silences tests * Update silences type to include access control info * Update comment for missing alertmanager * Update mock handlers and query param logic * Tweak query params again * Update access control mock * Revert AM picker fix as user may not have access to Grafana AM * Swap ternary order * Change text for no alert rule targeted * Don't show error alert from RTKQ query and remove alert instance preview in case of error * Add missing translations * Fix test adding missing mock for getting alert rule * Add missing translations in SilencesTable * Add translations autogenerated files * fix allowing edit silence in external alert manager --------- Co-authored-by: Sonia Aguilar <soniaaguilarpeiron@gmail.com> Co-authored-by: Yuri Tseretyan <yuriy.tseretyan@grafana.com>
2024-06-05 20:09:26 +01:00
grantPermissionsHelper([
AccessControlAction.AlertingRuleCreate,
AccessControlAction.AlertingRuleRead,
AccessControlAction.AlertingRuleUpdate,
AccessControlAction.AlertingRuleDelete,
AccessControlAction.AlertingInstanceCreate,
]);
});
2024-01-23 15:04:12 +01:00
describe('RuleViewer', () => {
describe('Grafana managed alert rule', () => {
const mockRule = getGrafanaRule(
{
name: 'Test alert',
annotations: {
[Annotation.dashboardUID]: 'dashboard-1',
[Annotation.panelID]: 'panel-1',
[Annotation.summary]: 'This is the summary for the rule',
[Annotation.runbookURL]: 'https://runbook.site/',
},
labels: {
team: 'operations',
severity: 'low',
},
group: {
name: 'my-group',
interval: '15m',
rules: [],
totals: { alerting: 1 },
},
},
{ uid: grafanaRulerRule.grafana_alert.uid }
2024-01-23 15:04:12 +01:00
);
const mockRuleIdentifier = ruleId.fromCombinedRule('grafana', mockRule);
beforeAll(() => {
Alerting: Add RBAC logic for silences creation (#87322) * Remove role requirement for editing silence (instead handled by silence editor displaying error) * Send query params for metadata/access control silence logic * Add new access control types to enum * Add folder-specific checks for silences * Remove filtering in alert manager picker * fix flakey rule viewer test and update permissions helper * Use `returnTo` in rule viewer page * Fix incorrect display of duration * Clean up some mock server behaviour in rule details tests * Tweak styles for silences alerts table * Remove alertmanager picker from silences drawer * Add error if user cannot edit a silence * Show alert rule name in silences table and consume RBAC logic * Update mocks to include RBAC access control logic * Update silences tests * Update silences type to include access control info * Update comment for missing alertmanager * Update mock handlers and query param logic * Tweak query params again * Update access control mock * Revert AM picker fix as user may not have access to Grafana AM * Swap ternary order * Change text for no alert rule targeted * Don't show error alert from RTKQ query and remove alert instance preview in case of error * Add missing translations * Fix test adding missing mock for getting alert rule * Add missing translations in SilencesTable * Add translations autogenerated files * fix allowing edit silence in external alert manager --------- Co-authored-by: Sonia Aguilar <soniaaguilarpeiron@gmail.com> Co-authored-by: Yuri Tseretyan <yuriy.tseretyan@grafana.com>
2024-06-05 20:09:26 +01:00
grantPermissionsHelper([
AccessControlAction.AlertingRuleCreate,
AccessControlAction.AlertingRuleRead,
AccessControlAction.AlertingRuleUpdate,
AccessControlAction.AlertingRuleDelete,
AccessControlAction.AlertingInstanceRead,
AccessControlAction.AlertingInstanceCreate,
Alerting: Add RBAC logic for silences creation (#87322) * Remove role requirement for editing silence (instead handled by silence editor displaying error) * Send query params for metadata/access control silence logic * Add new access control types to enum * Add folder-specific checks for silences * Remove filtering in alert manager picker * fix flakey rule viewer test and update permissions helper * Use `returnTo` in rule viewer page * Fix incorrect display of duration * Clean up some mock server behaviour in rule details tests * Tweak styles for silences alerts table * Remove alertmanager picker from silences drawer * Add error if user cannot edit a silence * Show alert rule name in silences table and consume RBAC logic * Update mocks to include RBAC access control logic * Update silences tests * Update silences type to include access control info * Update comment for missing alertmanager * Update mock handlers and query param logic * Tweak query params again * Update access control mock * Revert AM picker fix as user may not have access to Grafana AM * Swap ternary order * Change text for no alert rule targeted * Don't show error alert from RTKQ query and remove alert instance preview in case of error * Add missing translations * Fix test adding missing mock for getting alert rule * Add missing translations in SilencesTable * Add translations autogenerated files * fix allowing edit silence in external alert manager --------- Co-authored-by: Sonia Aguilar <soniaaguilarpeiron@gmail.com> Co-authored-by: Yuri Tseretyan <yuriy.tseretyan@grafana.com>
2024-06-05 20:09:26 +01:00
AccessControlAction.AlertingInstanceRead,
AccessControlAction.AlertingInstancesExternalRead,
AccessControlAction.AlertingInstancesExternalWrite,
]);
Alerting: Add RBAC logic for silences creation (#87322) * Remove role requirement for editing silence (instead handled by silence editor displaying error) * Send query params for metadata/access control silence logic * Add new access control types to enum * Add folder-specific checks for silences * Remove filtering in alert manager picker * fix flakey rule viewer test and update permissions helper * Use `returnTo` in rule viewer page * Fix incorrect display of duration * Clean up some mock server behaviour in rule details tests * Tweak styles for silences alerts table * Remove alertmanager picker from silences drawer * Add error if user cannot edit a silence * Show alert rule name in silences table and consume RBAC logic * Update mocks to include RBAC access control logic * Update silences tests * Update silences type to include access control info * Update comment for missing alertmanager * Update mock handlers and query param logic * Tweak query params again * Update access control mock * Revert AM picker fix as user may not have access to Grafana AM * Swap ternary order * Change text for no alert rule targeted * Don't show error alert from RTKQ query and remove alert instance preview in case of error * Add missing translations * Fix test adding missing mock for getting alert rule * Add missing translations in SilencesTable * Add translations autogenerated files * fix allowing edit silence in external alert manager --------- Co-authored-by: Sonia Aguilar <soniaaguilarpeiron@gmail.com> Co-authored-by: Yuri Tseretyan <yuriy.tseretyan@grafana.com>
2024-06-05 20:09:26 +01:00
const dataSources = {
am: mockDataSource<AlertManagerDataSourceJsonData>({
name: 'Alertmanager',
type: DataSourceType.Alertmanager,
jsonData: {
handleGrafanaManagedAlerts: true,
},
}),
};
setupDataSources(dataSources.am);
});
2024-01-23 15:04:12 +01:00
it('should render a Grafana managed alert rule', async () => {
await renderRuleViewer(mockRule, mockRuleIdentifier);
// assert on basic info to be visible
expect(screen.getByText('Test alert')).toBeInTheDocument();
expect(screen.getByText('Firing')).toBeInTheDocument();
// alert rule metadata
const ruleSummary = mockRule.annotations[Annotation.summary];
const runBookURL = mockRule.annotations[Annotation.runbookURL];
const groupInterval = mockRule.group.interval;
const labels = mockRule.labels;
expect(ELEMENTS.metadata.summary(ruleSummary).get()).toBeInTheDocument();
expect(ELEMENTS.metadata.dashboardAndPanel.get()).toBeInTheDocument();
expect(ELEMENTS.metadata.runbook(runBookURL).get()).toBeInTheDocument();
expect(ELEMENTS.metadata.evaluationInterval(groupInterval!).get()).toBeInTheDocument();
for (const label in labels) {
expect(ELEMENTS.metadata.label([label, labels[label]]).get()).toBeInTheDocument();
}
// actions
await waitFor(() => {
expect(ELEMENTS.actions.edit.get()).toBeInTheDocument();
expect(ELEMENTS.actions.more.button.get()).toBeInTheDocument();
});
// check the "more actions" button
await userEvent.click(ELEMENTS.actions.more.button.get());
const menuItems = Object.values(ELEMENTS.actions.more.actions);
for (const menuItem of menuItems) {
expect(menuItem.get()).toBeInTheDocument();
}
});
Alerting: Add RBAC logic for silences creation (#87322) * Remove role requirement for editing silence (instead handled by silence editor displaying error) * Send query params for metadata/access control silence logic * Add new access control types to enum * Add folder-specific checks for silences * Remove filtering in alert manager picker * fix flakey rule viewer test and update permissions helper * Use `returnTo` in rule viewer page * Fix incorrect display of duration * Clean up some mock server behaviour in rule details tests * Tweak styles for silences alerts table * Remove alertmanager picker from silences drawer * Add error if user cannot edit a silence * Show alert rule name in silences table and consume RBAC logic * Update mocks to include RBAC access control logic * Update silences tests * Update silences type to include access control info * Update comment for missing alertmanager * Update mock handlers and query param logic * Tweak query params again * Update access control mock * Revert AM picker fix as user may not have access to Grafana AM * Swap ternary order * Change text for no alert rule targeted * Don't show error alert from RTKQ query and remove alert instance preview in case of error * Add missing translations * Fix test adding missing mock for getting alert rule * Add missing translations in SilencesTable * Add translations autogenerated files * fix allowing edit silence in external alert manager --------- Co-authored-by: Sonia Aguilar <soniaaguilarpeiron@gmail.com> Co-authored-by: Yuri Tseretyan <yuriy.tseretyan@grafana.com>
2024-06-05 20:09:26 +01:00
it('renders silencing form correctly and shows alert rule name', async () => {
await renderRuleViewer(mockRule, mockRuleIdentifier);
Alerting: Add RBAC logic for silences creation (#87322) * Remove role requirement for editing silence (instead handled by silence editor displaying error) * Send query params for metadata/access control silence logic * Add new access control types to enum * Add folder-specific checks for silences * Remove filtering in alert manager picker * fix flakey rule viewer test and update permissions helper * Use `returnTo` in rule viewer page * Fix incorrect display of duration * Clean up some mock server behaviour in rule details tests * Tweak styles for silences alerts table * Remove alertmanager picker from silences drawer * Add error if user cannot edit a silence * Show alert rule name in silences table and consume RBAC logic * Update mocks to include RBAC access control logic * Update silences tests * Update silences type to include access control info * Update comment for missing alertmanager * Update mock handlers and query param logic * Tweak query params again * Update access control mock * Revert AM picker fix as user may not have access to Grafana AM * Swap ternary order * Change text for no alert rule targeted * Don't show error alert from RTKQ query and remove alert instance preview in case of error * Add missing translations * Fix test adding missing mock for getting alert rule * Add missing translations in SilencesTable * Add translations autogenerated files * fix allowing edit silence in external alert manager --------- Co-authored-by: Sonia Aguilar <soniaaguilarpeiron@gmail.com> Co-authored-by: Yuri Tseretyan <yuriy.tseretyan@grafana.com>
2024-06-05 20:09:26 +01:00
await openSilenceDrawer();
const silenceDrawer = await screen.findByRole('dialog', { name: 'Drawer title Silence alert rule' });
expect(await within(silenceDrawer).findByLabelText(/^alert rule/i)).toHaveValue(
grafanaRulerRule.grafana_alert.title
);
});
2024-01-23 15:04:12 +01:00
});
describe('Data source managed alert rule', () => {
const mockRule = getCloudRule({
name: 'cloud test alert',
annotations: { [Annotation.summary]: 'cloud summary', [Annotation.runbookURL]: 'https://runbook.example.com' },
group: { name: 'Cloud group', interval: '15m', rules: [], totals: { alerting: 1 } },
});
2024-01-23 15:04:12 +01:00
const mockRuleIdentifier = ruleId.fromCombinedRule('mimir-1', mockRule);
beforeAll(() => {
grantUserPermissions([
AccessControlAction.AlertingRuleExternalRead,
AccessControlAction.AlertingRuleExternalWrite,
]);
});
it('should render a data source managed alert rule', () => {
renderRuleViewer(mockRule, mockRuleIdentifier);
// assert on basic info to be vissible
expect(screen.getByText('cloud test alert')).toBeInTheDocument();
2024-01-23 15:04:12 +01:00
expect(screen.getByText('Firing')).toBeInTheDocument();
expect(screen.getByText(mockRule.annotations[Annotation.summary])).toBeInTheDocument();
expect(screen.getByRole('link', { name: mockRule.annotations[Annotation.runbookURL] })).toBeInTheDocument();
expect(screen.getByText(`Every ${mockRule.group.interval}`)).toBeInTheDocument();
});
it('should render custom plugin actions for a plugin-provided rule', async () => {
const sloRule = getCloudRule({
name: 'slo test alert',
labels: { __grafana_origin: 'plugin/grafana-slo-app' },
});
const sloRuleIdentifier = ruleId.fromCombinedRule('mimir-1', sloRule);
const user = userEvent.setup();
renderRuleViewer(sloRule, sloRuleIdentifier);
expect(ELEMENTS.actions.more.button.get()).toBeInTheDocument();
await user.click(ELEMENTS.actions.more.button.get());
expect(ELEMENTS.actions.more.pluginActions.sloDashboard.get()).toBeInTheDocument();
expect(ELEMENTS.actions.more.pluginActions.assertsWorkbench.query()).not.toBeInTheDocument();
await waitFor(() => expect(ELEMENTS.actions.more.pluginActions.declareIncident.get()).toBeEnabled());
});
it('should render different custom plugin actions for a different plugin-provided rule', async () => {
const assertsRule = getCloudRule({
name: 'asserts test alert',
labels: { __grafana_origin: 'plugin/grafana-asserts-app' },
});
const assertsRuleIdentifier = ruleId.fromCombinedRule('mimir-1', assertsRule);
renderRuleViewer(assertsRule, assertsRuleIdentifier);
expect(ELEMENTS.actions.more.button.get()).toBeInTheDocument();
await userEvent.click(ELEMENTS.actions.more.button.get());
expect(ELEMENTS.actions.more.pluginActions.assertsWorkbench.get()).toBeInTheDocument();
expect(ELEMENTS.actions.more.pluginActions.sloDashboard.query()).not.toBeInTheDocument();
await waitFor(() => expect(ELEMENTS.actions.more.pluginActions.declareIncident.get()).toBeEnabled());
});
2024-01-23 15:04:12 +01:00
});
});
const renderRuleViewer = async (rule: CombinedRule, identifier: RuleIdentifier) => {
render(
<AlertRuleProvider identifier={identifier} rule={rule}>
<RuleViewer />
</AlertRuleProvider>
2024-01-23 15:04:12 +01:00
);
await waitFor(() => expect(ELEMENTS.loading.query()).not.toBeInTheDocument());
};
2024-02-07 18:02:20 +01:00
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
useReturnToPrevious: jest.fn(),
}));