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/hooks/useExternalAMSelector.test.tsx

274 lines
8.1 KiB

import { renderHook, waitFor } from '@testing-library/react';
import { setupServer } from 'msw/node';
import React from 'react';
import { Provider } from 'react-redux';
import 'whatwg-fetch';
import { DataSourceJsonData, DataSourceSettings } from '@grafana/data';
import { config, setBackendSrv } from '@grafana/runtime';
import { backendSrv } from 'app/core/services/backend_srv';
import { AlertManagerDataSourceJsonData } from 'app/plugins/datasource/alertmanager/types';
import { mockDataSource, mockDataSourcesStore, mockStore } from '../mocks';
import { mockAlertmanagersResponse } from '../mocks/alertmanagerApi';
import { useExternalDataSourceAlertmanagers } from './useExternalAmSelector';
const server = setupServer();
beforeAll(() => {
setBackendSrv(backendSrv);
server.listen({ onUnhandledRequest: 'error' });
});
beforeEach(() => {
server.resetHandlers();
});
afterAll(() => {
server.close();
});
describe('useExternalDataSourceAlertmanagers', () => {
it('Should merge data sources information from config and api responses', async () => {
// Arrange
const { dsSettings, dsInstanceSettings } = setupAlertmanagerDataSource({ url: 'http://grafana.com' });
config.datasources = {
'External Alertmanager': dsInstanceSettings,
};
const store = mockDataSourcesStore({
dataSources: [dsSettings],
});
mockAlertmanagersResponse(server, { data: { activeAlertManagers: [], droppedAlertManagers: [] } });
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
// Act
const { result } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper });
await waitFor(() => {
// Assert
const { current } = result;
expect(current).toHaveLength(1);
expect(current[0].dataSource.uid).toBe('1');
expect(current[0].url).toBe('http://grafana.com');
});
});
it('Should have active state if available in the activeAlertManagers', async () => {
// Arrange
const { dsSettings, dsInstanceSettings } = setupAlertmanagerDataSource({ url: 'http://grafana.com' });
config.datasources = {
'External Alertmanager': dsInstanceSettings,
};
const store = mockStore((state) => {
state.dataSources.dataSources = [dsSettings];
});
mockAlertmanagersResponse(server, {
data: {
activeAlertManagers: [{ url: 'http://grafana.com/api/v2/alerts' }],
droppedAlertManagers: [],
},
});
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
// Act
const { result } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper });
await waitFor(() => {
// Assert
const { current } = result;
expect(current).toHaveLength(1);
expect(current[0].status).toBe('active');
expect(current[0].statusInconclusive).toBe(false);
});
});
it('Should have dropped state if available in the droppedAlertManagers', async () => {
// Arrange
const { dsSettings, dsInstanceSettings } = setupAlertmanagerDataSource({ url: 'http://grafana.com' });
config.datasources = {
'External Alertmanager': dsInstanceSettings,
};
const store = mockStore((state) => {
state.dataSources.dataSources = [dsSettings];
});
mockAlertmanagersResponse(server, {
data: {
activeAlertManagers: [],
droppedAlertManagers: [{ url: 'http://grafana.com/api/v2/alerts' }],
},
});
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
// Act
const { result } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper });
await waitFor(() => {
// Assert
const { current } = result;
expect(current).toHaveLength(1);
expect(current[0].status).toBe('dropped');
expect(current[0].statusInconclusive).toBe(false);
});
});
it('Should have pending state if not available neither in dropped nor in active alertManagers', async () => {
// Arrange
const { dsSettings, dsInstanceSettings } = setupAlertmanagerDataSource();
config.datasources = {
'External Alertmanager': dsInstanceSettings,
};
const store = mockStore((state) => {
state.dataSources.dataSources = [dsSettings];
});
mockAlertmanagersResponse(server, {
data: {
activeAlertManagers: [],
droppedAlertManagers: [],
},
});
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
// Act
const { result } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper });
await waitFor(() => {
// Assert
const { current } = result;
expect(current).toHaveLength(1);
expect(current[0].status).toBe('pending');
expect(current[0].statusInconclusive).toBe(false);
});
});
it('Should match Alertmanager url when datasource url does not have protocol specified', async () => {
// Arrange
const { dsSettings, dsInstanceSettings } = setupAlertmanagerDataSource({ url: 'localhost:9093' });
config.datasources = {
'External Alertmanager': dsInstanceSettings,
};
const store = mockStore((state) => {
state.dataSources.dataSources = [dsSettings];
});
mockAlertmanagersResponse(server, {
data: {
activeAlertManagers: [{ url: 'http://localhost:9093/api/v2/alerts' }],
droppedAlertManagers: [],
},
});
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
// Act
const { result } = renderHook(() => useExternalDataSourceAlertmanagers(), { wrapper });
await waitFor(() => {
// Assert
const { current } = result;
expect(current).toHaveLength(1);
expect(current[0].status).toBe('active');
expect(current[0].url).toBe('localhost:9093');
});
});
it('Should have inconclusive state when there are many Alertmanagers of the same URL', async () => {
// Arrange
mockAlertmanagersResponse(server, {
data: {
activeAlertManagers: [{ url: 'http://grafana.com/api/v2/alerts' }, { url: 'http://grafana.com/api/v2/alerts' }],
droppedAlertManagers: [],
},
});
const { dsSettings, dsInstanceSettings } = setupAlertmanagerDataSource({ url: 'http://grafana.com' });
config.datasources = {
'External Alertmanager': dsInstanceSettings,
};
const store = mockStore((state) => {
state.dataSources.dataSources = [dsSettings];
});
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
// Act
const { result } = renderHook(() => useExternalDataSourceAlertmanagers(), {
wrapper,
});
await waitFor(() => {
// Assert
expect(result.current).toHaveLength(1);
expect(result.current[0].status).toBe('active');
expect(result.current[0].statusInconclusive).toBe(true);
});
});
});
function setupAlertmanagerDataSource(partialDsSettings?: Partial<DataSourceSettings<AlertManagerDataSourceJsonData>>) {
const dsCommonConfig = {
uid: '1',
name: 'External Alertmanager',
type: 'alertmanager',
jsonData: { handleGrafanaManagedAlerts: true } as AlertManagerDataSourceJsonData,
};
const dsInstanceSettings = mockDataSource(dsCommonConfig);
const dsSettings = mockApiDataSource({
...dsCommonConfig,
...partialDsSettings,
});
return { dsSettings, dsInstanceSettings };
}
function mockApiDataSource(partial: Partial<DataSourceSettings<DataSourceJsonData, {}>> = {}) {
const dsSettings: DataSourceSettings<DataSourceJsonData, {}> = {
uid: '1',
id: 1,
name: '',
url: '',
type: '',
access: '',
orgId: 1,
typeLogoUrl: '',
typeName: '',
user: '',
database: '',
basicAuth: false,
isDefault: false,
basicAuthUser: '',
jsonData: { handleGrafanaManagedAlerts: true } as AlertManagerDataSourceJsonData,
secureJsonFields: {},
readOnly: false,
withCredentials: false,
...partial,
};
return dsSettings;
}