Alerting: Fix setting of existing Telegram Chat ID value (#89287)

This commit is contained in:
Tom Ratcliffe 2024-06-18 14:24:23 +01:00 committed by GitHub
parent 890482052a
commit 3badf73b45
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 85 additions and 25 deletions

View File

@ -3,14 +3,13 @@ import { selectOptionInTest } from 'test/helpers/selectOptionInTest';
import { render, screen, waitFor, userEvent } from 'test/test-utils'; import { render, screen, waitFor, userEvent } from 'test/test-utils';
import { import {
EXTERNAL_VANILLA_ALERTMANAGER_UID, PROVISIONED_MIMIR_ALERTMANAGER_UID,
mockDataSources,
setupVanillaAlertmanagerServer, setupVanillaAlertmanagerServer,
} from 'app/features/alerting/unified/components/settings/__mocks__/server'; } from 'app/features/alerting/unified/components/settings/__mocks__/server';
import { setupMswServer } from 'app/features/alerting/unified/mockApi'; import { setupMswServer } from 'app/features/alerting/unified/mockApi';
import { grantUserPermissions, mockDataSource } from 'app/features/alerting/unified/mocks'; import { grantUserPermissions } from 'app/features/alerting/unified/mocks';
import { setupDataSources } from 'app/features/alerting/unified/testSetup/datasources'; import { setupDataSources } from 'app/features/alerting/unified/testSetup/datasources';
import { DataSourceType } from 'app/features/alerting/unified/utils/datasource';
import { AlertManagerDataSourceJsonData, AlertManagerImplementation } from 'app/plugins/datasource/alertmanager/types';
import { AccessControlAction } from 'app/types'; import { AccessControlAction } from 'app/types';
import ContactPoints from './Receivers'; import ContactPoints from './Receivers';
@ -19,15 +18,15 @@ import 'core-js/stable/structured-clone';
const server = setupMswServer(); const server = setupMswServer();
const mockDataSources = { const assertSaveWasSuccessful = async () => {
[EXTERNAL_VANILLA_ALERTMANAGER_UID]: mockDataSource<AlertManagerDataSourceJsonData>({ // TODO: Have a better way to assert that the contact point was saved. This is instead asserting on some
uid: EXTERNAL_VANILLA_ALERTMANAGER_UID, // text that's present on the list page, as there's a lot of overlap in text between the form and the list page
name: EXTERNAL_VANILLA_ALERTMANAGER_UID, return waitFor(() => expect(screen.getByText(/search by name or type/i)).toBeInTheDocument(), { timeout: 2000 });
type: DataSourceType.Alertmanager, };
jsonData: {
implementation: AlertManagerImplementation.prometheus, const saveContactPoint = async () => {
}, const user = userEvent.setup();
}), return user.click(await screen.findByRole('button', { name: /save contact point/i }));
}; };
beforeEach(() => { beforeEach(() => {
@ -37,17 +36,22 @@ beforeEach(() => {
AccessControlAction.AlertingNotificationsExternalRead, AccessControlAction.AlertingNotificationsExternalRead,
AccessControlAction.AlertingNotificationsExternalWrite, AccessControlAction.AlertingNotificationsExternalWrite,
]); ]);
setupVanillaAlertmanagerServer(server);
setupDataSources(mockDataSources[PROVISIONED_MIMIR_ALERTMANAGER_UID]);
}); });
it('can save a contact point with a select dropdown', async () => { it('can save a contact point with a select dropdown', async () => {
setupVanillaAlertmanagerServer(server);
setupDataSources(mockDataSources[EXTERNAL_VANILLA_ALERTMANAGER_UID]);
const user = userEvent.setup(); const user = userEvent.setup();
render(<ContactPoints />, { render(<ContactPoints />, {
historyOptions: { historyOptions: {
initialEntries: [`/alerting/notifications/receivers/new?alertmanager=${EXTERNAL_VANILLA_ALERTMANAGER_UID}`], initialEntries: [
{
pathname: `/alerting/notifications/receivers/new`,
search: `?alertmanager=${PROVISIONED_MIMIR_ALERTMANAGER_UID}`,
},
],
}, },
}); });
@ -66,9 +70,28 @@ it('can save a contact point with a select dropdown', async () => {
await user.type(botToken, 'sometoken'); await user.type(botToken, 'sometoken');
await user.type(chatId, '-123'); await user.type(chatId, '-123');
await user.click(await screen.findByRole('button', { name: /save contact point/i })); await saveContactPoint();
// TODO: Have a better way to assert that the contact point was saved. This is instead asserting on some await assertSaveWasSuccessful();
// text that's present on the list page, as there's a lot of overlap in text between the form and the list page });
await waitFor(() => expect(screen.getByText(/search by name or type/i)).toBeInTheDocument(), { timeout: 2000 });
it('can save existing Telegram contact point', async () => {
render(<ContactPoints />, {
historyOptions: {
initialEntries: [
{
pathname: `/alerting/notifications/receivers/Telegram/edit`,
search: `?alertmanager=${PROVISIONED_MIMIR_ALERTMANAGER_UID}`,
},
],
},
});
// Here, we're implicitly testing that our parsing of an existing Telegram integration works correctly
// Our mock server will reject a request if we've sent the Chat ID as `0`,
// so opening and trying to save an existing Telegram integration should
// trigger this error if it regresses
await saveContactPoint();
await assertSaveWasSuccessful();
}); });

View File

@ -0,0 +1,26 @@
{
"template_files": {},
"alertmanager_config": {
"global": {},
"receivers": [
{
"name": "default"
},
{
"name": "Telegram",
"telegram_configs": [
{
"bot_token": "abc",
"chat_id": -123,
"disable_notifications": false,
"parse_mode": "MarkdownV2",
"send_resolved": true
}
]
}
],
"route": {
"receiver": "default"
}
}
}

View File

@ -16,6 +16,7 @@ import { DataSourceType } from '../../../utils/datasource';
import internalAlertmanagerConfig from './api/alertmanager/grafana/config/api/v1/alerts.json'; import internalAlertmanagerConfig from './api/alertmanager/grafana/config/api/v1/alerts.json';
import history from './api/alertmanager/grafana/config/history.json'; import history from './api/alertmanager/grafana/config/history.json';
import cloudAlertmanagerConfig from './api/alertmanager/provisioned/config/api/v1/alerts.json';
import vanillaAlertmanagerConfig from './api/alertmanager/vanilla prometheus/api/v2/status.json'; import vanillaAlertmanagerConfig from './api/alertmanager/vanilla prometheus/api/v2/status.json';
import datasources from './api/datasources.json'; import datasources from './api/datasources.json';
import admin_config from './api/v1/ngalert/admin_config.json'; import admin_config from './api/v1/ngalert/admin_config.json';
@ -37,7 +38,7 @@ const mocks = {
getAllDataSources: jest.mocked(config.getAllDataSources), getAllDataSources: jest.mocked(config.getAllDataSources),
}; };
const mockDataSources = { export const mockDataSources = {
[EXTERNAL_VANILLA_ALERTMANAGER_UID]: mockDataSource<AlertManagerDataSourceJsonData>({ [EXTERNAL_VANILLA_ALERTMANAGER_UID]: mockDataSource<AlertManagerDataSourceJsonData>({
uid: EXTERNAL_VANILLA_ALERTMANAGER_UID, uid: EXTERNAL_VANILLA_ALERTMANAGER_UID,
name: EXTERNAL_VANILLA_ALERTMANAGER_UID, name: EXTERNAL_VANILLA_ALERTMANAGER_UID,
@ -95,7 +96,12 @@ const createAlertmanagerConfigurationHandlers = () => {
}; };
return [ return [
http.get(`/api/alertmanager/:name/config/api/v1/alerts`, () => HttpResponse.json(internalAlertmanagerConfig)), http.get<{ name: string }>(`/api/alertmanager/:name/config/api/v1/alerts`, ({ params }) => {
if (params.name === 'grafana') {
return HttpResponse.json(internalAlertmanagerConfig);
}
return HttpResponse.json(cloudAlertmanagerConfig);
}),
http.post<never, AlertManagerCortexConfig>(`/api/alertmanager/:name/config/api/v1/alerts`, async ({ request }) => { http.post<never, AlertManagerCortexConfig>(`/api/alertmanager/:name/config/api/v1/alerts`, async ({ request }) => {
await delay(1000); // simulate some time await delay(1000); // simulate some time
@ -108,7 +114,12 @@ const createAlertmanagerConfigurationHandlers = () => {
return false; return false;
} }
return (receiver.telegram_configs || []).some((config) => typeof config.parse_mode === 'object'); const invalidParseMode = (receiver.telegram_configs || []).some(
(config) => typeof config.parse_mode === 'object'
);
const invalidChatId = (receiver.telegram_configs || []).some((config) => Number(config.chat_id) >= 0);
return invalidParseMode || invalidChatId;
}); });
if (invalidConfig) { if (invalidConfig) {

View File

@ -410,7 +410,7 @@ export const cloudNotifierTypes: Array<NotifierDTO<CloudNotifierType>> = [
}), }),
option('chat_id', 'Chat ID', 'ID of the chat where to send the messages', { option('chat_id', 'Chat ID', 'ID of the chat where to send the messages', {
required: true, required: true,
setValueAs: (value) => (typeof value === 'string' ? parseInt(value, 10) : 0), setValueAs: (value) => (typeof value === 'string' ? parseInt(value, 10) : value),
}), }),
option('message', 'Message', 'Message template', { option('message', 'Message', 'Message template', {
placeholder: '{{ template "webex.default.message" .}}', placeholder: '{{ template "webex.default.message" .}}',