2022-04-22 14:33:13 +01:00
import { SerializedError } from '@reduxjs/toolkit' ;
2023-02-20 08:47:50 +01:00
import { prettyDOM , render , screen , waitFor } from '@testing-library/react' ;
2022-04-22 14:33:13 +01:00
import userEvent from '@testing-library/user-event' ;
2024-03-26 16:26:50 +00:00
import { setupServer } from 'msw/node' ;
2022-04-22 14:33:13 +01:00
import React from 'react' ;
2023-02-02 09:53:06 +01:00
import { TestProvider } from 'test/helpers/TestProvider' ;
2022-11-03 12:50:32 +01:00
import { byRole , byTestId , byText } from 'testing-library-selector' ;
2022-04-22 14:33:13 +01:00
2024-03-26 16:26:50 +00:00
import { PluginExtensionTypes , PluginMeta } from '@grafana/data' ;
2024-03-21 09:05:51 +01:00
import { selectors } from '@grafana/e2e-selectors' ;
2023-11-20 16:43:36 +00:00
import {
DataSourceSrv ,
getPluginLinkExtensions ,
locationService ,
setBackendSrv ,
setDataSourceSrv ,
2024-04-24 09:33:16 +02:00
usePluginLinkExtensions ,
2023-11-20 16:43:36 +00:00
} from '@grafana/runtime' ;
2023-01-11 12:52:20 +01:00
import { backendSrv } from 'app/core/services/backend_srv' ;
2022-10-31 14:42:09 +01:00
import * as ruleActionButtons from 'app/features/alerting/unified/components/rules/RuleActionsButtons' ;
2024-03-26 16:26:50 +00:00
import {
mockAlertRuleApi ,
mockApi ,
mockFolderApi ,
mockSearchApi ,
mockUserApi ,
} from 'app/features/alerting/unified/mockApi' ;
import { mockAlertmanagerChoiceResponse } from 'app/features/alerting/unified/mocks/alertmanagerApi' ;
2022-11-03 12:50:32 +01:00
import * as actions from 'app/features/alerting/unified/state/actions' ;
2024-03-28 15:21:00 +00:00
import { getMockUser } from 'app/features/users/__mocks__/userMocks' ;
2024-03-26 16:26:50 +00:00
import { AlertmanagerChoice } from 'app/plugins/datasource/alertmanager/types' ;
2024-03-26 17:37:49 +00:00
import { AccessControlAction } from 'app/types' ;
2022-04-22 14:33:13 +01:00
import { PromAlertingRuleState , PromApplication } from 'app/types/unified-alerting-dto' ;
2023-10-25 16:47:32 +02:00
import * as analytics from './Analytics' ;
2022-04-22 14:33:13 +01:00
import RuleList from './RuleList' ;
2022-05-18 10:45:26 +02:00
import { discoverFeatures } from './api/buildInfo' ;
2022-04-22 14:33:13 +01:00
import { fetchRules } from './api/prometheus' ;
2024-05-14 10:01:08 +02:00
import * as apiRuler from './api/ruler' ;
2022-04-26 15:57:00 +02:00
import { deleteNamespace , deleteRulerRulesGroup , fetchRulerRules , setRulerRuleGroup } from './api/ruler' ;
2021-04-07 08:42:43 +03:00
import {
2024-01-26 14:56:00 +01:00
MockDataSourceSrv ,
2024-05-14 10:01:08 +02:00
getPotentiallyPausedRulerRules ,
2022-04-26 15:57:00 +02:00
grantUserPermissions ,
2021-04-07 08:42:43 +03:00
mockDataSource ,
2024-05-14 10:01:08 +02:00
mockFolder ,
2021-04-07 08:42:43 +03:00
mockPromAlert ,
mockPromAlertingRule ,
mockPromRecordingRule ,
mockPromRuleGroup ,
mockPromRuleNamespace ,
2024-05-14 10:01:08 +02:00
mockRulerGrafanaRule ,
2024-03-25 18:29:01 +00:00
pausedPromRules ,
2021-08-26 16:40:27 +03:00
somePromRules ,
someRulerRules ,
2021-04-07 08:42:43 +03:00
} from './mocks' ;
2022-08-01 15:01:14 +02:00
import * as config from './utils/config' ;
2021-04-07 08:42:43 +03:00
import { DataSourceType , GRAFANA_RULES_SOURCE_NAME } from './utils/datasource' ;
2023-11-20 16:43:36 +00:00
jest . mock ( '@grafana/runtime' , ( ) = > ( {
. . . jest . requireActual ( '@grafana/runtime' ) ,
getPluginLinkExtensions : jest.fn ( ) ,
2024-04-24 09:33:16 +02:00
usePluginLinkExtensions : jest.fn ( ) ,
2024-01-30 13:34:59 +01:00
useReturnToPrevious : jest.fn ( ) ,
2023-11-20 16:43:36 +00:00
} ) ) ;
2022-04-04 19:30:17 +02:00
jest . mock ( './api/buildInfo' ) ;
2021-04-07 08:42:43 +03:00
jest . mock ( './api/prometheus' ) ;
2021-08-26 16:40:27 +03:00
jest . mock ( './api/ruler' ) ;
2022-10-31 14:42:09 +01:00
jest . mock ( '../../../core/hooks/useMediaQueryChange' ) ;
jest . spyOn ( ruleActionButtons , 'matchesWidth' ) . mockReturnValue ( false ) ;
2021-08-26 16:40:27 +03:00
jest . mock ( 'app/core/core' , ( ) = > ( {
2023-05-22 14:26:20 -03:00
. . . jest . requireActual ( 'app/core/core' ) ,
2021-08-26 16:40:27 +03:00
appEvents : {
subscribe : ( ) = > {
return { unsubscribe : ( ) = > { } } ;
} ,
emit : ( ) = > { } ,
} ,
} ) ) ;
2021-04-07 08:42:43 +03:00
2023-10-25 16:47:32 +02:00
jest . spyOn ( analytics , 'logInfo' ) ;
2022-08-01 15:01:14 +02:00
jest . spyOn ( config , 'getAllDataSources' ) ;
2022-11-03 12:50:32 +01:00
jest . spyOn ( actions , 'rulesInSameGroupHaveInvalidFor' ) . mockReturnValue ( [ ] ) ;
2024-05-14 10:01:08 +02:00
jest . spyOn ( apiRuler , 'rulerUrlBuilder' ) ;
2022-08-01 15:01:14 +02:00
2021-04-07 08:42:43 +03:00
const mocks = {
2022-08-01 15:01:14 +02:00
getAllDataSourcesMock : jest.mocked ( config . getAllDataSources ) ,
2023-11-20 16:43:36 +00:00
getPluginLinkExtensionsMock : jest.mocked ( getPluginLinkExtensions ) ,
2024-04-24 09:33:16 +02:00
usePluginLinkExtensionsMock : jest.mocked ( usePluginLinkExtensions ) ,
2022-11-03 12:50:32 +01:00
rulesInSameGroupHaveInvalidForMock : jest.mocked ( actions . rulesInSameGroupHaveInvalidFor ) ,
2021-04-07 08:42:43 +03:00
api : {
2022-05-18 10:45:26 +02:00
discoverFeatures : jest.mocked ( discoverFeatures ) ,
2022-02-10 09:50:59 +11:00
fetchRules : jest.mocked ( fetchRules ) ,
fetchRulerRules : jest.mocked ( fetchRulerRules ) ,
deleteGroup : jest.mocked ( deleteRulerRulesGroup ) ,
deleteNamespace : jest.mocked ( deleteNamespace ) ,
setRulerRuleGroup : jest.mocked ( setRulerRuleGroup ) ,
2024-05-14 10:01:08 +02:00
rulerBuilderMock : jest.mocked ( apiRuler . rulerUrlBuilder ) ,
2021-04-07 08:42:43 +03:00
} ,
} ;
const renderRuleList = ( ) = > {
2021-08-26 16:40:27 +03:00
locationService . push ( '/' ) ;
2021-04-07 08:42:43 +03:00
return render (
2023-02-02 09:53:06 +01:00
< TestProvider >
< RuleList / >
< / TestProvider >
2021-04-07 08:42:43 +03:00
) ;
} ;
const dataSources = {
prom : mockDataSource ( {
name : 'Prometheus' ,
type : DataSourceType . Prometheus ,
} ) ,
2021-07-13 01:06:09 +03:00
promdisabled : mockDataSource ( {
name : 'Prometheus-disabled' ,
type : DataSourceType . Prometheus ,
jsonData : {
manageAlerts : false ,
} ,
} ) ,
2021-04-07 08:42:43 +03:00
loki : mockDataSource ( {
name : 'Loki' ,
type : DataSourceType . Loki ,
} ) ,
promBroken : mockDataSource ( {
name : 'Prometheus-broken' ,
type : DataSourceType . Prometheus ,
} ) ,
} ;
const ui = {
ruleGroup : byTestId ( 'rule-group' ) ,
2024-03-25 18:29:01 +00:00
pausedRuleGroup : byText ( /groupPaused/ ) ,
2021-04-07 08:42:43 +03:00
cloudRulesSourceErrors : byTestId ( 'cloud-rulessource-errors' ) ,
2024-03-21 09:05:51 +01:00
groupCollapseToggle : byTestId ( selectors . components . AlertRules . groupToggle ) ,
ruleCollapseToggle : byTestId ( selectors . components . AlertRules . toggle ) ,
2021-04-07 08:42:43 +03:00
rulesTable : byTestId ( 'rules-table' ) ,
2021-06-23 09:27:47 +03:00
ruleRow : byTestId ( 'row' ) ,
2024-03-21 09:05:51 +01:00
expandedContent : byTestId ( selectors . components . AlertRules . expandedContent ) ,
2021-07-26 12:05:49 -07:00
rulesFilterInput : byTestId ( 'search-query-input' ) ,
2021-08-12 10:57:52 +03:00
moreErrorsButton : byRole ( 'button' , { name : /more errors/ } ) ,
2021-08-26 16:40:27 +03:00
editCloudGroupIcon : byTestId ( 'edit-group' ) ,
2024-01-26 14:56:00 +01:00
newRuleButton : byText ( /new alert rule/i ) ,
exportButton : byText ( /export rules/i ) ,
2021-08-26 16:40:27 +03:00
editGroupModal : {
2023-02-20 08:47:50 +01:00
dialog : byRole ( 'dialog' ) ,
namespaceInput : byRole ( 'textbox' , { name : /^Namespace/ } ) ,
ruleGroupInput : byRole ( 'textbox' , { name : /Evaluation group/ } ) ,
2022-11-03 12:50:32 +01:00
intervalInput : byRole ( 'textbox' , {
2023-07-18 10:56:02 -03:00
name : /Evaluation interval How often is the rule evaluated. Applies to every rule within the group./i ,
2022-11-03 12:50:32 +01:00
} ) ,
2023-07-18 10:56:02 -03:00
saveButton : byRole ( 'button' , { name : /Save/ } ) ,
2021-08-26 16:40:27 +03:00
} ,
2024-03-25 18:29:01 +00:00
stateTags : {
paused : byText ( /^Paused/ ) ,
} ,
actionButtons : {
2024-04-30 16:17:55 +01:00
more : byRole ( 'button' , { name : /more-actions/ } ) ,
2024-03-25 18:29:01 +00:00
} ,
moreActionItems : {
2024-03-28 15:20:40 +00:00
pause : byRole ( 'menuitem' , { name : /pause evaluation/i } ) ,
resume : byRole ( 'menuitem' , { name : /resume evaluation/i } ) ,
2024-03-25 18:29:01 +00:00
} ,
2021-04-07 08:42:43 +03:00
} ;
2024-03-26 16:26:50 +00:00
const server = setupServer ( ) ;
const configureMockServer = ( ) = > {
mockSearchApi ( server ) . search ( [ ] ) ;
2024-03-28 15:21:00 +00:00
mockUserApi ( server ) . user ( getMockUser ( ) ) ;
2024-03-26 16:26:50 +00:00
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' ] ,
} ) ;
2024-05-14 10:01:08 +02:00
mockAlertRuleApi ( server ) . rulerRuleGroup ( GRAFANA_RULES_SOURCE_NAME , 'NAMESPACE_UID' , 'groupPaused' , {
name : 'group-1' ,
interval : '1m' ,
rules : [ mockRulerGrafanaRule ( ) ] ,
} ) ;
2024-03-26 16:26:50 +00:00
} ;
2023-01-11 12:52:20 +01:00
beforeAll ( ( ) = > {
setBackendSrv ( backendSrv ) ;
} ) ;
2021-04-07 08:42:43 +03:00
describe ( 'RuleList' , ( ) = > {
2022-05-23 09:58:20 -04:00
beforeEach ( ( ) = > {
2024-03-26 16:26:50 +00:00
server . listen ( { onUnhandledRequest : 'error' } ) ;
configureMockServer ( ) ;
2023-09-12 15:20:39 +02:00
grantUserPermissions ( [
AccessControlAction . AlertingRuleRead ,
AccessControlAction . AlertingRuleUpdate ,
AccessControlAction . AlertingRuleExternalRead ,
AccessControlAction . AlertingRuleExternalWrite ,
] ) ;
2022-11-03 12:50:32 +01:00
mocks . rulesInSameGroupHaveInvalidForMock . mockReturnValue ( [ ] ) ;
2024-04-24 09:33:16 +02:00
mocks . usePluginLinkExtensionsMock . mockReturnValue ( {
2023-11-20 16:43:36 +00:00
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 ( ) ,
} ,
] ,
2024-04-24 09:33:16 +02:00
isLoading : false ,
2023-11-20 16:43:36 +00:00
} ) ;
2022-05-23 09:58:20 -04:00
} ) ;
2021-04-15 04:53:40 -07:00
afterEach ( ( ) = > {
2024-03-26 16:26:50 +00:00
server . resetHandlers ( ) ;
2021-04-15 04:53:40 -07:00
jest . resetAllMocks ( ) ;
2023-02-14 16:46:42 +01:00
setDataSourceSrv ( undefined as unknown as DataSourceSrv ) ;
2021-04-15 04:53:40 -07:00
} ) ;
2021-04-07 08:42:43 +03:00
2024-03-26 08:47:16 +00:00
afterAll ( ( ) = > {
2024-03-26 16:26:50 +00:00
server . close ( ) ;
2024-03-26 08:47:16 +00:00
} ) ;
2021-04-07 08:42:43 +03:00
it ( 'load & show rule groups from multiple cloud data sources' , async ( ) = > {
mocks . getAllDataSourcesMock . mockReturnValue ( Object . values ( dataSources ) ) ;
2021-04-15 04:53:40 -07:00
setDataSourceSrv ( new MockDataSourceSrv ( dataSources ) ) ;
2022-05-18 10:45:26 +02:00
mocks . api . discoverFeatures . mockResolvedValue ( {
2022-04-04 19:30:17 +02:00
application : PromApplication.Prometheus ,
features : {
rulerApiEnabled : true ,
} ,
} ) ;
2021-04-07 08:42:43 +03:00
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 ( {
2021-04-14 15:57:36 +03:00
name : 'foofolder' ,
2021-04-07 08:42:43 +03:00
dataSourceName : GRAFANA_RULES_SOURCE_NAME ,
groups : [
mockPromRuleGroup ( {
name : 'grafana-group' ,
2021-04-19 12:53:02 +03:00
rules : [
mockPromAlertingRule ( {
query : '[]' ,
} ) ,
] ,
2021-04-07 08:42:43 +03:00
} ) ,
] ,
} ) ,
] ) ;
}
return Promise . reject ( new Error ( ` unexpected datasourceName: ${ dataSourceName } ` ) ) ;
} ) ;
2022-10-31 15:55:47 +01:00
mocks . api . fetchRulerRules . mockRejectedValue ( { status : 500 , data : { message : 'Server error' } } ) ;
2021-04-07 08:42:43 +03:00
await renderRuleList ( ) ;
await waitFor ( ( ) = > expect ( mocks . api . fetchRules ) . toHaveBeenCalledTimes ( 4 ) ) ;
const groups = await ui . ruleGroup . findAll ( ) ;
expect ( groups ) . toHaveLength ( 5 ) ;
2021-04-14 15:57:36 +03:00
expect ( groups [ 0 ] ) . toHaveTextContent ( 'foofolder' ) ;
2022-04-20 11:41:33 +02:00
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' ) ;
2021-04-07 08:42:43 +03:00
const errors = await ui . cloudRulesSourceErrors . find ( ) ;
2021-08-12 10:57:52 +03:00
expect ( errors ) . not . toHaveTextContent (
'Failed to load rules state from Prometheus-broken: this datasource is broken'
) ;
2022-04-21 13:15:21 +01:00
await userEvent . click ( ui . moreErrorsButton . get ( ) ) ;
2021-04-07 08:42:43 +03:00
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 ] ) ;
2022-04-04 19:30:17 +02:00
2021-04-15 04:53:40 -07:00
setDataSourceSrv ( new MockDataSourceSrv ( { prom : dataSources.prom } ) ) ;
2022-05-18 10:45:26 +02:00
mocks . api . discoverFeatures . mockResolvedValue ( {
2022-10-24 14:53:11 -05:00
application : PromApplication.Cortex ,
2022-04-04 19:30:17 +02:00
features : {
rulerApiEnabled : true ,
} ,
} ) ;
2021-04-07 08:42:43 +03:00
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 ) ;
2023-03-09 16:24:32 +01:00
await waitFor ( ( ) = > expect ( groups [ 0 ] ) . toHaveTextContent ( /firing|pending|normal/ ) ) ;
2023-03-14 09:45:27 +01:00
await waitFor ( ( ) = > expect ( groups [ 1 ] ) . toHaveTextContent ( /firing|pending|normal/ ) ) ;
2023-03-09 16:24:32 +01:00
2022-12-12 13:53:18 +01:00
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' ) ;
2021-04-07 08:42:43 +03:00
// expand second group to see rules table
expect ( ui . rulesTable . query ( ) ) . not . toBeInTheDocument ( ) ;
2022-04-21 13:15:21 +01:00
await userEvent . click ( ui . groupCollapseToggle . get ( groups [ 1 ] ) ) ;
2021-04-07 08:42:43 +03:00
const table = await ui . rulesTable . find ( groups [ 1 ] ) ;
// check that rule rows are rendered properly
2021-06-23 09:27:47 +03:00
let ruleRows = ui . ruleRow . getAll ( table ) ;
2021-04-07 08:42:43 +03:00
expect ( ruleRows ) . toHaveLength ( 4 ) ;
2021-05-14 13:41:13 +03:00
expect ( ruleRows [ 0 ] ) . toHaveTextContent ( 'Recording rule' ) ;
2021-04-07 08:42:43 +03:00
expect ( ruleRows [ 0 ] ) . toHaveTextContent ( 'recordingrule' ) ;
2021-05-14 13:41:13 +03:00
expect ( ruleRows [ 1 ] ) . toHaveTextContent ( 'Firing' ) ;
2021-04-07 08:42:43 +03:00
expect ( ruleRows [ 1 ] ) . toHaveTextContent ( 'alertingrule' ) ;
2021-05-14 13:41:13 +03:00
expect ( ruleRows [ 2 ] ) . toHaveTextContent ( 'Pending' ) ;
2021-04-07 08:42:43 +03:00
expect ( ruleRows [ 2 ] ) . toHaveTextContent ( 'p-rule' ) ;
2021-05-14 13:41:13 +03:00
expect ( ruleRows [ 3 ] ) . toHaveTextContent ( 'Normal' ) ;
2021-04-07 08:42:43 +03:00
expect ( ruleRows [ 3 ] ) . toHaveTextContent ( 'i-rule' ) ;
expect ( byText ( 'Labels' ) . query ( ) ) . not . toBeInTheDocument ( ) ;
// expand alert details
2022-04-21 13:15:21 +01:00
await userEvent . click ( ui . ruleCollapseToggle . get ( ruleRows [ 1 ] ) ) ;
2021-04-07 08:42:43 +03:00
2021-06-23 09:27:47 +03:00
const ruleDetails = ui . expandedContent . get ( ruleRows [ 1 ] ) ;
2024-04-23 14:38:31 +02:00
const labels = byTestId ( 'label-value' ) . getAll ( ruleDetails ) ;
expect ( labels [ 0 ] ) . toHaveTextContent ( 'severitywarning' ) ;
expect ( labels [ 1 ] ) . toHaveTextContent ( 'foobar' ) ;
2021-04-07 08:42:43 +03:00
expect ( ruleDetails ) . toHaveTextContent ( 'Expressiontopk ( 5 , foo ) [ 5m ]' ) ;
expect ( ruleDetails ) . toHaveTextContent ( 'messagegreat alert' ) ;
expect ( ruleDetails ) . toHaveTextContent ( 'Matching instances' ) ;
// finally, check instances table
2021-06-23 09:27:47 +03:00
const instancesTable = byTestId ( 'dynamic-table' ) . get ( ruleDetails ) ;
2021-04-07 08:42:43 +03:00
expect ( instancesTable ) . toBeInTheDocument ( ) ;
2021-06-23 09:27:47 +03:00
const instanceRows = byTestId ( 'row' ) . getAll ( instancesTable ) ;
2021-04-07 08:42:43 +03:00
expect ( instanceRows ) . toHaveLength ( 2 ) ;
2024-04-23 14:38:31 +02:00
expect ( instanceRows ! [ 0 ] ) . toHaveTextContent ( 'Firingfoobarseveritywarning2021-03-18 08:47:05' ) ;
expect ( instanceRows ! [ 1 ] ) . toHaveTextContent ( 'Firingfoobazseverityerror2021-03-18 08:47:05' ) ;
2021-04-07 08:42:43 +03:00
// expand details of an instance
2022-04-21 13:15:21 +01:00
await userEvent . click ( ui . ruleCollapseToggle . get ( instanceRows ! [ 0 ] ) ) ;
2021-04-07 08:42:43 +03:00
2024-03-21 09:05:51 +01:00
const alertDetails = byTestId ( selectors . components . AlertRules . expandedContent ) . get ( instanceRows [ 0 ] ) ;
2021-04-07 08:42:43 +03:00
expect ( alertDetails ) . toHaveTextContent ( 'Value2e+10' ) ;
expect ( alertDetails ) . toHaveTextContent ( 'messagefirst alert message' ) ;
// collapse everything again
2022-04-21 13:15:21 +01:00
await userEvent . click ( ui . ruleCollapseToggle . get ( instanceRows ! [ 0 ] ) ) ;
2024-03-21 09:05:51 +01:00
expect ( byTestId ( selectors . components . AlertRules . expandedContent ) . query ( instanceRows [ 0 ] ) ) . not . toBeInTheDocument ( ) ;
2022-04-21 13:15:21 +01:00
await userEvent . click ( ui . ruleCollapseToggle . getAll ( ruleRows [ 1 ] ) [ 0 ] ) ;
await userEvent . click ( ui . groupCollapseToggle . get ( groups [ 1 ] ) ) ;
2021-04-07 08:42:43 +03:00
expect ( ui . rulesTable . query ( ) ) . not . toBeInTheDocument ( ) ;
} ) ;
2021-07-26 12:05:49 -07:00
it ( 'filters rules and alerts by labels' , async ( ) = > {
mocks . getAllDataSourcesMock . mockReturnValue ( [ dataSources . prom ] ) ;
setDataSourceSrv ( new MockDataSourceSrv ( { prom : dataSources.prom } ) ) ;
2022-04-04 19:30:17 +02:00
2022-05-18 10:45:26 +02:00
mocks . api . discoverFeatures . mockResolvedValue ( {
2022-10-24 14:53:11 -05:00
application : PromApplication.Cortex ,
2022-04-04 19:30:17 +02:00
features : {
rulerApiEnabled : true ,
} ,
} ) ;
2021-08-26 16:40:27 +03:00
mocks . api . fetchRulerRules . mockResolvedValue ( { } ) ;
2021-07-26 12:05:49 -07:00
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 ( ) ;
2023-03-09 16:24:32 +01:00
2021-07-26 12:05:49 -07:00
const groups = await ui . ruleGroup . findAll ( ) ;
expect ( groups ) . toHaveLength ( 2 ) ;
const filterInput = ui . rulesFilterInput . get ( ) ;
2023-03-09 16:24:32 +01:00
await userEvent . type ( filterInput , 'label:foo=bar{Enter}' ) ;
2021-07-26 12:05:49 -07:00
// Input is debounced so wait for it to be visible
2023-01-26 13:44:14 +01:00
await waitFor ( ( ) = > expect ( filterInput ) . toHaveValue ( 'label:foo=bar' ) ) ;
2021-07-26 12:05:49 -07:00
// Group doesn't contain matching labels
2021-08-26 16:40:27 +03:00
await waitFor ( ( ) = > expect ( ui . ruleGroup . queryAll ( ) ) . toHaveLength ( 1 ) ) ;
2021-07-26 12:05:49 -07:00
2022-04-21 13:15:21 +01:00
await userEvent . click ( ui . groupCollapseToggle . get ( groups [ 0 ] ) ) ;
2021-07-26 12:05:49 -07:00
const ruleRows = ui . ruleRow . getAll ( groups [ 0 ] ) ;
expect ( ruleRows ) . toHaveLength ( 1 ) ;
2022-04-21 13:15:21 +01:00
await userEvent . click ( ui . ruleCollapseToggle . get ( ruleRows [ 0 ] ) ) ;
2021-07-26 12:05:49 -07:00
const ruleDetails = ui . expandedContent . get ( ruleRows [ 0 ] ) ;
2024-04-23 14:38:31 +02:00
const labels = byTestId ( 'label-value' ) . getAll ( ruleDetails ) ;
expect ( labels [ 0 ] ) . toHaveTextContent ( 'severitywarning' ) ;
expect ( labels [ 1 ] ) . toHaveTextContent ( 'foobar' ) ;
2021-07-26 12:05:49 -07:00
// Check for different label matchers
2022-04-21 13:15:21 +01:00
await userEvent . clear ( filterInput ) ;
2023-03-09 16:24:32 +01:00
await userEvent . type ( filterInput , 'label:foo!=bar label:foo!=baz{Enter}' ) ;
2021-07-26 12:05:49 -07:00
// Group doesn't contain matching labels
2021-08-26 16:40:27 +03:00
await waitFor ( ( ) = > expect ( ui . ruleGroup . queryAll ( ) ) . toHaveLength ( 1 ) ) ;
await waitFor ( ( ) = > expect ( ui . ruleGroup . get ( ) ) . toHaveTextContent ( 'group-2' ) ) ;
2022-04-21 13:15:21 +01:00
await userEvent . clear ( filterInput ) ;
2023-03-09 16:24:32 +01:00
await userEvent . type ( filterInput , 'label:"foo=~b.+"{Enter}' ) ;
2021-08-26 16:40:27 +03:00
await waitFor ( ( ) = > expect ( ui . ruleGroup . queryAll ( ) ) . toHaveLength ( 2 ) ) ;
2022-04-21 13:15:21 +01:00
await userEvent . clear ( filterInput ) ;
2023-03-09 16:24:32 +01:00
await userEvent . type ( filterInput , 'label:region=US{Enter}' ) ;
2021-08-26 16:40:27 +03:00
await waitFor ( ( ) = > expect ( ui . ruleGroup . queryAll ( ) ) . toHaveLength ( 1 ) ) ;
await waitFor ( ( ) = > expect ( ui . ruleGroup . get ( ) ) . toHaveTextContent ( 'group-2' ) ) ;
} ) ;
2024-03-25 18:29:01 +00:00
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' ) : [ ] )
) ;
2024-05-14 10:01:08 +02:00
mocks . api . rulerBuilderMock . mockReturnValue ( {
rules : ( ) = > ( { path : ` api/ruler/ ${ GRAFANA_RULES_SOURCE_NAME } /api/v1/rules ` } ) ,
namespace : ( ) = > ( { path : 'ruler' } ) ,
namespaceGroup : ( ) = > ( {
path : ` api/ruler/ ${ GRAFANA_RULES_SOURCE_NAME } /api/v1/rules/NAMESPACE_UID/groupPaused ` ,
} ) ,
} ) ;
2024-03-25 18:29:01 +00:00
} ) ;
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 ( ) ) ;
} ) ;
} ) ;
2021-08-26 16:40:27 +03:00
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 ) ) ;
2022-04-04 19:30:17 +02:00
2022-05-18 10:45:26 +02:00
mocks . api . discoverFeatures . mockResolvedValue ( {
2022-10-24 14:53:11 -05:00
application : PromApplication.Cortex ,
2022-04-04 19:30:17 +02:00
features : {
rulerApiEnabled : true ,
} ,
} ) ;
2021-08-26 16:40:27 +03:00
mocks . api . fetchRules . mockImplementation ( ( sourceName ) = >
Promise . resolve ( sourceName === testDatasources . prom . name ? somePromRules ( ) : [ ] )
) ;
2022-04-04 19:30:17 +02:00
mocks . api . fetchRulerRules . mockImplementation ( ( { dataSourceName } ) = >
Promise . resolve ( dataSourceName === testDatasources . prom . name ? someRulerRules : { } )
2021-08-26 16:40:27 +03:00
) ;
mocks . api . setRulerRuleGroup . mockResolvedValue ( ) ;
mocks . api . deleteNamespace . mockResolvedValue ( ) ;
await renderRuleList ( ) ;
expect ( await ui . rulesFilterInput . find ( ) ) . toHaveValue ( '' ) ;
2023-02-20 08:47:50 +01:00
await waitFor ( ( ) = > expect ( ui . ruleGroup . queryAll ( ) ) . toHaveLength ( 3 ) ) ;
2021-08-26 16:40:27 +03:00
const groups = await ui . ruleGroup . findAll ( ) ;
expect ( groups ) . toHaveLength ( 3 ) ;
// open edit dialog
2022-04-21 13:15:21 +01:00
await userEvent . click ( ui . editCloudGroupIcon . get ( groups [ 0 ] ) ) ;
2023-02-20 08:47:50 +01:00
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' ) ;
2021-08-26 16:40:27 +03:00
await fn ( ) ;
} ) ;
}
testCase ( 'rename both lotex namespace and group' , async ( ) = > {
// make changes to form
2022-04-21 13:15:21 +01:00
await userEvent . clear ( ui . editGroupModal . namespaceInput . get ( ) ) ;
await userEvent . type ( ui . editGroupModal . namespaceInput . get ( ) , 'super namespace' ) ;
2021-08-26 16:40:27 +03:00
2022-04-21 13:15:21 +01:00
await userEvent . clear ( ui . editGroupModal . ruleGroupInput . get ( ) ) ;
await userEvent . type ( ui . editGroupModal . ruleGroupInput . get ( ) , 'super group' ) ;
2021-08-26 16:40:27 +03:00
2024-04-04 16:24:35 +02:00
await userEvent . clear ( ui . editGroupModal . intervalInput . get ( ) ) ;
2022-04-21 13:15:21 +01:00
await userEvent . type ( ui . editGroupModal . intervalInput . get ( ) , '5m' ) ;
2021-08-26 16:40:27 +03:00
// submit, check that appropriate calls were made
2022-04-21 13:15:21 +01:00
await userEvent . click ( ui . editGroupModal . saveButton . get ( ) ) ;
2021-08-26 16:40:27 +03:00
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 ) ;
2022-04-04 19:30:17 +02:00
expect ( mocks . api . setRulerRuleGroup ) . toHaveBeenNthCalledWith (
1 ,
{ dataSourceName : testDatasources.prom.name , apiVersion : 'legacy' } ,
'super namespace' ,
{
. . . someRulerRules [ 'namespace1' ] [ 0 ] ,
name : 'super group' ,
interval : '5m' ,
}
) ;
2021-08-26 16:40:27 +03:00
expect ( mocks . api . setRulerRuleGroup ) . toHaveBeenNthCalledWith (
2 ,
2022-04-04 19:30:17 +02:00
{ dataSourceName : testDatasources.prom.name , apiVersion : 'legacy' } ,
2021-08-26 16:40:27 +03:00
'super namespace' ,
someRulerRules [ 'namespace1' ] [ 1 ]
) ;
2022-04-04 19:30:17 +02:00
expect ( mocks . api . deleteNamespace ) . toHaveBeenLastCalledWith (
{ dataSourceName : testDatasources.prom.name , apiVersion : 'legacy' } ,
'namespace1'
) ;
2021-08-26 16:40:27 +03:00
} ) ;
testCase ( 'rename just the lotex group' , async ( ) = > {
// make changes to form
2023-02-20 08:47:50 +01:00
await userEvent . clear ( ui . editGroupModal . ruleGroupInput . get ( ) ) ;
await userEvent . type ( ui . editGroupModal . ruleGroupInput . get ( ) , 'super group' ) ;
2024-04-04 16:24:35 +02:00
await userEvent . clear ( ui . editGroupModal . intervalInput . get ( ) ) ;
2023-07-18 10:56:02 -03:00
await userEvent . type ( ui . editGroupModal . intervalInput . get ( ) , '5m' ) ;
2021-08-26 16:40:27 +03:00
// submit, check that appropriate calls were made
2022-04-21 13:15:21 +01:00
await userEvent . click ( ui . editGroupModal . saveButton . get ( ) ) ;
2021-08-26 16:40:27 +03:00
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 ) ;
2022-04-04 19:30:17 +02:00
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'
) ;
2021-08-26 16:40:27 +03:00
} ) ;
testCase ( 'edit lotex group eval interval, no renaming' , async ( ) = > {
// make changes to form
2024-04-04 16:24:35 +02:00
await userEvent . clear ( ui . editGroupModal . intervalInput . get ( ) ) ;
2022-04-21 13:15:21 +01:00
await userEvent . type ( ui . editGroupModal . intervalInput . get ( ) , '5m' ) ;
2021-08-26 16:40:27 +03:00
// submit, check that appropriate calls were made
2022-04-21 13:15:21 +01:00
await userEvent . click ( ui . editGroupModal . saveButton . get ( ) ) ;
2021-08-26 16:40:27 +03:00
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 ) ;
2022-04-04 19:30:17 +02:00
expect ( mocks . api . setRulerRuleGroup ) . toHaveBeenNthCalledWith (
1 ,
{ dataSourceName : testDatasources.prom.name , apiVersion : 'legacy' } ,
'namespace1' ,
{
. . . someRulerRules [ 'namespace1' ] [ 0 ] ,
interval : '5m' ,
}
) ;
2021-08-26 16:40:27 +03:00
} ) ;
2021-07-26 12:05:49 -07:00
} ) ;
2022-04-26 15:57:00 +02:00
describe ( 'RBAC Enabled' , ( ) = > {
2023-01-30 11:13:08 +01:00
describe ( 'Export button' , ( ) = > {
2023-10-12 19:17:32 +02:00
it ( 'Export button should be visible when the user has alert read permissions' , async ( ) = > {
2023-11-28 10:48:42 +01:00
grantUserPermissions ( [ AccessControlAction . AlertingRuleRead ] ) ;
2023-01-30 11:13:08 +01:00
mocks . getAllDataSourcesMock . mockReturnValue ( [ ] ) ;
setDataSourceSrv ( new MockDataSourceSrv ( { } ) ) ;
2023-10-12 19:17:32 +02:00
mocks . api . fetchRules . mockResolvedValue ( [
mockPromRuleNamespace ( {
name : 'foofolder' ,
dataSourceName : GRAFANA_RULES_SOURCE_NAME ,
groups : [
mockPromRuleGroup ( {
name : 'grafana-group' ,
rules : [
mockPromAlertingRule ( {
query : '[]' ,
} ) ,
] ,
} ) ,
] ,
} ) ,
] ) ;
2023-08-08 12:29:34 -04:00
mocks . api . fetchRulerRules . mockResolvedValue ( { } ) ;
renderRuleList ( ) ;
2024-01-26 14:56:00 +01:00
await waitFor ( ( ) = > expect ( mocks . api . fetchRules ) . toHaveBeenCalledTimes ( 1 ) ) ;
2023-08-08 12:29:34 -04:00
expect ( ui . exportButton . get ( ) ) . toBeInTheDocument ( ) ;
} ) ;
2023-01-30 11:13:08 +01:00
} ) ;
2022-04-26 15:57:00 +02:00
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 } ) ) ;
2022-05-18 10:45:26 +02:00
mocks . api . discoverFeatures . mockResolvedValue ( {
2022-10-24 14:53:11 -05:00
application : PromApplication.Cortex ,
2022-04-26 15:57:00 +02:00
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 } ) ) ;
2022-05-18 10:45:26 +02:00
mocks . api . discoverFeatures . mockResolvedValue ( {
2022-10-24 14:53:11 -05:00
application : PromApplication.Cortex ,
2022-04-26 15:57:00 +02:00
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 ( ) ;
} ) ;
} ) ;
} ) ;
2022-10-03 11:00:19 -03:00
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 ) ) ;
2023-05-31 10:56:54 -03:00
const button = screen . getByText ( 'New alert rule' ) ;
2022-10-03 11:00:19 -03:00
button . addEventListener ( 'click' , ( event ) = > event . preventDefault ( ) , false ) ;
expect ( button ) . toBeEnabled ( ) ;
await userEvent . click ( button ) ;
2023-10-25 16:47:32 +02:00
expect ( analytics . logInfo ) . toHaveBeenCalledWith ( analytics . LogMessages . alertRuleFromScratch ) ;
2022-10-03 11:00:19 -03:00
} ) ;
} ) ;
2021-04-07 08:42:43 +03:00
} ) ;