From 5be8a9b3c3b5ee5b7b4e2d5b1a69c37af4ba5716 Mon Sep 17 00:00:00 2001 From: Tom Ratcliffe Date: Thu, 12 Dec 2024 09:50:36 +0000 Subject: [PATCH] Alerting/chore: Deprecate MockDataSourceSrv and remove from Alerting tests (#97267) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Mark MockDataSourceSrv as deprecated * Add `module` into necessary existing mock datasources * Remove config mock * Update helper method for test datasources to more accurately reflect real behaviour * Update alerting/unified tests to remove mock datasource srv * Lint fix * Remove some unused re-exports * Make mock mimir use correct module Ⓜ️ * Add necessary handlers for mimir query editor responses * Lint fix * Add implementation to mock mimir data source --- .betterer.results | 8 -- .../alerting/unified/AlertGroups.test.tsx | 12 +-- .../alerting/unified/CloneRuleEditor.test.tsx | 4 +- .../unified/PanelAlertTabContent.test.tsx | 78 ++++++++++--------- .../alerting/unified/RuleList.test.tsx | 51 ++---------- .../alerting/unified/Settings.test.tsx | 7 +- .../components/rules/RulesFilter.test.tsx | 5 +- .../settings/AlertmanagerConfig.test.tsx | 3 + .../components/settings/__mocks__/server.ts | 58 ++++++-------- .../unified/hooks/useFilteredRules.test.ts | 5 +- public/app/features/alerting/unified/mocks.ts | 2 +- .../unified/mocks/server/configure.ts | 3 +- .../mocks/server/handlers/datasources.ts | 25 +++++- .../unified/state/AlertingQueryRunner.test.ts | 20 +++-- .../alerting/unified/testSetup/datasources.ts | 14 +++- 15 files changed, 132 insertions(+), 163 deletions(-) diff --git a/.betterer.results b/.betterer.results index 510154a2371..0dcf32bb34a 100644 --- a/.betterer.results +++ b/.betterer.results @@ -1663,14 +1663,6 @@ exports[`better eslint`] = { [0, 0, 0, "No untranslated strings. Wrap text with ", "5"], [0, 0, 0, "No untranslated strings. Wrap text with ", "6"] ], - "public/app/features/alerting/unified/components/settings/__mocks__/server.ts:5381": [ - [0, 0, 0, "Do not re-export imported variable (\`DataSourcesResponse\`)", "0"], - [0, 0, 0, "Do not re-export imported variable (\`AdminConfigResponse\`)", "1"], - [0, 0, 0, "Do not re-export imported variable (\`AlertmanagersResponse\`)", "2"], - [0, 0, 0, "Do not re-export imported variable (\`InternalAlertmanagerConfiguration\`)", "3"], - [0, 0, 0, "Do not re-export imported variable (\`VanillaAlertmanagerConfiguration\`)", "4"], - [0, 0, 0, "Do not re-export imported variable (\`alertmanagerConfigurationHistory\`)", "5"] - ], "public/app/features/alerting/unified/components/silences/MatchersField.tsx:5381": [ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"], [0, 0, 0, "No untranslated strings. Wrap text with ", "1"] diff --git a/public/app/features/alerting/unified/AlertGroups.test.tsx b/public/app/features/alerting/unified/AlertGroups.test.tsx index 6b4f3ca1894..a39b0348f15 100644 --- a/public/app/features/alerting/unified/AlertGroups.test.tsx +++ b/public/app/features/alerting/unified/AlertGroups.test.tsx @@ -2,18 +2,12 @@ import { render, waitFor, waitForElementToBeRemoved } from 'test/test-utils'; import { byRole, byTestId, byText } from 'testing-library-selector'; import { selectors } from '@grafana/e2e-selectors'; -import { setDataSourceSrv } from '@grafana/runtime'; +import { setupDataSources } from 'app/features/alerting/unified/testSetup/datasources'; import { AccessControlAction } from 'app/types'; import AlertGroups from './AlertGroups'; import { fetchAlertGroups } from './api/alertmanager'; -import { - MockDataSourceSrv, - grantUserPermissions, - mockAlertGroup, - mockAlertmanagerAlert, - mockDataSource, -} from './mocks'; +import { grantUserPermissions, mockAlertGroup, mockAlertmanagerAlert, mockDataSource } from './mocks'; import { AlertmanagerProvider } from './state/AlertmanagerContext'; import { DataSourceType } from './utils/datasource'; @@ -63,7 +57,7 @@ describe('AlertGroups', () => { }); beforeEach(() => { - setDataSourceSrv(new MockDataSourceSrv(dataSources)); + setupDataSources(dataSources.am); }); afterEach(() => { diff --git a/public/app/features/alerting/unified/CloneRuleEditor.test.tsx b/public/app/features/alerting/unified/CloneRuleEditor.test.tsx index 27e72824154..3eff21b9b26 100644 --- a/public/app/features/alerting/unified/CloneRuleEditor.test.tsx +++ b/public/app/features/alerting/unified/CloneRuleEditor.test.tsx @@ -3,7 +3,6 @@ import { FormProvider, useForm } from 'react-hook-form'; import { getWrapper, render, waitFor, waitForElementToBeRemoved, within } from 'test/test-utils'; import { byRole, byTestId, byText } from 'testing-library-selector'; -import { setDataSourceSrv } from '@grafana/runtime'; import { RuleWithLocation } from 'app/types/unified-alerting'; import { AccessControlAction } from '../../../types'; @@ -18,7 +17,6 @@ import { CloneRuleEditor, cloneRuleDefinition } from './CloneRuleEditor'; import { ExpressionEditorProps } from './components/rule-editor/ExpressionEditor'; import { mockFeatureDiscoveryApi, setupMswServer } from './mockApi'; import { - MockDataSourceSrv, grantUserPermissions, mockDataSource, mockRulerAlertingRule, @@ -74,7 +72,7 @@ describe('CloneRuleEditor', function () { describe('Grafana-managed rules', function () { it('should populate form values from the existing alert rule', async function () { - setDataSourceSrv(new MockDataSourceSrv({})); + setupDataSources(); render( , diff --git a/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx b/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx index 4d87a26183b..488719b2e65 100644 --- a/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx +++ b/public/app/features/alerting/unified/PanelAlertTabContent.test.tsx @@ -1,13 +1,11 @@ import { render } from 'test/test-utils'; import { byTestId, byText } from 'testing-library-selector'; -import { DataSourceApi } from '@grafana/data'; -import { PromOptions, PrometheusDatasource } from '@grafana/prometheus'; -import { setDataSourceSrv, setPluginLinksHook } from '@grafana/runtime'; -import * as ruleActionButtons from 'app/features/alerting/unified/components/rules/RuleActionsButtons'; +import { PromOptions } from '@grafana/prometheus'; +import { setPluginLinksHook } from '@grafana/runtime'; +import { setupDataSources } from 'app/features/alerting/unified/testSetup/datasources'; import { DashboardModel } from 'app/features/dashboard/state/DashboardModel'; import { PanelModel } from 'app/features/dashboard/state/PanelModel'; -import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; import { AccessControlAction } from 'app/types'; import { AlertQuery, PromRulesResponse } from 'app/types/unified-alerting-dto'; @@ -16,7 +14,6 @@ import * as apiRuler from './api/ruler'; import * as alertingAbilities from './hooks/useAbilities'; import { mockAlertRuleApi, setupMswServer } from './mockApi'; import { - MockDataSourceSrv, grantUserPermissions, mockDataSource, mockPromAlert, @@ -26,42 +23,51 @@ import { } from './mocks'; import { captureRequests } from './mocks/server/events'; import { RuleFormValues } from './types/rule-form'; -import * as config from './utils/config'; import { Annotation } from './utils/constants'; import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource'; -jest.mock('./api/prometheus'); jest.mock('./api/ruler'); -jest.mock('../../../core/hooks/useMediaQueryChange'); - -jest.spyOn(config, 'getAllDataSources'); -jest.spyOn(ruleActionButtons, 'matchesWidth').mockReturnValue(false); -jest.spyOn(apiRuler, 'rulerUrlBuilder'); jest.spyOn(alertingAbilities, 'useAlertRuleAbility'); + +const prometheusModuleSettings = { alerting: true, module: 'core:plugin/prometheus' }; + const dataSources = { - prometheus: mockDataSource({ - name: 'Prometheus', - type: DataSourceType.Prometheus, - isDefault: false, - }), - default: mockDataSource({ - name: 'Default', - type: DataSourceType.Prometheus, - isDefault: true, - }), + prometheus: mockDataSource( + { + name: 'Prometheus', + type: DataSourceType.Prometheus, + isDefault: false, + jsonData: { manageAlerts: true }, + }, + prometheusModuleSettings + ), + default: mockDataSource( + { + name: 'Default', + type: DataSourceType.Prometheus, + isDefault: true, + jsonData: { manageAlerts: true }, + }, + prometheusModuleSettings + ), + prometheusMinInterval: mockDataSource( + { + name: 'Prometheus Min Interval', + type: DataSourceType.Prometheus, + isDefault: false, + jsonData: { manageAlerts: true, timeInterval: '7m' }, + }, + prometheusModuleSettings + ), }; -dataSources.prometheus.meta.alerting = true; -dataSources.default.meta.alerting = true; const mocks = { - getAllDataSources: jest.mocked(config.getAllDataSources), useAlertRuleAbilityMock: jest.mocked(alertingAbilities.useAlertRuleAbility), rulerBuilderMock: jest.mocked(apiRuler.rulerUrlBuilder), }; -const renderAlertTabContent = (dashboard: DashboardModel, panel: PanelModel) => { +const renderAlertTabContent = (dashboard: DashboardModel, panel: PanelModel) => render(); -}; const promResponse: PromRulesResponse = { status: 'success', @@ -190,19 +196,13 @@ describe('PanelAlertTabContent', () => { AccessControlAction.AlertingRuleExternalRead, AccessControlAction.AlertingRuleExternalWrite, ]); + setupDataSources(...Object.values(dataSources)); setPluginLinksHook(() => ({ links: [], isLoading: false, })); - mocks.getAllDataSources.mockReturnValue(Object.values(dataSources)); - const dsService = new MockDataSourceSrv(dataSources); - dsService.datasources[dataSources.prometheus.uid] = new PrometheusDatasource( - dataSources.prometheus - ) as DataSourceApi; - dsService.datasources[dataSources.default.uid] = new PrometheusDatasource(dataSources.default) as DataSourceApi; - setDataSourceSrv(dsService); mocks.rulerBuilderMock.mockReturnValue({ rules: () => ({ path: `api/ruler/${GRAFANA_RULES_SOURCE_NAME}/api/v1/rules` }), namespace: () => ({ path: 'ruler' }), @@ -297,13 +297,15 @@ describe('PanelAlertTabContent', () => { }); it('Will take into account datasource minInterval', async () => { - (getDatasourceSrv() as unknown as MockDataSourceSrv).datasources[dataSources.prometheus.uid].interval = '7m'; - renderAlertTabContent( dashboard, new PanelModel({ ...panel, maxDataPoints: 100, + datasource: { + type: 'prometheus', + uid: dataSources.prometheusMinInterval.uid, + }, }) ); @@ -318,7 +320,7 @@ describe('PanelAlertTabContent', () => { refId: 'A', datasource: { type: 'prometheus', - uid: 'mock-ds-2', + uid: 'mock-ds-4', }, interval: '', intervalMs: 420000, diff --git a/public/app/features/alerting/unified/RuleList.test.tsx b/public/app/features/alerting/unified/RuleList.test.tsx index 6fee153615b..8c6caf63e91 100644 --- a/public/app/features/alerting/unified/RuleList.test.tsx +++ b/public/app/features/alerting/unified/RuleList.test.tsx @@ -7,25 +7,23 @@ import { byRole, byTestId, byText } from 'testing-library-selector'; import { PluginExtensionTypes } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; -import { DataSourceSrv, locationService, setAppEvents, setDataSourceSrv, usePluginLinks } from '@grafana/runtime'; +import { locationService, setAppEvents, usePluginLinks } from '@grafana/runtime'; import appEvents from 'app/core/app_events'; -import * as ruleActionButtons from 'app/features/alerting/unified/components/rules/RuleActionsButtons'; import { mockUserApi, setupMswServer } from 'app/features/alerting/unified/mockApi'; import { setAlertmanagerChoices } from 'app/features/alerting/unified/mocks/server/configure'; import * as actions from 'app/features/alerting/unified/state/actions'; +import { setupDataSources } from 'app/features/alerting/unified/testSetup/datasources'; import { getMockUser } from 'app/features/users/__mocks__/userMocks'; import { AlertmanagerChoice } from 'app/plugins/datasource/alertmanager/types'; import { AccessControlAction } from 'app/types'; import { PromAlertingRuleState, PromApplication } from 'app/types/unified-alerting-dto'; -import * as analytics from './Analytics'; import RuleList from './RuleList'; import { discoverFeaturesByUid } from './api/buildInfo'; import { fetchRules } from './api/prometheus'; import * as apiRuler from './api/ruler'; import { fetchRulerRules } from './api/ruler'; import { - MockDataSourceSrv, getPotentiallyPausedRulerRules, grantUserPermissions, mockDataSource, @@ -39,7 +37,6 @@ import { someRulerRules, } from './mocks'; import { setupPluginsExtensionsHook } from './testSetup/plugins'; -import * as config from './utils/config'; import { DataSourceType, GRAFANA_RULES_SOURCE_NAME } from './utils/datasource'; jest.mock('@grafana/runtime', () => ({ @@ -51,11 +48,7 @@ jest.mock('@grafana/runtime', () => ({ jest.mock('./api/buildInfo'); jest.mock('./api/prometheus'); jest.mock('./api/ruler'); -jest.mock('../../../core/hooks/useMediaQueryChange'); -jest.spyOn(ruleActionButtons, 'matchesWidth').mockReturnValue(false); -jest.spyOn(analytics, 'logInfo'); -jest.spyOn(config, 'getAllDataSources'); jest.spyOn(actions, 'rulesInSameGroupHaveInvalidFor').mockReturnValue([]); jest.spyOn(apiRuler, 'rulerUrlBuilder'); @@ -63,7 +56,6 @@ setAppEvents(appEvents); setupPluginsExtensionsHook(); const mocks = { - getAllDataSourcesMock: jest.mocked(config.getAllDataSources), usePluginLinksMock: jest.mocked(usePluginLinks), rulesInSameGroupHaveInvalidForMock: jest.mocked(actions.rulesInSameGroupHaveInvalidFor), @@ -173,18 +165,14 @@ describe('RuleList', () => { ], isLoading: false, }); + setupDataSources(...Object.values(dataSources)); }); afterEach(() => { jest.resetAllMocks(); - setDataSourceSrv(undefined as unknown as DataSourceSrv); }); it('load & show rule groups from multiple cloud data sources', async () => { - mocks.getAllDataSourcesMock.mockReturnValue(Object.values(dataSources)); - - setDataSourceSrv(new MockDataSourceSrv(dataSources)); - mocks.api.discoverFeaturesByUid.mockResolvedValue({ application: PromApplication.Prometheus, features: { @@ -276,9 +264,6 @@ describe('RuleList', () => { }); it('expand rule group, rule and alert details', async () => { - mocks.getAllDataSourcesMock.mockReturnValue([dataSources.prom]); - - setDataSourceSrv(new MockDataSourceSrv({ prom: dataSources.prom })); mocks.api.discoverFeaturesByUid.mockResolvedValue({ application: PromApplication.Cortex, features: { @@ -287,7 +272,7 @@ describe('RuleList', () => { }); mocks.api.fetchRules.mockImplementation((dataSourceName: string) => { - if (dataSourceName === GRAFANA_RULES_SOURCE_NAME) { + if (dataSourceName !== dataSources.prom.name) { return Promise.resolve([]); } else { return Promise.resolve([ @@ -427,9 +412,6 @@ describe('RuleList', () => { }); it('filters rules and alerts by labels', async () => { - mocks.getAllDataSourcesMock.mockReturnValue([dataSources.prom]); - setDataSourceSrv(new MockDataSourceSrv({ prom: dataSources.prom })); - mocks.api.discoverFeaturesByUid.mockResolvedValue({ application: PromApplication.Cortex, features: { @@ -439,7 +421,7 @@ describe('RuleList', () => { mocks.api.fetchRulerRules.mockResolvedValue({}); mocks.api.fetchRules.mockImplementation((dataSourceName: string) => { - if (dataSourceName === GRAFANA_RULES_SOURCE_NAME) { + if (dataSourceName !== dataSources.prom.name) { return Promise.resolve([]); } else { return Promise.resolve([ @@ -573,10 +555,6 @@ describe('RuleList', () => { it.skip('uses entire group when reordering after filtering', async () => { const user = userEvent.setup(); - mocks.getAllDataSourcesMock.mockReturnValue([dataSources.prom]); - - setDataSourceSrv(new MockDataSourceSrv({ prom: dataSources.prom })); - mocks.api.discoverFeaturesByUid.mockResolvedValue({ application: PromApplication.Cortex, features: { @@ -635,8 +613,6 @@ describe('RuleList', () => { 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') : []) @@ -685,9 +661,6 @@ describe('RuleList', () => { function testCase(name: string, fn: () => Promise) { it(name, async () => { - mocks.getAllDataSourcesMock.mockReturnValue(Object.values(testDatasources)); - setDataSourceSrv(new MockDataSourceSrv(testDatasources)); - mocks.api.discoverFeaturesByUid.mockResolvedValue({ application: PromApplication.Cortex, features: { @@ -776,8 +749,6 @@ describe('RuleList', () => { it('Export button should be visible when the user has alert read permissions', async () => { grantUserPermissions([AccessControlAction.AlertingRuleRead]); - mocks.getAllDataSourcesMock.mockReturnValue([]); - setDataSourceSrv(new MockDataSourceSrv({})); mocks.api.fetchRules.mockResolvedValue([ mockPromRuleNamespace({ name: 'foofolder', @@ -813,8 +784,6 @@ describe('RuleList', () => { AccessControlAction.AlertingRuleRead, ]); - mocks.getAllDataSourcesMock.mockReturnValue([]); - setDataSourceSrv(new MockDataSourceSrv({})); mocks.api.fetchRules.mockResolvedValue([]); mocks.api.fetchRulerRules.mockResolvedValue({}); @@ -832,8 +801,6 @@ describe('RuleList', () => { AccessControlAction.AlertingRuleRead, ]); - mocks.getAllDataSourcesMock.mockReturnValue([]); - setDataSourceSrv(new MockDataSourceSrv({})); mocks.api.fetchRules.mockResolvedValue(somePromRules('grafana')); mocks.api.fetchRulerRules.mockResolvedValue(someRulerRules); @@ -853,8 +820,6 @@ describe('RuleList', () => { AccessControlAction.AlertingRuleExternalWrite, ]); - mocks.getAllDataSourcesMock.mockReturnValue([dataSources.prom]); - setDataSourceSrv(new MockDataSourceSrv({ prom: dataSources.prom })); mocks.api.discoverFeaturesByUid.mockResolvedValue({ application: PromApplication.Cortex, features: { @@ -867,7 +832,7 @@ describe('RuleList', () => { renderRuleList(); - await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalledTimes(1)); + await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalled()); expect(ui.newRuleButton.get()).toBeInTheDocument(); }); @@ -878,8 +843,6 @@ describe('RuleList', () => { AccessControlAction.AlertingRuleExternalWrite, ]); - mocks.getAllDataSourcesMock.mockReturnValue([dataSources.prom]); - setDataSourceSrv(new MockDataSourceSrv({ prom: dataSources.prom })); mocks.api.discoverFeaturesByUid.mockResolvedValue({ application: PromApplication.Cortex, features: { @@ -892,7 +855,7 @@ describe('RuleList', () => { renderRuleList(); - await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalledTimes(1)); + await waitFor(() => expect(mocks.api.fetchRules).toHaveBeenCalled()); expect(ui.newRuleButton.get()).toBeInTheDocument(); }); }); diff --git a/public/app/features/alerting/unified/Settings.test.tsx b/public/app/features/alerting/unified/Settings.test.tsx index 0df8f2570f1..401b4b6fee7 100644 --- a/public/app/features/alerting/unified/Settings.test.tsx +++ b/public/app/features/alerting/unified/Settings.test.tsx @@ -4,11 +4,8 @@ import { render } from 'test/test-utils'; import { byRole, byTestId, byText } from 'testing-library-selector'; import SettingsPage from './Settings'; -import { - DataSourcesResponse, - setupGrafanaManagedServer, - withExternalOnlySetting, -} from './components/settings/__mocks__/server'; +import DataSourcesResponse from './components/settings/__mocks__/api/datasources.json'; +import { setupGrafanaManagedServer, withExternalOnlySetting } from './components/settings/__mocks__/server'; import { setupMswServer } from './mockApi'; import { grantUserRole } from './mocks'; diff --git a/public/app/features/alerting/unified/components/rules/RulesFilter.test.tsx b/public/app/features/alerting/unified/components/rules/RulesFilter.test.tsx index f2df2ef5747..1484cfaa4ec 100644 --- a/public/app/features/alerting/unified/components/rules/RulesFilter.test.tsx +++ b/public/app/features/alerting/unified/components/rules/RulesFilter.test.tsx @@ -1,11 +1,10 @@ import { render, screen } from 'test/test-utils'; import { byLabelText, byRole } from 'testing-library-selector'; -import { locationService, setDataSourceSrv } from '@grafana/runtime'; +import { locationService } from '@grafana/runtime'; import { setupMswServer } from 'app/features/alerting/unified/mockApi'; import * as analytics from '../../Analytics'; -import { MockDataSourceSrv } from '../../mocks'; import { setupPluginsExtensionsHook } from '../../testSetup/plugins'; import RulesFilter from './Filter/RulesFilter'; @@ -21,8 +20,6 @@ jest.mock('./MultipleDataSourcePicker', () => { }; }); -setDataSourceSrv(new MockDataSourceSrv({})); - setupPluginsExtensionsHook(); const ui = { diff --git a/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.test.tsx b/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.test.tsx index 5cc98ea0587..c629073d589 100644 --- a/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.test.tsx +++ b/public/app/features/alerting/unified/components/settings/AlertmanagerConfig.test.tsx @@ -3,6 +3,7 @@ import userEvent from '@testing-library/user-event'; import { render } from 'test/test-utils'; import { byRole } from 'testing-library-selector'; +import { setupDataSources } from 'app/features/alerting/unified/testSetup/datasources'; import { AccessControlAction } from 'app/types'; import { setupMswServer } from '../../mockApi'; @@ -13,6 +14,7 @@ import AlertmanagerConfig from './AlertmanagerConfig'; import { EXTERNAL_VANILLA_ALERTMANAGER_UID, PROVISIONED_MIMIR_ALERTMANAGER_UID, + mockDataSources, setupVanillaAlertmanagerServer, } from './__mocks__/server'; @@ -75,6 +77,7 @@ describe('vanilla Alertmanager', () => { beforeEach(() => { setupVanillaAlertmanagerServer(server); + setupDataSources(...Object.values(mockDataSources)); grantUserPermissions([AccessControlAction.AlertingNotificationsRead, AccessControlAction.AlertingInstanceRead]); }); diff --git a/public/app/features/alerting/unified/components/settings/__mocks__/server.ts b/public/app/features/alerting/unified/components/settings/__mocks__/server.ts index b1bb83c5f26..387f499bc05 100644 --- a/public/app/features/alerting/unified/components/settings/__mocks__/server.ts +++ b/public/app/features/alerting/unified/components/settings/__mocks__/server.ts @@ -1,7 +1,6 @@ import { HttpResponse, delay, http } from 'msw'; import { SetupServerApi } from 'msw/node'; -import { setDataSourceSrv } from '@grafana/runtime'; import { AlertManagerCortexConfig, AlertManagerDataSourceJsonData, @@ -10,8 +9,7 @@ import { Receiver, } from 'app/plugins/datasource/alertmanager/types'; -import { MockDataSourceSrv, mockDataSource } from '../../../mocks'; -import * as config from '../../../utils/config'; +import { mockDataSource } from '../../../mocks'; import { DataSourceType } from '../../../utils/datasource'; import internalAlertmanagerConfig from './api/alertmanager/grafana/config/api/v1/alerts.json'; @@ -22,41 +20,34 @@ import datasources from './api/datasources.json'; import admin_config from './api/v1/ngalert/admin_config.json'; import alertmanagers from './api/v1/ngalert/alertmanagers.json'; -export { datasources as DataSourcesResponse }; -export { admin_config as AdminConfigResponse }; -export { alertmanagers as AlertmanagersResponse }; -export { internalAlertmanagerConfig as InternalAlertmanagerConfiguration }; -export { vanillaAlertmanagerConfig as VanillaAlertmanagerConfiguration }; -export { history as alertmanagerConfigurationHistory }; - export const EXTERNAL_VANILLA_ALERTMANAGER_UID = 'vanilla-alertmanager'; export const PROVISIONED_MIMIR_ALERTMANAGER_UID = 'provisioned-alertmanager'; -jest.spyOn(config, 'getAllDataSources'); - -const mocks = { - getAllDataSources: jest.mocked(config.getAllDataSources), -}; - export const mockDataSources = { - [EXTERNAL_VANILLA_ALERTMANAGER_UID]: mockDataSource({ - uid: EXTERNAL_VANILLA_ALERTMANAGER_UID, - name: EXTERNAL_VANILLA_ALERTMANAGER_UID, - type: DataSourceType.Alertmanager, - jsonData: { - implementation: AlertManagerImplementation.prometheus, + [EXTERNAL_VANILLA_ALERTMANAGER_UID]: mockDataSource( + { + uid: EXTERNAL_VANILLA_ALERTMANAGER_UID, + name: EXTERNAL_VANILLA_ALERTMANAGER_UID, + type: DataSourceType.Alertmanager, + jsonData: { + implementation: AlertManagerImplementation.prometheus, + }, }, - }), - [PROVISIONED_MIMIR_ALERTMANAGER_UID]: mockDataSource({ - uid: PROVISIONED_MIMIR_ALERTMANAGER_UID, - name: PROVISIONED_MIMIR_ALERTMANAGER_UID, - type: DataSourceType.Alertmanager, - jsonData: { - // this is a mutable data source type but we're making it readOnly - implementation: AlertManagerImplementation.mimir, + { module: 'core:plugin/alertmanager' } + ), + [PROVISIONED_MIMIR_ALERTMANAGER_UID]: mockDataSource( + { + uid: PROVISIONED_MIMIR_ALERTMANAGER_UID, + name: PROVISIONED_MIMIR_ALERTMANAGER_UID, + type: DataSourceType.Alertmanager, + jsonData: { + // this is a mutable data source type but we're making it readOnly + implementation: AlertManagerImplementation.mimir, + }, + readOnly: true, }, - readOnly: true, - }), + { module: 'core:plugin/alertmanager' } + ), }; export function setupGrafanaManagedServer(server: SetupServerApi) { @@ -72,9 +63,6 @@ export function setupGrafanaManagedServer(server: SetupServerApi) { } export function setupVanillaAlertmanagerServer(server: SetupServerApi) { - mocks.getAllDataSources.mockReturnValue(Object.values(mockDataSources)); - setDataSourceSrv(new MockDataSourceSrv(mockDataSources)); - server.use( createVanillaAlertmanagerConfigurationHandler(EXTERNAL_VANILLA_ALERTMANAGER_UID), ...createAlertmanagerConfigurationHandlers() diff --git a/public/app/features/alerting/unified/hooks/useFilteredRules.test.ts b/public/app/features/alerting/unified/hooks/useFilteredRules.test.ts index 01c91c4cc0e..728bbfaf765 100644 --- a/public/app/features/alerting/unified/hooks/useFilteredRules.test.ts +++ b/public/app/features/alerting/unified/hooks/useFilteredRules.test.ts @@ -1,8 +1,7 @@ -import { setDataSourceSrv } from '@grafana/runtime'; +import { setupDataSources } from 'app/features/alerting/unified/testSetup/datasources'; import { PromAlertingRuleState } from '../../../../types/unified-alerting-dto'; import { - MockDataSourceSrv, getCloudRule, mockAlertQuery, mockCombinedCloudRuleNamespace, @@ -25,7 +24,7 @@ const dataSources = { loki: mockDataSource({ uid: 'loki-1', name: 'loki' }), }; beforeAll(() => { - setDataSourceSrv(new MockDataSourceSrv(dataSources)); + setupDataSources(...Object.values(dataSources)); }); describe('filterRules', function () { diff --git a/public/app/features/alerting/unified/mocks.ts b/public/app/features/alerting/unified/mocks.ts index cf716feee59..818dc9b2d41 100644 --- a/public/app/features/alerting/unified/mocks.ts +++ b/public/app/features/alerting/unified/mocks.ts @@ -416,7 +416,7 @@ class MockDataSourceApi extends DataSourceApi { } } -// TODO This should be eventually moved to public/app/features/alerting/unified/testSetup/datasources.ts +/** @deprecated use `setupDatasources` instead */ export class MockDataSourceSrv implements DataSourceSrv { datasources: Record = {}; // @ts-ignore diff --git a/public/app/features/alerting/unified/mocks/server/configure.ts b/public/app/features/alerting/unified/mocks/server/configure.ts index 2738946b624..7e2d6c66c71 100644 --- a/public/app/features/alerting/unified/mocks/server/configure.ts +++ b/public/app/features/alerting/unified/mocks/server/configure.ts @@ -102,9 +102,10 @@ export function mimirDataSource() { url: 'https://mimir.local:9000', jsonData: { manageAlerts: true, + implementation: 'mimir', }, }, - { alerting: true } + { alerting: true, module: 'core:plugin/prometheus' } ); setupDataSources(dataSource); diff --git a/public/app/features/alerting/unified/mocks/server/handlers/datasources.ts b/public/app/features/alerting/unified/mocks/server/handlers/datasources.ts index b586367e6bc..3ea92548fb5 100644 --- a/public/app/features/alerting/unified/mocks/server/handlers/datasources.ts +++ b/public/app/features/alerting/unified/mocks/server/handlers/datasources.ts @@ -28,5 +28,28 @@ export const datasourceBuildInfoHandler = () => } ); -const datasourcesHandlers = [datasourceBuildInfoHandler()]; +// TODO: Add more accurate endpoint responses as tests require +const labelValuesHandler = () => + http.get('/api/datasources/uid/:datasourceUid/resources/api/v1/label/__name__/values', ({ params }) => { + return HttpResponse.json({ status: 'sucess', data: [] }); + }); + +// TODO: Add more accurate endpoint responses as tests require +const resourcesLabelsHandler = () => + http.get('/api/datasources/uid/:datasourceUid/resources/api/v1/labels', () => + HttpResponse.json({ status: 'success', data: [] }) + ); + +// TODO: Add more accurate endpoint responses as tests require +const resourcesMetadataHandler = () => + http.get('/api/datasources/uid/:datasourceUid/resources/api/v1/metadata', () => + HttpResponse.json({ status: 'success', data: {} }) + ); + +const datasourcesHandlers = [ + datasourceBuildInfoHandler(), + labelValuesHandler(), + resourcesLabelsHandler(), + resourcesMetadataHandler(), +]; export default datasourcesHandlers; diff --git a/public/app/features/alerting/unified/state/AlertingQueryRunner.test.ts b/public/app/features/alerting/unified/state/AlertingQueryRunner.test.ts index e9935f7bc91..a926172c907 100644 --- a/public/app/features/alerting/unified/state/AlertingQueryRunner.test.ts +++ b/public/app/features/alerting/unified/state/AlertingQueryRunner.test.ts @@ -16,10 +16,18 @@ import { import { DataSourceSrv, DataSourceWithBackend, FetchResponse } from '@grafana/runtime'; import { DataQuery } from '@grafana/schema'; import { BackendSrv } from 'app/core/services/backend_srv'; +import { + EXTERNAL_VANILLA_ALERTMANAGER_UID, + mockDataSources, +} from 'app/features/alerting/unified/components/settings/__mocks__/server'; +import { setupMswServer } from 'app/features/alerting/unified/mockApi'; +import { setupDataSources } from 'app/features/alerting/unified/testSetup/datasources'; import { AlertDataQuery, AlertQuery } from 'app/types/unified-alerting-dto'; import { AlertingQueryResponse, AlertingQueryRunner } from './AlertingQueryRunner'; +setupMswServer(); + describe('AlertingQueryRunner', () => { it('should successfully map response and return panel data by refId', async () => { const response = createFetchResponse({ @@ -28,12 +36,12 @@ describe('AlertingQueryRunner', () => { B: { frames: [createDataFrameJSON([5, 6])] }, }, }); + setupDataSources(...Object.values(mockDataSources)); const runner = new AlertingQueryRunner( mockBackendSrv({ fetch: () => of(response), - }), - mockDataSourceSrv() + }) ); const data = runner.get(); @@ -121,8 +129,7 @@ describe('AlertingQueryRunner', () => { const runner = new AlertingQueryRunner( mockBackendSrv({ fetch: () => of(response).pipe(delay(210)), - }), - mockDataSourceSrv() + }) ); const data = runner.get(); @@ -176,8 +183,7 @@ describe('AlertingQueryRunner', () => { const runner = new AlertingQueryRunner( mockBackendSrv({ fetch: () => throwError(error), - }), - mockDataSourceSrv() + }) ); const data = runner.get(); @@ -332,7 +338,7 @@ const createQuery = (refId: string, options?: Partial): AlertQuery = return defaultsDeep(options, { refId, queryType: '', - datasourceUid: '', + datasourceUid: EXTERNAL_VANILLA_ALERTMANAGER_UID, model: { refId }, relativeTimeRange: getDefaultRelativeTimeRange(), }); diff --git a/public/app/features/alerting/unified/testSetup/datasources.ts b/public/app/features/alerting/unified/testSetup/datasources.ts index d70e0d8050b..e0afce55201 100644 --- a/public/app/features/alerting/unified/testSetup/datasources.ts +++ b/public/app/features/alerting/unified/testSetup/datasources.ts @@ -2,8 +2,7 @@ import { keyBy } from 'lodash'; import { DataSourceInstanceSettings } from '@grafana/data'; import { config, setDataSourceSrv } from '@grafana/runtime'; - -import { MockDataSourceSrv } from '../mocks'; +import { DatasourceSrv } from 'app/features/plugins/datasource_srv'; /** * Sets up the data sources for the tests. @@ -11,6 +10,13 @@ import { MockDataSourceSrv } from '../mocks'; * @param configs data source instance settings. Use **mockDataSource** to create mock settings */ export function setupDataSources(...configs: DataSourceInstanceSettings[]) { - config.datasources = keyBy(configs, (c) => c.name); - setDataSourceSrv(new MockDataSourceSrv(config.datasources)); + const dataSourceSrv = new DatasourceSrv(); + const datasourceSettings = keyBy(configs, (c) => c.name); + + const defaultDatasource = configs.find((c) => c.isDefault); + config.datasources = datasourceSettings; + dataSourceSrv.init(config.datasources, defaultDatasource?.name || config.defaultDatasource); + setDataSourceSrv(dataSourceSrv); + + return dataSourceSrv; }