123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- import { render, waitFor, fireEvent } from '@testing-library/react';
- import userEvent from '@testing-library/user-event';
- import React from 'react';
- import { Provider } from 'react-redux';
- import { Router } from 'react-router-dom';
- import { byRole, byTestId, byText } from 'testing-library-selector';
- import { locationService, setDataSourceSrv } from '@grafana/runtime';
- import { AlertManagerCortexConfig, MuteTimeInterval } from 'app/plugins/datasource/alertmanager/types';
- import { configureStore } from 'app/store/configureStore';
- import MuteTimings from './MuteTimings';
- import { fetchAlertManagerConfig, updateAlertManagerConfig } from './api/alertmanager';
- import { disableRBAC, mockDataSource, MockDataSourceSrv } from './mocks';
- import { DataSourceType } from './utils/datasource';
- jest.mock('./api/alertmanager');
- const mocks = {
- api: {
- fetchAlertManagerConfig: jest.mocked(fetchAlertManagerConfig),
- updateAlertManagerConfig: jest.mocked(updateAlertManagerConfig),
- },
- };
- const renderMuteTimings = (location = '/alerting/routes/mute-timing/new') => {
- const store = configureStore();
- locationService.push(location);
- return render(
- <Provider store={store}>
- <Router history={locationService.getHistory()}>
- <MuteTimings />
- </Router>
- </Provider>
- );
- };
- const dataSources = {
- am: mockDataSource({
- name: 'Alertmanager',
- type: DataSourceType.Alertmanager,
- }),
- };
- const ui = {
- form: byTestId('mute-timing-form'),
- nameField: byTestId('mute-timing-name'),
- startsAt: byTestId('mute-timing-starts-at'),
- endsAt: byTestId('mute-timing-ends-at'),
- addTimeRange: byRole('button', { name: /add another time range/i }),
- weekdays: byTestId('mute-timing-weekdays'),
- days: byTestId('mute-timing-days'),
- months: byTestId('mute-timing-months'),
- years: byTestId('mute-timing-years'),
- addInterval: byRole('button', { name: /add another time interval/i }),
- submitButton: byText(/submit/i),
- };
- const muteTimeInterval: MuteTimeInterval = {
- name: 'default-mute',
- time_intervals: [
- {
- times: [
- {
- start_time: '12:00',
- end_time: '24:00',
- },
- ],
- days_of_month: ['15', '-1'],
- months: ['august:december', 'march'],
- },
- ],
- };
- const defaultConfig: AlertManagerCortexConfig = {
- alertmanager_config: {
- receivers: [{ name: 'default' }, { name: 'critical' }],
- route: {
- receiver: 'default',
- group_by: ['alertname'],
- routes: [
- {
- matchers: ['env=prod', 'region!=EU'],
- mute_time_intervals: [muteTimeInterval.name],
- },
- ],
- },
- templates: [],
- mute_time_intervals: [muteTimeInterval],
- },
- template_files: {},
- };
- const resetMocks = () => {
- jest.resetAllMocks();
- mocks.api.fetchAlertManagerConfig.mockImplementation(() => {
- return Promise.resolve({ ...defaultConfig });
- });
- mocks.api.updateAlertManagerConfig.mockImplementation(() => {
- return Promise.resolve();
- });
- };
- describe('Mute timings', () => {
- beforeEach(() => {
- setDataSourceSrv(new MockDataSourceSrv(dataSources));
- resetMocks();
- });
- it('creates a new mute timing', async () => {
- disableRBAC();
- await renderMuteTimings();
- await waitFor(() => expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalled());
- expect(ui.nameField.get()).toBeInTheDocument();
- await userEvent.type(ui.nameField.get(), 'maintenance period');
- await userEvent.type(ui.startsAt.get(), '22:00');
- await userEvent.type(ui.endsAt.get(), '24:00');
- await userEvent.type(ui.days.get(), '-1');
- await userEvent.type(ui.months.get(), 'january, july');
- fireEvent.submit(ui.form.get());
- await waitFor(() => expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalled());
- expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalledWith('grafana', {
- ...defaultConfig,
- alertmanager_config: {
- ...defaultConfig.alertmanager_config,
- mute_time_intervals: [
- muteTimeInterval,
- {
- name: 'maintenance period',
- time_intervals: [
- {
- days_of_month: ['-1'],
- months: ['january', 'july'],
- times: [
- {
- start_time: '22:00',
- end_time: '24:00',
- },
- ],
- },
- ],
- },
- ],
- },
- });
- });
- it('prepoluates the form when editing a mute timing', async () => {
- await renderMuteTimings(
- '/alerting/routes/mute-timing/edit' + `?muteName=${encodeURIComponent(muteTimeInterval.name)}`
- );
- await waitFor(() => expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalled());
- expect(ui.nameField.get()).toBeInTheDocument();
- expect(ui.nameField.get()).toHaveValue(muteTimeInterval.name);
- expect(ui.months.get()).toHaveValue(muteTimeInterval.time_intervals[0].months?.join(', '));
- await userEvent.clear(ui.startsAt.getAll()?.[0]);
- await userEvent.clear(ui.endsAt.getAll()?.[0]);
- await userEvent.clear(ui.weekdays.get());
- await userEvent.clear(ui.days.get());
- await userEvent.clear(ui.months.get());
- await userEvent.clear(ui.years.get());
- await userEvent.type(ui.weekdays.get(), 'monday');
- await userEvent.type(ui.days.get(), '-7:-1');
- await userEvent.type(ui.months.get(), '3, 6, 9, 12');
- await userEvent.type(ui.years.get(), '2021:2024');
- fireEvent.submit(ui.form.get());
- await waitFor(() => expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalled());
- expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalledWith('grafana', {
- alertmanager_config: {
- receivers: [
- {
- name: 'default',
- },
- {
- name: 'critical',
- },
- ],
- route: {
- receiver: 'default',
- group_by: ['alertname'],
- routes: [
- {
- matchers: ['env=prod', 'region!=EU'],
- mute_time_intervals: ['default-mute'],
- },
- ],
- },
- templates: [],
- mute_time_intervals: [
- {
- name: 'default-mute',
- time_intervals: [
- {
- times: [],
- weekdays: ['monday'],
- days_of_month: ['-7:-1'],
- months: ['3', '6', '9', '12'],
- years: ['2021:2024'],
- },
- ],
- },
- ],
- },
- template_files: {},
- });
- });
- it('form is invalid with duplicate mute timing name', async () => {
- await renderMuteTimings();
- await waitFor(() => expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalled());
- await waitFor(() => expect(ui.nameField.get()).toBeInTheDocument());
- await userEvent.type(ui.nameField.get(), 'default-mute');
- await userEvent.type(ui.days.get(), '1');
- await waitFor(() => expect(ui.nameField.get()).toHaveValue('default-mute'));
- fireEvent.submit(ui.form.get());
- // Form state should be invalid and prevent firing of update action
- await waitFor(() => expect(byRole('alert').get()).toBeInTheDocument());
- expect(mocks.api.updateAlertManagerConfig).not.toHaveBeenCalled();
- });
- it('replaces mute timings in routes when the mute timing name is changed', async () => {
- await renderMuteTimings(
- '/alerting/routes/mute-timing/edit' + `?muteName=${encodeURIComponent(muteTimeInterval.name)}`
- );
- await waitFor(() => expect(mocks.api.fetchAlertManagerConfig).toHaveBeenCalled());
- expect(ui.nameField.get()).toBeInTheDocument();
- expect(ui.nameField.get()).toHaveValue(muteTimeInterval.name);
- await userEvent.clear(ui.nameField.get());
- await userEvent.type(ui.nameField.get(), 'Lunch breaks');
- fireEvent.submit(ui.form.get());
- await waitFor(() => expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalled());
- expect(mocks.api.updateAlertManagerConfig).toHaveBeenCalledWith('grafana', {
- alertmanager_config: {
- receivers: [
- {
- name: 'default',
- },
- {
- name: 'critical',
- },
- ],
- route: {
- receiver: 'default',
- group_by: ['alertname'],
- routes: [
- {
- matchers: ['env=prod', 'region!=EU'],
- mute_time_intervals: ['Lunch breaks'],
- },
- ],
- },
- templates: [],
- mute_time_intervals: [
- {
- name: 'Lunch breaks',
- time_intervals: [
- {
- times: [
- {
- start_time: '12:00',
- end_time: '24:00',
- },
- ],
- days_of_month: ['15', '-1'],
- months: ['august:december', 'march'],
- },
- ],
- },
- ],
- },
- template_files: {},
- });
- });
- });
|