159 lines
5.7 KiB
TypeScript
159 lines
5.7 KiB
TypeScript
import { renderHook, waitFor } from '@testing-library/react';
|
|
import * as React from 'react';
|
|
import { Provider } from 'react-redux';
|
|
|
|
import { contextSrv } from 'app/core/services/context_srv';
|
|
import { MIMIR_DATASOURCE_UID } from 'app/features/alerting/unified/mocks/server/constants';
|
|
import { configureStore } from 'app/store/configureStore';
|
|
import { AccessControlAction, FolderDTO } from 'app/types';
|
|
|
|
import { setupMswServer } from '../mockApi';
|
|
import { mockDataSource, mockFolder, mockRulerAlertingRule, mockRulerGrafanaRule } from '../mocks';
|
|
import { setupDataSources } from '../testSetup/datasources';
|
|
import { GRAFANA_RULES_SOURCE_NAME } from '../utils/datasource';
|
|
|
|
import { useFolder } from './useFolder';
|
|
import { useIsRuleEditable } from './useIsRuleEditable';
|
|
|
|
jest.mock('./useFolder');
|
|
|
|
const mocks = {
|
|
useFolder: jest.mocked(useFolder),
|
|
};
|
|
|
|
setupMswServer();
|
|
|
|
const dataSources = {
|
|
mimir: mockDataSource({ uid: MIMIR_DATASOURCE_UID, name: 'Mimir' }),
|
|
};
|
|
|
|
setupDataSources(dataSources.mimir);
|
|
|
|
describe('useIsRuleEditable', () => {
|
|
describe('RBAC enabled', () => {
|
|
describe('Grafana rules', () => {
|
|
// When RBAC is enabled we require appropriate alerting permissions in the folder scope
|
|
it('Should allow editing when the user has the alert rule update permission in the folder', async () => {
|
|
mockUseFolder({
|
|
accessControl: {
|
|
[AccessControlAction.AlertingRuleUpdate]: true,
|
|
},
|
|
});
|
|
|
|
const wrapper = getProviderWrapper();
|
|
|
|
const { result } = renderHook(() => useIsRuleEditable('grafana', mockRulerGrafanaRule()), { wrapper });
|
|
|
|
await waitFor(() => expect(result.current.loading).toBe(false));
|
|
expect(result.current.isEditable).toBe(true);
|
|
});
|
|
|
|
it('Should allow deleting when the user has the alert rule delete permission', async () => {
|
|
mockUseFolder({
|
|
accessControl: {
|
|
[AccessControlAction.AlertingRuleDelete]: true,
|
|
},
|
|
});
|
|
|
|
const wrapper = getProviderWrapper();
|
|
|
|
const { result } = renderHook(() => useIsRuleEditable(GRAFANA_RULES_SOURCE_NAME, mockRulerGrafanaRule()), {
|
|
wrapper,
|
|
});
|
|
|
|
await waitFor(() => expect(result.current.loading).toBe(false));
|
|
expect(result.current.isRemovable).toBe(true);
|
|
});
|
|
|
|
it('Should forbid editing when the user has no alert rule update permission', async () => {
|
|
mockUseFolder({ accessControl: {} });
|
|
|
|
const wrapper = getProviderWrapper();
|
|
|
|
const { result } = renderHook(() => useIsRuleEditable('grafana', mockRulerGrafanaRule()), { wrapper });
|
|
|
|
await waitFor(() => expect(result.current.loading).toBe(false));
|
|
expect(result.current.isEditable).toBe(false);
|
|
});
|
|
|
|
it('Should forbid deleting when the user has no alert rule delete permission', async () => {
|
|
mockUseFolder({ accessControl: {} });
|
|
|
|
const wrapper = getProviderWrapper();
|
|
|
|
const { result } = renderHook(() => useIsRuleEditable('grafana', mockRulerGrafanaRule()), { wrapper });
|
|
|
|
await waitFor(() => expect(result.current.loading).toBe(false));
|
|
expect(result.current.isRemovable).toBe(false);
|
|
});
|
|
|
|
it('Should allow editing and deleting when the user has alert rule permissions but does not have folder canSave permission', async () => {
|
|
mockUseFolder({
|
|
canSave: false,
|
|
accessControl: {
|
|
[AccessControlAction.AlertingRuleUpdate]: true,
|
|
[AccessControlAction.AlertingRuleDelete]: true,
|
|
},
|
|
});
|
|
|
|
const wrapper = getProviderWrapper();
|
|
|
|
const { result } = renderHook(() => useIsRuleEditable('grafana', mockRulerGrafanaRule()), { wrapper });
|
|
|
|
await waitFor(() => expect(result.current.loading).toBe(false));
|
|
expect(result.current.isEditable).toBe(true);
|
|
expect(result.current.isRemovable).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe('Cloud rules', () => {
|
|
beforeEach(() => {
|
|
mocks.useFolder.mockReturnValue({ loading: false });
|
|
contextSrv.isEditor = true;
|
|
});
|
|
|
|
it('Should allow editing and deleting when the user has alert rule external write permission', async () => {
|
|
mockPermissions([AccessControlAction.AlertingRuleExternalWrite]);
|
|
const wrapper = getProviderWrapper();
|
|
|
|
const { result } = renderHook(() => useIsRuleEditable(dataSources.mimir.name, mockRulerAlertingRule()), {
|
|
wrapper,
|
|
});
|
|
|
|
await waitFor(() => expect(result.current.loading).toBe(false));
|
|
expect(result.current.isEditable).toBe(true);
|
|
expect(result.current.isRemovable).toBe(true);
|
|
});
|
|
|
|
it('Should forbid editing and deleting when the user has no alert rule external write permission', async () => {
|
|
mockPermissions([]);
|
|
const wrapper = getProviderWrapper();
|
|
|
|
const { result } = renderHook(() => useIsRuleEditable(dataSources.mimir.name, mockRulerAlertingRule()), {
|
|
wrapper,
|
|
});
|
|
|
|
await waitFor(() => expect(result.current.loading).toBe(false));
|
|
expect(result.current.isEditable).toBe(false);
|
|
expect(result.current.isRemovable).toBe(false);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
function mockUseFolder(partial?: Partial<FolderDTO>) {
|
|
mocks.useFolder.mockReturnValue({ loading: false, folder: mockFolder(partial) });
|
|
}
|
|
|
|
function mockPermissions(grantedPermissions: AccessControlAction[]) {
|
|
jest
|
|
.spyOn(contextSrv, 'hasPermission')
|
|
.mockImplementation((action) => grantedPermissions.includes(action as AccessControlAction));
|
|
}
|
|
|
|
function getProviderWrapper() {
|
|
const store = configureStore();
|
|
const wrapper = ({ children }: React.PropsWithChildren<{}>) => <Provider store={store}>{children}</Provider>;
|
|
return wrapper;
|
|
}
|