2022-04-22 14:33:13 +01:00
import { SerializedError } from '@reduxjs/toolkit' ;
2021-04-07 08:42:43 +03:00
import { render , waitFor } from '@testing-library/react' ;
2022-04-22 14:33:13 +01:00
import userEvent from '@testing-library/user-event' ;
import React from 'react' ;
2021-04-07 08:42:43 +03:00
import { Provider } from 'react-redux' ;
2022-04-22 14:33:13 +01:00
import { Router } from 'react-router-dom' ;
2021-08-26 16:40:27 +03:00
import { byLabelText , byRole , byTestId , byText } from 'testing-library-selector' ;
2022-04-22 14:33:13 +01:00
import { locationService , setDataSourceSrv } from '@grafana/runtime' ;
2022-05-23 09:58:20 -04:00
import { contextSrv } from 'app/core/services/context_srv' ;
2022-04-22 14:33:13 +01:00
import { configureStore } from 'app/store/configureStore' ;
2022-04-26 15:57:00 +02:00
import { AccessControlAction } from 'app/types' ;
2022-04-22 14:33:13 +01:00
import { PromAlertingRuleState , PromApplication } from 'app/types/unified-alerting-dto' ;
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' ;
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 {
2022-05-16 03:45:41 -07:00
disableRBAC ,
2022-04-26 15:57:00 +02:00
enableRBAC ,
grantUserPermissions ,
2021-04-07 08:42:43 +03:00
mockDataSource ,
2022-04-26 15:57:00 +02:00
MockDataSourceSrv ,
2021-04-07 08:42:43 +03:00
mockPromAlert ,
mockPromAlertingRule ,
mockPromRecordingRule ,
mockPromRuleGroup ,
mockPromRuleNamespace ,
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' ;
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' ) ;
jest . mock ( 'app/core/core' , ( ) = > ( {
appEvents : {
subscribe : ( ) = > {
return { unsubscribe : ( ) = > { } } ;
} ,
emit : ( ) = > { } ,
} ,
} ) ) ;
2021-04-07 08:42:43 +03:00
2022-08-01 15:01:14 +02:00
jest . spyOn ( config , 'getAllDataSources' ) ;
2021-04-07 08:42:43 +03:00
const mocks = {
2022-08-01 15:01:14 +02:00
getAllDataSourcesMock : jest.mocked ( config . getAllDataSources ) ,
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 ) ,
2021-04-07 08:42:43 +03:00
} ,
} ;
const renderRuleList = ( ) = > {
const store = configureStore ( ) ;
2021-08-26 16:40:27 +03:00
locationService . push ( '/' ) ;
2021-04-07 08:42:43 +03:00
return render (
< Provider store = { store } >
2021-04-27 16:28:53 +03:00
< Router history = { locationService . getHistory ( ) } >
< RuleList / >
< / Router >
2021-04-07 08:42:43 +03:00
< / Provider >
) ;
} ;
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' ) ,
cloudRulesSourceErrors : byTestId ( 'cloud-rulessource-errors' ) ,
groupCollapseToggle : byTestId ( 'group-collapse-toggle' ) ,
2021-06-23 09:27:47 +03:00
ruleCollapseToggle : byTestId ( 'collapse-toggle' ) ,
2021-04-07 08:42:43 +03:00
rulesTable : byTestId ( 'rules-table' ) ,
2021-06-23 09:27:47 +03:00
ruleRow : byTestId ( 'row' ) ,
expandedContent : byTestId ( 'expanded-content' ) ,
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' ) ,
2022-04-26 15:57:00 +02:00
newRuleButton : byRole ( 'link' , { name : 'New alert rule' } ) ,
2021-08-26 16:40:27 +03:00
editGroupModal : {
namespaceInput : byLabelText ( 'Namespace' ) ,
ruleGroupInput : byLabelText ( 'Rule group' ) ,
intervalInput : byLabelText ( 'Rule group evaluation interval' ) ,
saveButton : byRole ( 'button' , { name : /Save changes/ } ) ,
} ,
2021-04-07 08:42:43 +03:00
} ;
describe ( 'RuleList' , ( ) = > {
2022-05-23 09:58:20 -04:00
beforeEach ( ( ) = > {
contextSrv . isEditor = true ;
} ) ;
2021-04-15 04:53:40 -07:00
afterEach ( ( ) = > {
jest . resetAllMocks ( ) ;
setDataSourceSrv ( undefined as any ) ;
} ) ;
2021-04-07 08:42:43 +03:00
it ( 'load & show rule groups from multiple cloud data sources' , async ( ) = > {
2022-05-16 03:45:41 -07:00
disableRBAC ( ) ;
2021-04-07 08:42:43 +03:00
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 } ` ) ) ;
} ) ;
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 ( {
application : PromApplication.Lotex ,
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 ) ;
expect ( groups [ 0 ] ) . toHaveTextContent ( '1 rule' ) ;
expect ( groups [ 1 ] ) . toHaveTextContent ( '4 rules: 1 firing, 1 pending' ) ;
// 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 ] ) ;
2021-04-07 08:42:43 +03:00
expect ( ruleDetails ) . toHaveTextContent ( 'Labelsseverity=warningfoo=bar' ) ;
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 ) ;
2022-09-05 16:36:52 +02:00
expect ( instanceRows ! [ 0 ] ) . toHaveTextContent ( 'Firingfoo=barseverity=warning2021-03-18 08:47:05' ) ;
expect ( instanceRows ! [ 1 ] ) . toHaveTextContent ( 'Firingfoo=bazseverity=error2021-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
2021-06-23 09:27:47 +03:00
const alertDetails = byTestId ( 'expanded-content' ) . 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 ] ) ) ;
2021-06-23 09:27:47 +03:00
expect ( byTestId ( 'expanded-content' ) . 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 ( {
application : PromApplication.Lotex ,
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 ( ) ;
const groups = await ui . ruleGroup . findAll ( ) ;
expect ( groups ) . toHaveLength ( 2 ) ;
const filterInput = ui . rulesFilterInput . get ( ) ;
2022-04-21 13:15:21 +01:00
await userEvent . type ( filterInput , '{{foo="bar"}' ) ;
2021-07-26 12:05:49 -07:00
// Input is debounced so wait for it to be visible
2021-08-26 16:40:27 +03:00
await waitFor ( ( ) = > expect ( filterInput ) . toHaveValue ( '{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 ] ) ;
expect ( ruleDetails ) . toHaveTextContent ( 'Labelsseverity=warningfoo=bar' ) ;
// Check for different label matchers
2022-04-21 13:15:21 +01:00
await userEvent . clear ( filterInput ) ;
await userEvent . type ( filterInput , '{{foo!="bar",foo!="baz"}' ) ;
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 ) ;
await userEvent . type ( filterInput , '{{foo=~"b.+"}' ) ;
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 ) ;
await userEvent . type ( filterInput , '{{region="US"}' ) ;
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' ) ) ;
} ) ;
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 ( {
application : PromApplication.Lotex ,
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 ( '' ) ;
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 ] ) ) ;
2021-08-26 16:40:27 +03:00
expect ( ui . editGroupModal . namespaceInput . get ( ) ) . toHaveValue ( 'namespace1' ) ;
expect ( ui . editGroupModal . ruleGroupInput . get ( ) ) . toHaveValue ( 'group1' ) ;
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
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
2022-04-21 13:15:21 +01:00
await userEvent . clear ( ui . editGroupModal . ruleGroupInput . get ( ) ) ;
await userEvent . type ( ui . editGroupModal . ruleGroupInput . get ( ) , 'super group' ) ;
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
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' , ( ) = > {
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 ( ) = > {
enableRBAC ( ) ;
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 ( ) = > {
enableRBAC ( ) ;
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 ( ) = > {
enableRBAC ( ) ;
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 ( {
application : PromApplication.Lotex ,
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 ( ) = > {
enableRBAC ( ) ;
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 ( {
application : PromApplication.Lotex ,
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 ( ) ;
} ) ;
} ) ;
} ) ;
2021-04-07 08:42:43 +03:00
} ) ;