The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
grafana/public/app/features/alerting/unified/RuleList.test.tsx

963 lines
34 KiB

import { SerializedError } from '@reduxjs/toolkit';
import { prettyDOM, render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { setupServer } from 'msw/node';
import React from 'react';
import { TestProvider } from 'test/helpers/TestProvider';
import { byRole, byTestId, byText } from 'testing-library-selector';
import { PluginExtensionTypes, PluginMeta } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import {
DataSourceSrv,
getPluginLinkExtensions,
locationService,
setBackendSrv,
setDataSourceSrv,
PluginExtensions: Make the extensions registry reactive (#83085) * feat: add a reactive extension registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: add hooks to work with the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: start using the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "command palette" extension point to use the hook * feat: update the "alerting" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "explore" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "datasources config" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "panel menu" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "pyroscope datasource" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "user profile page" extension point to use the hooks * chore: update betterer * fix: update the hooks to not re-render unnecessarily * chore: remove the old `createPluginExtensionRegistry` impementation * chore: add "TODO" for `PanelMenuBehaviour` extension point * feat: update the return value of the hooks to contain a `{ isLoading }` param * tests: add more tests for the usePluginExtensions() hook * fix: exclude the cloud-home-app from being non-awaited * refactor: use uuidv4() for random ID generation (for the registry object) * fix: linting issue * feat: use the hooks for the new alerting extension point * feat: use `useMemo()` for `AlertInstanceAction` extension point context --------- Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
1 year ago
usePluginLinkExtensions,
} from '@grafana/runtime';
import { backendSrv } from 'app/core/services/backend_srv';
import * as ruleActionButtons from 'app/features/alerting/unified/components/rules/RuleActionsButtons';
import {
mockAlertRuleApi,
mockApi,
mockFolderApi,
mockSearchApi,
mockUserApi,
} from 'app/features/alerting/unified/mockApi';
import { mockAlertmanagerChoiceResponse } from 'app/features/alerting/unified/mocks/alertmanagerApi';
import * as actions from 'app/features/alerting/unified/state/actions';
import { getMockUser } from 'app/features/users/__mocks__/userMocks';
import { AlertmanagerChoice } from 'app/plugins/datasource/alertmanager/types';
import { AccessControlAction } from 'app/types';
import { PromAlertingRuleState, PromApplication } from 'app/types/unified-alerting-dto';
import * as analytics from './Analytics';
import RuleList from './RuleList';
import { discoverFeatures } from './api/buildInfo';
import { fetchRules } from './api/prometheus';
import { deleteNamespace, deleteRulerRulesGroup, fetchRulerRules, setRulerRuleGroup } from './api/ruler';
import {
MockDataSourceSrv,
grantUserPermissions,
mockDataSource,
mockPromAlert,
mockPromAlertingRule,
mockPromRecordingRule,
mockPromRuleGroup,
mockPromRuleNamespace,
pausedPromRules,
getPotentiallyPausedRulerRules,
somePromRules,
someRulerRules,
mockFolder,
} from './mocks';
import * as config from './utils/config';
import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource';
jest.mock('@grafana/runtime', () => ({
...jest.requireActual('@grafana/runtime'),
getPluginLinkExtensions: jest.fn(),
PluginExtensions: Make the extensions registry reactive (#83085) * feat: add a reactive extension registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: add hooks to work with the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: start using the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "command palette" extension point to use the hook * feat: update the "alerting" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "explore" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "datasources config" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "panel menu" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "pyroscope datasource" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "user profile page" extension point to use the hooks * chore: update betterer * fix: update the hooks to not re-render unnecessarily * chore: remove the old `createPluginExtensionRegistry` impementation * chore: add "TODO" for `PanelMenuBehaviour` extension point * feat: update the return value of the hooks to contain a `{ isLoading }` param * tests: add more tests for the usePluginExtensions() hook * fix: exclude the cloud-home-app from being non-awaited * refactor: use uuidv4() for random ID generation (for the registry object) * fix: linting issue * feat: use the hooks for the new alerting extension point * feat: use `useMemo()` for `AlertInstanceAction` extension point context --------- Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
1 year ago
usePluginLinkExtensions: jest.fn(),
useReturnToPrevious: jest.fn(),
}));
Alerting: Add support to distinguish Prometheus datasource subtypes (Mimir, Cortex and Vanilla Prometheus) (#46771) * Add basic UI for custom ruler URL * Add build info fetching for alerting data sources * Add keeping data sources build info in the store * Use data source build info to construct data source urls * Remove unused code * Add custom ruler support in prometheus api calls * Migrate actions * Use thunk condition to prevent multiple data source buildinfo fetches * Unify prom and ruler rules loading * Upgrade RuleEditor tests * Upgrade RuleList tests * Upgrade PanelAlertTab tests * Upgrade actions tests * Build info refactoring * Get rid of lotex ruler support action * Add prom ruler availability checking when the buildinfo is not available * Add rulerUrlBuilder tests * Improve prometheus data source validation, small build info refactoring * Change prefix based on Prometheus subtype * Use the correct path * Revert config routing * Add deprecation notice for /api/prom prefix * Add tests to the datasource subtype * Remove custom ruler support * Remove deprecation notice * Prevent fetching ruler rules when ruler api is not available * Add build info tests * Unify naming of ruler methods * Fix test * Change buildinfo data source validation * Use strings for subtype params and unveil mimir * organise imports * frontend changes and wordsmithing * fix test suite * add a nicer verbose message for prometheus datasources * detect Mimir datasource * fix test * fix buildinfo test for Mimir * shrink vectors * add some code documentation * DRY prepareRulesFilterQueryParams * clarify that Prometheus does not support managing rules * Improve buildinfo error handling Co-authored-by: gotjosh <josue.abreu@gmail.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
3 years ago
jest.mock('./api/buildInfo');
jest.mock('./api/prometheus');
jest.mock('./api/ruler');
jest.mock('../../../core/hooks/useMediaQueryChange');
jest.spyOn(ruleActionButtons, 'matchesWidth').mockReturnValue(false);
jest.mock('app/core/core', () => ({
...jest.requireActual('app/core/core'),
appEvents: {
subscribe: () => {
return { unsubscribe: () => {} };
},
emit: () => {},
},
}));
jest.spyOn(analytics, 'logInfo');
jest.spyOn(config, 'getAllDataSources');
jest.spyOn(actions, 'rulesInSameGroupHaveInvalidFor').mockReturnValue([]);
const mocks = {
getAllDataSourcesMock: jest.mocked(config.getAllDataSources),
getPluginLinkExtensionsMock: jest.mocked(getPluginLinkExtensions),
PluginExtensions: Make the extensions registry reactive (#83085) * feat: add a reactive extension registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: add hooks to work with the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: start using the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "command palette" extension point to use the hook * feat: update the "alerting" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "explore" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "datasources config" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "panel menu" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "pyroscope datasource" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "user profile page" extension point to use the hooks * chore: update betterer * fix: update the hooks to not re-render unnecessarily * chore: remove the old `createPluginExtensionRegistry` impementation * chore: add "TODO" for `PanelMenuBehaviour` extension point * feat: update the return value of the hooks to contain a `{ isLoading }` param * tests: add more tests for the usePluginExtensions() hook * fix: exclude the cloud-home-app from being non-awaited * refactor: use uuidv4() for random ID generation (for the registry object) * fix: linting issue * feat: use the hooks for the new alerting extension point * feat: use `useMemo()` for `AlertInstanceAction` extension point context --------- Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
1 year ago
usePluginLinkExtensionsMock: jest.mocked(usePluginLinkExtensions),
rulesInSameGroupHaveInvalidForMock: jest.mocked(actions.rulesInSameGroupHaveInvalidFor),
api: {
discoverFeatures: jest.mocked(discoverFeatures),
fetchRules: jest.mocked(fetchRules),
fetchRulerRules: jest.mocked(fetchRulerRules),
deleteGroup: jest.mocked(deleteRulerRulesGroup),
deleteNamespace: jest.mocked(deleteNamespace),
setRulerRuleGroup: jest.mocked(setRulerRuleGroup),
},
};
const renderRuleList = () => {
locationService.push('/');
return render(
<TestProvider>
<RuleList />
</TestProvider>
);
};
const dataSources = {
prom: mockDataSource({
name: 'Prometheus',
type: DataSourceType.Prometheus,
}),
promdisabled: mockDataSource({
name: 'Prometheus-disabled',
type: DataSourceType.Prometheus,
jsonData: {
manageAlerts: false,
},
}),
loki: mockDataSource({
name: 'Loki',
type: DataSourceType.Loki,
}),
promBroken: mockDataSource({
name: 'Prometheus-broken',
type: DataSourceType.Prometheus,
}),
};
const ui = {
ruleGroup: byTestId('rule-group'),
pausedRuleGroup: byText(/groupPaused/),
cloudRulesSourceErrors: byTestId('cloud-rulessource-errors'),
groupCollapseToggle: byTestId(selectors.components.AlertRules.groupToggle),
ruleCollapseToggle: byTestId(selectors.components.AlertRules.toggle),
rulesTable: byTestId('rules-table'),
ruleRow: byTestId('row'),
expandedContent: byTestId(selectors.components.AlertRules.expandedContent),
rulesFilterInput: byTestId('search-query-input'),
moreErrorsButton: byRole('button', { name: /more errors/ }),
editCloudGroupIcon: byTestId('edit-group'),
newRuleButton: byText(/new alert rule/i),
exportButton: byText(/export rules/i),
editGroupModal: {
dialog: byRole('dialog'),
namespaceInput: byRole('textbox', { name: /^Namespace/ }),
ruleGroupInput: byRole('textbox', { name: /Evaluation group/ }),
intervalInput: byRole('textbox', {
name: /Evaluation interval How often is the rule evaluated. Applies to every rule within the group./i,
}),
saveButton: byRole('button', { name: /Save/ }),
},
stateTags: {
paused: byText(/^Paused/),
},
actionButtons: {
more: byRole('button', { name: 'More' }),
},
moreActionItems: {
pause: byRole('menuitem', { name: /pause evaluation/i }),
resume: byRole('menuitem', { name: /resume evaluation/i }),
},
};
const server = setupServer();
const configureMockServer = () => {
mockSearchApi(server).search([]);
mockUserApi(server).user(getMockUser());
mockFolderApi(server).folder(
'NAMESPACE_UID',
mockFolder({
accessControl: { [AccessControlAction.AlertingRuleUpdate]: true },
})
);
mockApi(server).plugins.getPluginSettings(
// We aren't particularly concerned with the plugin response in these tests
// at the time of writing, so we can go unknown -> PluginMeta to get the bare minimum
{ id: 'grafana-incident-app' } as unknown as PluginMeta
);
mockAlertmanagerChoiceResponse(server, {
alertmanagersChoice: AlertmanagerChoice.All,
numExternalAlertmanagers: 1,
});
mockAlertRuleApi(server).updateRule('grafana', {
message: 'rule group updated successfully',
updated: ['foo', 'bar', 'baz'],
});
};
beforeAll(() => {
setBackendSrv(backendSrv);
});
describe('RuleList', () => {
beforeEach(() => {
server.listen({ onUnhandledRequest: 'error' });
configureMockServer();
grantUserPermissions([
AccessControlAction.AlertingRuleRead,
AccessControlAction.AlertingRuleUpdate,
AccessControlAction.AlertingRuleExternalRead,
AccessControlAction.AlertingRuleExternalWrite,
]);
mocks.rulesInSameGroupHaveInvalidForMock.mockReturnValue([]);
PluginExtensions: Make the extensions registry reactive (#83085) * feat: add a reactive extension registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: add hooks to work with the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: start using the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "command palette" extension point to use the hook * feat: update the "alerting" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "explore" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "datasources config" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "panel menu" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "pyroscope datasource" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "user profile page" extension point to use the hooks * chore: update betterer * fix: update the hooks to not re-render unnecessarily * chore: remove the old `createPluginExtensionRegistry` impementation * chore: add "TODO" for `PanelMenuBehaviour` extension point * feat: update the return value of the hooks to contain a `{ isLoading }` param * tests: add more tests for the usePluginExtensions() hook * fix: exclude the cloud-home-app from being non-awaited * refactor: use uuidv4() for random ID generation (for the registry object) * fix: linting issue * feat: use the hooks for the new alerting extension point * feat: use `useMemo()` for `AlertInstanceAction` extension point context --------- Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
1 year ago
mocks.usePluginLinkExtensionsMock.mockReturnValue({
extensions: [
{
pluginId: 'grafana-ml-app',
id: '1',
type: PluginExtensionTypes.link,
title: 'Run investigation',
category: 'Sift',
description: 'Run a Sift investigation for this alert',
onClick: jest.fn(),
},
],
PluginExtensions: Make the extensions registry reactive (#83085) * feat: add a reactive extension registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: add hooks to work with the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: start using the reactive registry Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "command palette" extension point to use the hook * feat: update the "alerting" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "explore" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "datasources config" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "panel menu" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "pyroscope datasource" extension point to use the hooks Co-authored-by: Marcus Andersson <marcus.andersson@grafana.com> * feat: update the "user profile page" extension point to use the hooks * chore: update betterer * fix: update the hooks to not re-render unnecessarily * chore: remove the old `createPluginExtensionRegistry` impementation * chore: add "TODO" for `PanelMenuBehaviour` extension point * feat: update the return value of the hooks to contain a `{ isLoading }` param * tests: add more tests for the usePluginExtensions() hook * fix: exclude the cloud-home-app from being non-awaited * refactor: use uuidv4() for random ID generation (for the registry object) * fix: linting issue * feat: use the hooks for the new alerting extension point * feat: use `useMemo()` for `AlertInstanceAction` extension point context --------- Co-authored-by: Levente Balogh <balogh.levente.hu@gmail.com>
1 year ago
isLoading: false,
});
});
afterEach(() => {
server.resetHandlers();
jest.resetAllMocks();
setDataSourceSrv(undefined as unknown as DataSourceSrv);
});
afterAll(() => {
server.close();
});
it('load & show rule groups from multiple cloud data sources', async () => {
mocks.getAllDataSourcesMock.mockReturnValue(Object.values(dataSources));
setDataSourceSrv(new MockDataSourceSrv(dataSources));
mocks.api.discoverFeatures.mockResolvedValue({
Alerting: Add support to distinguish Prometheus datasource subtypes (Mimir, Cortex and Vanilla Prometheus) (#46771) * Add basic UI for custom ruler URL * Add build info fetching for alerting data sources * Add keeping data sources build info in the store * Use data source build info to construct data source urls * Remove unused code * Add custom ruler support in prometheus api calls * Migrate actions * Use thunk condition to prevent multiple data source buildinfo fetches * Unify prom and ruler rules loading * Upgrade RuleEditor tests * Upgrade RuleList tests * Upgrade PanelAlertTab tests * Upgrade actions tests * Build info refactoring * Get rid of lotex ruler support action * Add prom ruler availability checking when the buildinfo is not available * Add rulerUrlBuilder tests * Improve prometheus data source validation, small build info refactoring * Change prefix based on Prometheus subtype * Use the correct path * Revert config routing * Add deprecation notice for /api/prom prefix * Add tests to the datasource subtype * Remove custom ruler support * Remove deprecation notice * Prevent fetching ruler rules when ruler api is not available * Add build info tests * Unify naming of ruler methods * Fix test * Change buildinfo data source validation * Use strings for subtype params and unveil mimir * organise imports * frontend changes and wordsmithing * fix test suite * add a nicer verbose message for prometheus datasources * detect Mimir datasource * fix test * fix buildinfo test for Mimir * shrink vectors * add some code documentation * DRY prepareRulesFilterQueryParams * clarify that Prometheus does not support managing rules * Improve buildinfo error handling Co-authored-by: gotjosh <josue.abreu@gmail.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
3 years ago
application: PromApplication.Prometheus,
features: {
rulerApiEnabled: true,
},
});
mocks.api.fetchRules.mockImplementation((dataSourceName: string) => {
if (dataSourceName === dataSources.prom.name) {
return Promise.resolve([
mockPromRuleNamespace({
name: 'default',
dataSourceName: dataSources.prom.name,
groups: [
mockPromRuleGroup({
name: 'group-2',
}),
mockPromRuleGroup({
name: 'group-1',
}),
],
}),
]);
} else if (dataSourceName === dataSources.loki.name) {
return Promise.resolve([
mockPromRuleNamespace({
name: 'default',
dataSourceName: dataSources.loki.name,
groups: [
mockPromRuleGroup({
name: 'group-1',
}),
],
}),
mockPromRuleNamespace({
name: 'lokins',
dataSourceName: dataSources.loki.name,
groups: [
mockPromRuleGroup({
name: 'group-1',
}),
],
}),
]);
} else if (dataSourceName === dataSources.promBroken.name) {
return Promise.reject({ message: 'this datasource is broken' } as SerializedError);
} else if (dataSourceName === GRAFANA_RULES_SOURCE_NAME) {
return Promise.resolve([
mockPromRuleNamespace({
name: 'foofolder',
dataSourceName: GRAFANA_RULES_SOURCE_NAME,
groups: [
mockPromRuleGroup({
name: 'grafana-group',
rules: [
mockPromAlertingRule({
query: '[]',
}),
],
}),
],
}),
]);
}
return Promise.reject(new Error(`unexpected datasourceName: ${dataSourceName}`));
});
mocks.api.fetchRulerRules.mockRejectedValue({ status: 500, data: { message: 'Server error' } });
await renderRuleList();
await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalledTimes(4));
const groups = await ui.ruleGroup.findAll();
expect(groups).toHaveLength(5);
expect(groups[0]).toHaveTextContent('foofolder');
expect(groups[1]).toHaveTextContent('default group-1');
expect(groups[2]).toHaveTextContent('default group-1');
expect(groups[3]).toHaveTextContent('default group-2');
expect(groups[4]).toHaveTextContent('lokins group-1');
const errors = await ui.cloudRulesSourceErrors.find();
expect(errors).not.toHaveTextContent(
'Failed to load rules state from Prometheus-broken: this datasource is broken'
);
await userEvent.click(ui.moreErrorsButton.get());
expect(errors).toHaveTextContent('Failed to load rules state from Prometheus-broken: this datasource is broken');
});
it('expand rule group, rule and alert details', async () => {
mocks.getAllDataSourcesMock.mockReturnValue([dataSources.prom]);
Alerting: Add support to distinguish Prometheus datasource subtypes (Mimir, Cortex and Vanilla Prometheus) (#46771) * Add basic UI for custom ruler URL * Add build info fetching for alerting data sources * Add keeping data sources build info in the store * Use data source build info to construct data source urls * Remove unused code * Add custom ruler support in prometheus api calls * Migrate actions * Use thunk condition to prevent multiple data source buildinfo fetches * Unify prom and ruler rules loading * Upgrade RuleEditor tests * Upgrade RuleList tests * Upgrade PanelAlertTab tests * Upgrade actions tests * Build info refactoring * Get rid of lotex ruler support action * Add prom ruler availability checking when the buildinfo is not available * Add rulerUrlBuilder tests * Improve prometheus data source validation, small build info refactoring * Change prefix based on Prometheus subtype * Use the correct path * Revert config routing * Add deprecation notice for /api/prom prefix * Add tests to the datasource subtype * Remove custom ruler support * Remove deprecation notice * Prevent fetching ruler rules when ruler api is not available * Add build info tests * Unify naming of ruler methods * Fix test * Change buildinfo data source validation * Use strings for subtype params and unveil mimir * organise imports * frontend changes and wordsmithing * fix test suite * add a nicer verbose message for prometheus datasources * detect Mimir datasource * fix test * fix buildinfo test for Mimir * shrink vectors * add some code documentation * DRY prepareRulesFilterQueryParams * clarify that Prometheus does not support managing rules * Improve buildinfo error handling Co-authored-by: gotjosh <josue.abreu@gmail.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
3 years ago
setDataSourceSrv(new MockDataSourceSrv({ prom: dataSources.prom }));
mocks.api.discoverFeatures.mockResolvedValue({
application: PromApplication.Cortex,
Alerting: Add support to distinguish Prometheus datasource subtypes (Mimir, Cortex and Vanilla Prometheus) (#46771) * Add basic UI for custom ruler URL * Add build info fetching for alerting data sources * Add keeping data sources build info in the store * Use data source build info to construct data source urls * Remove unused code * Add custom ruler support in prometheus api calls * Migrate actions * Use thunk condition to prevent multiple data source buildinfo fetches * Unify prom and ruler rules loading * Upgrade RuleEditor tests * Upgrade RuleList tests * Upgrade PanelAlertTab tests * Upgrade actions tests * Build info refactoring * Get rid of lotex ruler support action * Add prom ruler availability checking when the buildinfo is not available * Add rulerUrlBuilder tests * Improve prometheus data source validation, small build info refactoring * Change prefix based on Prometheus subtype * Use the correct path * Revert config routing * Add deprecation notice for /api/prom prefix * Add tests to the datasource subtype * Remove custom ruler support * Remove deprecation notice * Prevent fetching ruler rules when ruler api is not available * Add build info tests * Unify naming of ruler methods * Fix test * Change buildinfo data source validation * Use strings for subtype params and unveil mimir * organise imports * frontend changes and wordsmithing * fix test suite * add a nicer verbose message for prometheus datasources * detect Mimir datasource * fix test * fix buildinfo test for Mimir * shrink vectors * add some code documentation * DRY prepareRulesFilterQueryParams * clarify that Prometheus does not support managing rules * Improve buildinfo error handling Co-authored-by: gotjosh <josue.abreu@gmail.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
3 years ago
features: {
rulerApiEnabled: true,
},
});
mocks.api.fetchRules.mockImplementation((dataSourceName: string) => {
if (dataSourceName === GRAFANA_RULES_SOURCE_NAME) {
return Promise.resolve([]);
} else {
return Promise.resolve([
mockPromRuleNamespace({
groups: [
mockPromRuleGroup({
name: 'group-1',
}),
mockPromRuleGroup({
name: 'group-2',
rules: [
mockPromRecordingRule({
name: 'recordingrule',
}),
mockPromAlertingRule({
name: 'alertingrule',
labels: {
severity: 'warning',
foo: 'bar',
},
query: 'topk(5, foo)[5m]',
annotations: {
message: 'great alert',
},
alerts: [
mockPromAlert({
labels: {
foo: 'bar',
severity: 'warning',
},
value: '2e+10',
annotations: {
message: 'first alert message',
},
}),
mockPromAlert({
labels: {
foo: 'baz',
severity: 'error',
},
value: '3e+11',
annotations: {
message: 'first alert message',
},
}),
],
}),
mockPromAlertingRule({
name: 'p-rule',
alerts: [],
state: PromAlertingRuleState.Pending,
}),
mockPromAlertingRule({
name: 'i-rule',
alerts: [],
state: PromAlertingRuleState.Inactive,
}),
],
}),
],
}),
]);
}
});
await renderRuleList();
const groups = await ui.ruleGroup.findAll();
expect(groups).toHaveLength(2);
await waitFor(() => expect(groups[0]).toHaveTextContent(/firing|pending|normal/));
await waitFor(() => expect(groups[1]).toHaveTextContent(/firing|pending|normal/));
expect(groups[0]).toHaveTextContent('1 firing');
expect(groups[1]).toHaveTextContent('1 firing');
expect(groups[1]).toHaveTextContent('1 pending');
expect(groups[1]).toHaveTextContent('1 recording');
expect(groups[1]).toHaveTextContent('1 normal');
// expand second group to see rules table
expect(ui.rulesTable.query()).not.toBeInTheDocument();
await userEvent.click(ui.groupCollapseToggle.get(groups[1]));
const table = await ui.rulesTable.find(groups[1]);
// check that rule rows are rendered properly
let ruleRows = ui.ruleRow.getAll(table);
expect(ruleRows).toHaveLength(4);
expect(ruleRows[0]).toHaveTextContent('Recording rule');
expect(ruleRows[0]).toHaveTextContent('recordingrule');
expect(ruleRows[1]).toHaveTextContent('Firing');
expect(ruleRows[1]).toHaveTextContent('alertingrule');
expect(ruleRows[2]).toHaveTextContent('Pending');
expect(ruleRows[2]).toHaveTextContent('p-rule');
expect(ruleRows[3]).toHaveTextContent('Normal');
expect(ruleRows[3]).toHaveTextContent('i-rule');
expect(byText('Labels').query()).not.toBeInTheDocument();
// expand alert details
await userEvent.click(ui.ruleCollapseToggle.get(ruleRows[1]));
const ruleDetails = ui.expandedContent.get(ruleRows[1]);
const labels = byTestId('label-value').getAll(ruleDetails);
expect(labels[0]).toHaveTextContent('severitywarning');
expect(labels[1]).toHaveTextContent('foobar');
expect(ruleDetails).toHaveTextContent('Expressiontopk ( 5 , foo ) [ 5m ]');
expect(ruleDetails).toHaveTextContent('messagegreat alert');
expect(ruleDetails).toHaveTextContent('Matching instances');
// finally, check instances table
const instancesTable = byTestId('dynamic-table').get(ruleDetails);
expect(instancesTable).toBeInTheDocument();
const instanceRows = byTestId('row').getAll(instancesTable);
expect(instanceRows).toHaveLength(2);
expect(instanceRows![0]).toHaveTextContent('Firingfoobarseveritywarning2021-03-18 08:47:05');
expect(instanceRows![1]).toHaveTextContent('Firingfoobazseverityerror2021-03-18 08:47:05');
// expand details of an instance
await userEvent.click(ui.ruleCollapseToggle.get(instanceRows![0]));
const alertDetails = byTestId(selectors.components.AlertRules.expandedContent).get(instanceRows[0]);
expect(alertDetails).toHaveTextContent('Value2e+10');
expect(alertDetails).toHaveTextContent('messagefirst alert message');
// collapse everything again
await userEvent.click(ui.ruleCollapseToggle.get(instanceRows![0]));
expect(byTestId(selectors.components.AlertRules.expandedContent).query(instanceRows[0])).not.toBeInTheDocument();
await userEvent.click(ui.ruleCollapseToggle.getAll(ruleRows[1])[0]);
await userEvent.click(ui.groupCollapseToggle.get(groups[1]));
expect(ui.rulesTable.query()).not.toBeInTheDocument();
});
it('filters rules and alerts by labels', async () => {
mocks.getAllDataSourcesMock.mockReturnValue([dataSources.prom]);
setDataSourceSrv(new MockDataSourceSrv({ prom: dataSources.prom }));
Alerting: Add support to distinguish Prometheus datasource subtypes (Mimir, Cortex and Vanilla Prometheus) (#46771) * Add basic UI for custom ruler URL * Add build info fetching for alerting data sources * Add keeping data sources build info in the store * Use data source build info to construct data source urls * Remove unused code * Add custom ruler support in prometheus api calls * Migrate actions * Use thunk condition to prevent multiple data source buildinfo fetches * Unify prom and ruler rules loading * Upgrade RuleEditor tests * Upgrade RuleList tests * Upgrade PanelAlertTab tests * Upgrade actions tests * Build info refactoring * Get rid of lotex ruler support action * Add prom ruler availability checking when the buildinfo is not available * Add rulerUrlBuilder tests * Improve prometheus data source validation, small build info refactoring * Change prefix based on Prometheus subtype * Use the correct path * Revert config routing * Add deprecation notice for /api/prom prefix * Add tests to the datasource subtype * Remove custom ruler support * Remove deprecation notice * Prevent fetching ruler rules when ruler api is not available * Add build info tests * Unify naming of ruler methods * Fix test * Change buildinfo data source validation * Use strings for subtype params and unveil mimir * organise imports * frontend changes and wordsmithing * fix test suite * add a nicer verbose message for prometheus datasources * detect Mimir datasource * fix test * fix buildinfo test for Mimir * shrink vectors * add some code documentation * DRY prepareRulesFilterQueryParams * clarify that Prometheus does not support managing rules * Improve buildinfo error handling Co-authored-by: gotjosh <josue.abreu@gmail.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
3 years ago
mocks.api.discoverFeatures.mockResolvedValue({
application: PromApplication.Cortex,
Alerting: Add support to distinguish Prometheus datasource subtypes (Mimir, Cortex and Vanilla Prometheus) (#46771) * Add basic UI for custom ruler URL * Add build info fetching for alerting data sources * Add keeping data sources build info in the store * Use data source build info to construct data source urls * Remove unused code * Add custom ruler support in prometheus api calls * Migrate actions * Use thunk condition to prevent multiple data source buildinfo fetches * Unify prom and ruler rules loading * Upgrade RuleEditor tests * Upgrade RuleList tests * Upgrade PanelAlertTab tests * Upgrade actions tests * Build info refactoring * Get rid of lotex ruler support action * Add prom ruler availability checking when the buildinfo is not available * Add rulerUrlBuilder tests * Improve prometheus data source validation, small build info refactoring * Change prefix based on Prometheus subtype * Use the correct path * Revert config routing * Add deprecation notice for /api/prom prefix * Add tests to the datasource subtype * Remove custom ruler support * Remove deprecation notice * Prevent fetching ruler rules when ruler api is not available * Add build info tests * Unify naming of ruler methods * Fix test * Change buildinfo data source validation * Use strings for subtype params and unveil mimir * organise imports * frontend changes and wordsmithing * fix test suite * add a nicer verbose message for prometheus datasources * detect Mimir datasource * fix test * fix buildinfo test for Mimir * shrink vectors * add some code documentation * DRY prepareRulesFilterQueryParams * clarify that Prometheus does not support managing rules * Improve buildinfo error handling Co-authored-by: gotjosh <josue.abreu@gmail.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
3 years ago
features: {
rulerApiEnabled: true,
},
});
mocks.api.fetchRulerRules.mockResolvedValue({});
mocks.api.fetchRules.mockImplementation((dataSourceName: string) => {
if (dataSourceName === GRAFANA_RULES_SOURCE_NAME) {
return Promise.resolve([]);
} else {
return Promise.resolve([
mockPromRuleNamespace({
groups: [
mockPromRuleGroup({
name: 'group-1',
rules: [
mockPromAlertingRule({
name: 'alertingrule',
labels: {
severity: 'warning',
foo: 'bar',
},
query: 'topk(5, foo)[5m]',
annotations: {
message: 'great alert',
},
alerts: [
mockPromAlert({
labels: {
foo: 'bar',
severity: 'warning',
},
value: '2e+10',
annotations: {
message: 'first alert message',
},
}),
mockPromAlert({
labels: {
foo: 'baz',
severity: 'error',
},
value: '3e+11',
annotations: {
message: 'first alert message',
},
}),
],
}),
],
}),
mockPromRuleGroup({
name: 'group-2',
rules: [
mockPromAlertingRule({
name: 'alertingrule2',
labels: {
severity: 'error',
foo: 'buzz',
},
query: 'topk(5, foo)[5m]',
annotations: {
message: 'great alert',
},
alerts: [
mockPromAlert({
labels: {
foo: 'buzz',
severity: 'error',
region: 'EU',
},
value: '2e+10',
annotations: {
message: 'alert message',
},
}),
mockPromAlert({
labels: {
foo: 'buzz',
severity: 'error',
region: 'US',
},
value: '3e+11',
annotations: {
message: 'alert message',
},
}),
],
}),
],
}),
],
}),
]);
}
});
await renderRuleList();
const groups = await ui.ruleGroup.findAll();
expect(groups).toHaveLength(2);
const filterInput = ui.rulesFilterInput.get();
await userEvent.type(filterInput, 'label:foo=bar{Enter}');
// Input is debounced so wait for it to be visible
await waitFor(() => expect(filterInput).toHaveValue('label:foo=bar'));
// Group doesn't contain matching labels
await waitFor(() => expect(ui.ruleGroup.queryAll()).toHaveLength(1));
await userEvent.click(ui.groupCollapseToggle.get(groups[0]));
const ruleRows = ui.ruleRow.getAll(groups[0]);
expect(ruleRows).toHaveLength(1);
await userEvent.click(ui.ruleCollapseToggle.get(ruleRows[0]));
const ruleDetails = ui.expandedContent.get(ruleRows[0]);
const labels = byTestId('label-value').getAll(ruleDetails);
expect(labels[0]).toHaveTextContent('severitywarning');
expect(labels[1]).toHaveTextContent('foobar');
// Check for different label matchers
await userEvent.clear(filterInput);
await userEvent.type(filterInput, 'label:foo!=bar label:foo!=baz{Enter}');
// Group doesn't contain matching labels
await waitFor(() => expect(ui.ruleGroup.queryAll()).toHaveLength(1));
await waitFor(() => expect(ui.ruleGroup.get()).toHaveTextContent('group-2'));
await userEvent.clear(filterInput);
await userEvent.type(filterInput, 'label:"foo=~b.+"{Enter}');
await waitFor(() => expect(ui.ruleGroup.queryAll()).toHaveLength(2));
await userEvent.clear(filterInput);
await userEvent.type(filterInput, 'label:region=US{Enter}');
await waitFor(() => expect(ui.ruleGroup.queryAll()).toHaveLength(1));
await waitFor(() => expect(ui.ruleGroup.get()).toHaveTextContent('group-2'));
});
describe('pausing rules', () => {
beforeEach(() => {
grantUserPermissions([
AccessControlAction.AlertingRuleRead,
AccessControlAction.AlertingRuleUpdate,
AccessControlAction.AlertingRuleExternalRead,
AccessControlAction.AlertingRuleExternalWrite,
]);
mocks.getAllDataSourcesMock.mockReturnValue([]);
setDataSourceSrv(new MockDataSourceSrv({}));
mocks.api.fetchRulerRules.mockImplementation(() => Promise.resolve(getPotentiallyPausedRulerRules(true)));
mocks.api.fetchRules.mockImplementation((sourceName) =>
Promise.resolve(sourceName === 'grafana' ? pausedPromRules('grafana') : [])
);
});
test('resuming paused alert rule', async () => {
const user = userEvent.setup();
renderRuleList();
// Expand the paused rule group so we can assert the rule state
await user.click(await ui.pausedRuleGroup.find());
expect(await ui.stateTags.paused.find()).toBeInTheDocument();
// TODO: Migrate all testing logic to MSW and so we aren't manually tweaking the API response behaviour
mocks.api.fetchRulerRules.mockImplementationOnce(() => {
return Promise.resolve(getPotentiallyPausedRulerRules(false));
});
await user.click(await ui.actionButtons.more.find());
await user.click(await ui.moreActionItems.resume.find());
await waitFor(() => expect(ui.stateTags.paused.query()).not.toBeInTheDocument());
});
});
describe('edit lotex groups, namespaces', () => {
const testDatasources = {
prom: dataSources.prom,
};
function testCase(name: string, fn: () => Promise<void>) {
it(name, async () => {
mocks.getAllDataSourcesMock.mockReturnValue(Object.values(testDatasources));
setDataSourceSrv(new MockDataSourceSrv(testDatasources));
Alerting: Add support to distinguish Prometheus datasource subtypes (Mimir, Cortex and Vanilla Prometheus) (#46771) * Add basic UI for custom ruler URL * Add build info fetching for alerting data sources * Add keeping data sources build info in the store * Use data source build info to construct data source urls * Remove unused code * Add custom ruler support in prometheus api calls * Migrate actions * Use thunk condition to prevent multiple data source buildinfo fetches * Unify prom and ruler rules loading * Upgrade RuleEditor tests * Upgrade RuleList tests * Upgrade PanelAlertTab tests * Upgrade actions tests * Build info refactoring * Get rid of lotex ruler support action * Add prom ruler availability checking when the buildinfo is not available * Add rulerUrlBuilder tests * Improve prometheus data source validation, small build info refactoring * Change prefix based on Prometheus subtype * Use the correct path * Revert config routing * Add deprecation notice for /api/prom prefix * Add tests to the datasource subtype * Remove custom ruler support * Remove deprecation notice * Prevent fetching ruler rules when ruler api is not available * Add build info tests * Unify naming of ruler methods * Fix test * Change buildinfo data source validation * Use strings for subtype params and unveil mimir * organise imports * frontend changes and wordsmithing * fix test suite * add a nicer verbose message for prometheus datasources * detect Mimir datasource * fix test * fix buildinfo test for Mimir * shrink vectors * add some code documentation * DRY prepareRulesFilterQueryParams * clarify that Prometheus does not support managing rules * Improve buildinfo error handling Co-authored-by: gotjosh <josue.abreu@gmail.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
3 years ago
mocks.api.discoverFeatures.mockResolvedValue({
application: PromApplication.Cortex,
Alerting: Add support to distinguish Prometheus datasource subtypes (Mimir, Cortex and Vanilla Prometheus) (#46771) * Add basic UI for custom ruler URL * Add build info fetching for alerting data sources * Add keeping data sources build info in the store * Use data source build info to construct data source urls * Remove unused code * Add custom ruler support in prometheus api calls * Migrate actions * Use thunk condition to prevent multiple data source buildinfo fetches * Unify prom and ruler rules loading * Upgrade RuleEditor tests * Upgrade RuleList tests * Upgrade PanelAlertTab tests * Upgrade actions tests * Build info refactoring * Get rid of lotex ruler support action * Add prom ruler availability checking when the buildinfo is not available * Add rulerUrlBuilder tests * Improve prometheus data source validation, small build info refactoring * Change prefix based on Prometheus subtype * Use the correct path * Revert config routing * Add deprecation notice for /api/prom prefix * Add tests to the datasource subtype * Remove custom ruler support * Remove deprecation notice * Prevent fetching ruler rules when ruler api is not available * Add build info tests * Unify naming of ruler methods * Fix test * Change buildinfo data source validation * Use strings for subtype params and unveil mimir * organise imports * frontend changes and wordsmithing * fix test suite * add a nicer verbose message for prometheus datasources * detect Mimir datasource * fix test * fix buildinfo test for Mimir * shrink vectors * add some code documentation * DRY prepareRulesFilterQueryParams * clarify that Prometheus does not support managing rules * Improve buildinfo error handling Co-authored-by: gotjosh <josue.abreu@gmail.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
3 years ago
features: {
rulerApiEnabled: true,
},
});
mocks.api.fetchRules.mockImplementation((sourceName) =>
Promise.resolve(sourceName === testDatasources.prom.name ? somePromRules() : [])
);
Alerting: Add support to distinguish Prometheus datasource subtypes (Mimir, Cortex and Vanilla Prometheus) (#46771) * Add basic UI for custom ruler URL * Add build info fetching for alerting data sources * Add keeping data sources build info in the store * Use data source build info to construct data source urls * Remove unused code * Add custom ruler support in prometheus api calls * Migrate actions * Use thunk condition to prevent multiple data source buildinfo fetches * Unify prom and ruler rules loading * Upgrade RuleEditor tests * Upgrade RuleList tests * Upgrade PanelAlertTab tests * Upgrade actions tests * Build info refactoring * Get rid of lotex ruler support action * Add prom ruler availability checking when the buildinfo is not available * Add rulerUrlBuilder tests * Improve prometheus data source validation, small build info refactoring * Change prefix based on Prometheus subtype * Use the correct path * Revert config routing * Add deprecation notice for /api/prom prefix * Add tests to the datasource subtype * Remove custom ruler support * Remove deprecation notice * Prevent fetching ruler rules when ruler api is not available * Add build info tests * Unify naming of ruler methods * Fix test * Change buildinfo data source validation * Use strings for subtype params and unveil mimir * organise imports * frontend changes and wordsmithing * fix test suite * add a nicer verbose message for prometheus datasources * detect Mimir datasource * fix test * fix buildinfo test for Mimir * shrink vectors * add some code documentation * DRY prepareRulesFilterQueryParams * clarify that Prometheus does not support managing rules * Improve buildinfo error handling Co-authored-by: gotjosh <josue.abreu@gmail.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
3 years ago
mocks.api.fetchRulerRules.mockImplementation(({ dataSourceName }) =>
Promise.resolve(dataSourceName === testDatasources.prom.name ? someRulerRules : {})
);
mocks.api.setRulerRuleGroup.mockResolvedValue();
mocks.api.deleteNamespace.mockResolvedValue();
await renderRuleList();
expect(await ui.rulesFilterInput.find()).toHaveValue('');
await waitFor(() => expect(ui.ruleGroup.queryAll()).toHaveLength(3));
const groups = await ui.ruleGroup.findAll();
expect(groups).toHaveLength(3);
// open edit dialog
await userEvent.click(ui.editCloudGroupIcon.get(groups[0]));
await waitFor(() => expect(ui.editGroupModal.dialog.get()).toBeInTheDocument());
prettyDOM(ui.editGroupModal.dialog.get());
expect(ui.editGroupModal.namespaceInput.get()).toHaveDisplayValue('namespace1');
expect(ui.editGroupModal.ruleGroupInput.get()).toHaveDisplayValue('group1');
await fn();
});
}
testCase('rename both lotex namespace and group', async () => {
// make changes to form
await userEvent.clear(ui.editGroupModal.namespaceInput.get());
await userEvent.type(ui.editGroupModal.namespaceInput.get(), 'super namespace');
await userEvent.clear(ui.editGroupModal.ruleGroupInput.get());
await userEvent.type(ui.editGroupModal.ruleGroupInput.get(), 'super group');
await userEvent.clear(ui.editGroupModal.intervalInput.get());
await userEvent.type(ui.editGroupModal.intervalInput.get(), '5m');
// submit, check that appropriate calls were made
await userEvent.click(ui.editGroupModal.saveButton.get());
await waitFor(() => expect(ui.editGroupModal.namespaceInput.query()).not.toBeInTheDocument());
expect(mocks.api.setRulerRuleGroup).toHaveBeenCalledTimes(2);
expect(mocks.api.deleteNamespace).toHaveBeenCalledTimes(1);
expect(mocks.api.deleteGroup).not.toHaveBeenCalled();
expect(mocks.api.fetchRulerRules).toHaveBeenCalledTimes(4);
Alerting: Add support to distinguish Prometheus datasource subtypes (Mimir, Cortex and Vanilla Prometheus) (#46771) * Add basic UI for custom ruler URL * Add build info fetching for alerting data sources * Add keeping data sources build info in the store * Use data source build info to construct data source urls * Remove unused code * Add custom ruler support in prometheus api calls * Migrate actions * Use thunk condition to prevent multiple data source buildinfo fetches * Unify prom and ruler rules loading * Upgrade RuleEditor tests * Upgrade RuleList tests * Upgrade PanelAlertTab tests * Upgrade actions tests * Build info refactoring * Get rid of lotex ruler support action * Add prom ruler availability checking when the buildinfo is not available * Add rulerUrlBuilder tests * Improve prometheus data source validation, small build info refactoring * Change prefix based on Prometheus subtype * Use the correct path * Revert config routing * Add deprecation notice for /api/prom prefix * Add tests to the datasource subtype * Remove custom ruler support * Remove deprecation notice * Prevent fetching ruler rules when ruler api is not available * Add build info tests * Unify naming of ruler methods * Fix test * Change buildinfo data source validation * Use strings for subtype params and unveil mimir * organise imports * frontend changes and wordsmithing * fix test suite * add a nicer verbose message for prometheus datasources * detect Mimir datasource * fix test * fix buildinfo test for Mimir * shrink vectors * add some code documentation * DRY prepareRulesFilterQueryParams * clarify that Prometheus does not support managing rules * Improve buildinfo error handling Co-authored-by: gotjosh <josue.abreu@gmail.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
3 years ago
expect(mocks.api.setRulerRuleGroup).toHaveBeenNthCalledWith(
1,
{ dataSourceName: testDatasources.prom.name, apiVersion: 'legacy' },
'super namespace',
{
...someRulerRules['namespace1'][0],
name: 'super group',
interval: '5m',
}
);
expect(mocks.api.setRulerRuleGroup).toHaveBeenNthCalledWith(
2,
Alerting: Add support to distinguish Prometheus datasource subtypes (Mimir, Cortex and Vanilla Prometheus) (#46771) * Add basic UI for custom ruler URL * Add build info fetching for alerting data sources * Add keeping data sources build info in the store * Use data source build info to construct data source urls * Remove unused code * Add custom ruler support in prometheus api calls * Migrate actions * Use thunk condition to prevent multiple data source buildinfo fetches * Unify prom and ruler rules loading * Upgrade RuleEditor tests * Upgrade RuleList tests * Upgrade PanelAlertTab tests * Upgrade actions tests * Build info refactoring * Get rid of lotex ruler support action * Add prom ruler availability checking when the buildinfo is not available * Add rulerUrlBuilder tests * Improve prometheus data source validation, small build info refactoring * Change prefix based on Prometheus subtype * Use the correct path * Revert config routing * Add deprecation notice for /api/prom prefix * Add tests to the datasource subtype * Remove custom ruler support * Remove deprecation notice * Prevent fetching ruler rules when ruler api is not available * Add build info tests * Unify naming of ruler methods * Fix test * Change buildinfo data source validation * Use strings for subtype params and unveil mimir * organise imports * frontend changes and wordsmithing * fix test suite * add a nicer verbose message for prometheus datasources * detect Mimir datasource * fix test * fix buildinfo test for Mimir * shrink vectors * add some code documentation * DRY prepareRulesFilterQueryParams * clarify that Prometheus does not support managing rules * Improve buildinfo error handling Co-authored-by: gotjosh <josue.abreu@gmail.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
3 years ago
{ dataSourceName: testDatasources.prom.name, apiVersion: 'legacy' },
'super namespace',
someRulerRules['namespace1'][1]
);
Alerting: Add support to distinguish Prometheus datasource subtypes (Mimir, Cortex and Vanilla Prometheus) (#46771) * Add basic UI for custom ruler URL * Add build info fetching for alerting data sources * Add keeping data sources build info in the store * Use data source build info to construct data source urls * Remove unused code * Add custom ruler support in prometheus api calls * Migrate actions * Use thunk condition to prevent multiple data source buildinfo fetches * Unify prom and ruler rules loading * Upgrade RuleEditor tests * Upgrade RuleList tests * Upgrade PanelAlertTab tests * Upgrade actions tests * Build info refactoring * Get rid of lotex ruler support action * Add prom ruler availability checking when the buildinfo is not available * Add rulerUrlBuilder tests * Improve prometheus data source validation, small build info refactoring * Change prefix based on Prometheus subtype * Use the correct path * Revert config routing * Add deprecation notice for /api/prom prefix * Add tests to the datasource subtype * Remove custom ruler support * Remove deprecation notice * Prevent fetching ruler rules when ruler api is not available * Add build info tests * Unify naming of ruler methods * Fix test * Change buildinfo data source validation * Use strings for subtype params and unveil mimir * organise imports * frontend changes and wordsmithing * fix test suite * add a nicer verbose message for prometheus datasources * detect Mimir datasource * fix test * fix buildinfo test for Mimir * shrink vectors * add some code documentation * DRY prepareRulesFilterQueryParams * clarify that Prometheus does not support managing rules * Improve buildinfo error handling Co-authored-by: gotjosh <josue.abreu@gmail.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
3 years ago
expect(mocks.api.deleteNamespace).toHaveBeenLastCalledWith(
{ dataSourceName: testDatasources.prom.name, apiVersion: 'legacy' },
'namespace1'
);
});
testCase('rename just the lotex group', async () => {
// make changes to form
await userEvent.clear(ui.editGroupModal.ruleGroupInput.get());
await userEvent.type(ui.editGroupModal.ruleGroupInput.get(), 'super group');
await userEvent.clear(ui.editGroupModal.intervalInput.get());
await userEvent.type(ui.editGroupModal.intervalInput.get(), '5m');
// submit, check that appropriate calls were made
await userEvent.click(ui.editGroupModal.saveButton.get());
await waitFor(() => expect(ui.editGroupModal.namespaceInput.query()).not.toBeInTheDocument());
expect(mocks.api.setRulerRuleGroup).toHaveBeenCalledTimes(1);
expect(mocks.api.deleteGroup).toHaveBeenCalledTimes(1);
expect(mocks.api.deleteNamespace).not.toHaveBeenCalled();
expect(mocks.api.fetchRulerRules).toHaveBeenCalledTimes(4);
Alerting: Add support to distinguish Prometheus datasource subtypes (Mimir, Cortex and Vanilla Prometheus) (#46771) * Add basic UI for custom ruler URL * Add build info fetching for alerting data sources * Add keeping data sources build info in the store * Use data source build info to construct data source urls * Remove unused code * Add custom ruler support in prometheus api calls * Migrate actions * Use thunk condition to prevent multiple data source buildinfo fetches * Unify prom and ruler rules loading * Upgrade RuleEditor tests * Upgrade RuleList tests * Upgrade PanelAlertTab tests * Upgrade actions tests * Build info refactoring * Get rid of lotex ruler support action * Add prom ruler availability checking when the buildinfo is not available * Add rulerUrlBuilder tests * Improve prometheus data source validation, small build info refactoring * Change prefix based on Prometheus subtype * Use the correct path * Revert config routing * Add deprecation notice for /api/prom prefix * Add tests to the datasource subtype * Remove custom ruler support * Remove deprecation notice * Prevent fetching ruler rules when ruler api is not available * Add build info tests * Unify naming of ruler methods * Fix test * Change buildinfo data source validation * Use strings for subtype params and unveil mimir * organise imports * frontend changes and wordsmithing * fix test suite * add a nicer verbose message for prometheus datasources * detect Mimir datasource * fix test * fix buildinfo test for Mimir * shrink vectors * add some code documentation * DRY prepareRulesFilterQueryParams * clarify that Prometheus does not support managing rules * Improve buildinfo error handling Co-authored-by: gotjosh <josue.abreu@gmail.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
3 years ago
expect(mocks.api.setRulerRuleGroup).toHaveBeenNthCalledWith(
1,
{ dataSourceName: testDatasources.prom.name, apiVersion: 'legacy' },
'namespace1',
{
...someRulerRules['namespace1'][0],
name: 'super group',
interval: '5m',
}
);
expect(mocks.api.deleteGroup).toHaveBeenLastCalledWith(
{ dataSourceName: testDatasources.prom.name, apiVersion: 'legacy' },
'namespace1',
'group1'
);
});
testCase('edit lotex group eval interval, no renaming', async () => {
// make changes to form
await userEvent.clear(ui.editGroupModal.intervalInput.get());
await userEvent.type(ui.editGroupModal.intervalInput.get(), '5m');
// submit, check that appropriate calls were made
await userEvent.click(ui.editGroupModal.saveButton.get());
await waitFor(() => expect(ui.editGroupModal.namespaceInput.query()).not.toBeInTheDocument());
expect(mocks.api.setRulerRuleGroup).toHaveBeenCalledTimes(1);
expect(mocks.api.deleteGroup).not.toHaveBeenCalled();
expect(mocks.api.deleteNamespace).not.toHaveBeenCalled();
expect(mocks.api.fetchRulerRules).toHaveBeenCalledTimes(4);
Alerting: Add support to distinguish Prometheus datasource subtypes (Mimir, Cortex and Vanilla Prometheus) (#46771) * Add basic UI for custom ruler URL * Add build info fetching for alerting data sources * Add keeping data sources build info in the store * Use data source build info to construct data source urls * Remove unused code * Add custom ruler support in prometheus api calls * Migrate actions * Use thunk condition to prevent multiple data source buildinfo fetches * Unify prom and ruler rules loading * Upgrade RuleEditor tests * Upgrade RuleList tests * Upgrade PanelAlertTab tests * Upgrade actions tests * Build info refactoring * Get rid of lotex ruler support action * Add prom ruler availability checking when the buildinfo is not available * Add rulerUrlBuilder tests * Improve prometheus data source validation, small build info refactoring * Change prefix based on Prometheus subtype * Use the correct path * Revert config routing * Add deprecation notice for /api/prom prefix * Add tests to the datasource subtype * Remove custom ruler support * Remove deprecation notice * Prevent fetching ruler rules when ruler api is not available * Add build info tests * Unify naming of ruler methods * Fix test * Change buildinfo data source validation * Use strings for subtype params and unveil mimir * organise imports * frontend changes and wordsmithing * fix test suite * add a nicer verbose message for prometheus datasources * detect Mimir datasource * fix test * fix buildinfo test for Mimir * shrink vectors * add some code documentation * DRY prepareRulesFilterQueryParams * clarify that Prometheus does not support managing rules * Improve buildinfo error handling Co-authored-by: gotjosh <josue.abreu@gmail.com> Co-authored-by: gillesdemey <gilles.de.mey@gmail.com>
3 years ago
expect(mocks.api.setRulerRuleGroup).toHaveBeenNthCalledWith(
1,
{ dataSourceName: testDatasources.prom.name, apiVersion: 'legacy' },
'namespace1',
{
...someRulerRules['namespace1'][0],
interval: '5m',
}
);
});
});
describe('RBAC Enabled', () => {
describe('Export button', () => {
it('Export button should be visible when the user has alert read permissions', async () => {
grantUserPermissions([AccessControlAction.AlertingRuleRead]);
mocks.getAllDataSourcesMock.mockReturnValue([]);
setDataSourceSrv(new MockDataSourceSrv({}));
mocks.api.fetchRules.mockResolvedValue([
mockPromRuleNamespace({
name: 'foofolder',
dataSourceName: GRAFANA_RULES_SOURCE_NAME,
groups: [
mockPromRuleGroup({
name: 'grafana-group',
rules: [
mockPromAlertingRule({
query: '[]',
}),
],
}),
],
}),
]);
mocks.api.fetchRulerRules.mockResolvedValue({});
renderRuleList();
await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalledTimes(1));
expect(ui.exportButton.get()).toBeInTheDocument();
});
});
describe('Grafana Managed Alerts', () => {
it('New alert button should be visible when the user has alert rule create and folder read permissions and no rules exists', async () => {
grantUserPermissions([
AccessControlAction.FoldersRead,
AccessControlAction.AlertingRuleCreate,
AccessControlAction.AlertingRuleRead,
]);
mocks.getAllDataSourcesMock.mockReturnValue([]);
setDataSourceSrv(new MockDataSourceSrv({}));
mocks.api.fetchRules.mockResolvedValue([]);
mocks.api.fetchRulerRules.mockResolvedValue({});
renderRuleList();
await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalledTimes(1));
expect(ui.newRuleButton.get()).toBeInTheDocument();
});
it('New alert button should be visible when the user has alert rule create and folder read permissions and rules already exists', async () => {
grantUserPermissions([
AccessControlAction.FoldersRead,
AccessControlAction.AlertingRuleCreate,
AccessControlAction.AlertingRuleRead,
]);
mocks.getAllDataSourcesMock.mockReturnValue([]);
setDataSourceSrv(new MockDataSourceSrv({}));
mocks.api.fetchRules.mockResolvedValue(somePromRules('grafana'));
mocks.api.fetchRulerRules.mockResolvedValue(someRulerRules);
renderRuleList();
await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalledTimes(1));
expect(ui.newRuleButton.get()).toBeInTheDocument();
});
});
describe('Cloud Alerts', () => {
it('New alert button should be visible when the user has the alert rule external write and datasource read permissions and no rules exists', async () => {
grantUserPermissions([
// AccessControlAction.AlertingRuleRead,
AccessControlAction.DataSourcesRead,
AccessControlAction.AlertingRuleExternalRead,
AccessControlAction.AlertingRuleExternalWrite,
]);
mocks.getAllDataSourcesMock.mockReturnValue([dataSources.prom]);
setDataSourceSrv(new MockDataSourceSrv({ prom: dataSources.prom }));
mocks.api.discoverFeatures.mockResolvedValue({
application: PromApplication.Cortex,
features: {
rulerApiEnabled: true,
},
});
mocks.api.fetchRules.mockResolvedValue([]);
mocks.api.fetchRulerRules.mockResolvedValue({});
renderRuleList();
await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalledTimes(1));
expect(ui.newRuleButton.get()).toBeInTheDocument();
});
it('New alert button should be visible when the user has the alert rule external write and data source read permissions and rules already exists', async () => {
grantUserPermissions([
AccessControlAction.DataSourcesRead,
AccessControlAction.AlertingRuleExternalRead,
AccessControlAction.AlertingRuleExternalWrite,
]);
mocks.getAllDataSourcesMock.mockReturnValue([dataSources.prom]);
setDataSourceSrv(new MockDataSourceSrv({ prom: dataSources.prom }));
mocks.api.discoverFeatures.mockResolvedValue({
application: PromApplication.Cortex,
features: {
rulerApiEnabled: true,
},
});
mocks.api.fetchRules.mockResolvedValue(somePromRules('Cortex'));
mocks.api.fetchRulerRules.mockResolvedValue(someRulerRules);
renderRuleList();
await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalledTimes(1));
expect(ui.newRuleButton.get()).toBeInTheDocument();
});
});
});
describe('Analytics', () => {
it('Sends log info when creating an alert rule from a scratch', async () => {
grantUserPermissions([
AccessControlAction.FoldersRead,
AccessControlAction.AlertingRuleCreate,
AccessControlAction.AlertingRuleRead,
]);
mocks.getAllDataSourcesMock.mockReturnValue([]);
setDataSourceSrv(new MockDataSourceSrv({}));
mocks.api.fetchRules.mockResolvedValue([]);
mocks.api.fetchRulerRules.mockResolvedValue({});
renderRuleList();
await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalledTimes(1));
const button = screen.getByText('New alert rule');
button.addEventListener('click', (event) => event.preventDefault(), false);
expect(button).toBeEnabled();
await userEvent.click(button);
expect(analytics.logInfo).toHaveBeenCalledWith(analytics.LogMessages.alertRuleFromScratch);
});
});
});