Compare commits
14 Commits
main
...
unit-testi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee4086dce5 | ||
|
|
7d73b144c9 | ||
|
|
5fd919a369 | ||
|
|
3159121929 | ||
|
|
d5c3760dc9 | ||
|
|
950584af36 | ||
|
|
fb5d4475e2 | ||
|
|
6771857941 | ||
|
|
1e16df65ac | ||
|
|
933b70134c | ||
|
|
581e80cd37 | ||
|
|
50836593a4 | ||
|
|
f647e828dd | ||
|
|
56fb58abed |
106
frontend/src/container/ListAlertRules/ListAlertRules.test.tsx
Normal file
106
frontend/src/container/ListAlertRules/ListAlertRules.test.tsx
Normal file
@@ -0,0 +1,106 @@
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { fireEvent, render, screen, within } from 'tests/test-utils';
|
||||
|
||||
import ListAlertRules from '.';
|
||||
|
||||
describe('ListAlertRules', () => {
|
||||
test('Should render the table', async () => {
|
||||
act(() => {
|
||||
render(<ListAlertRules />);
|
||||
});
|
||||
|
||||
const newAlert = await screen.findByRole('button', {
|
||||
name: /plus new alert/i,
|
||||
});
|
||||
|
||||
expect(newAlert).toBeInTheDocument();
|
||||
|
||||
const status = await screen.findByText(/status/i);
|
||||
expect(status).toBeInTheDocument();
|
||||
|
||||
const alertName = await screen.findByText(/alert name/i);
|
||||
expect(alertName).toBeInTheDocument();
|
||||
|
||||
const severity = await screen.findByText(/severity/i);
|
||||
expect(severity).toBeInTheDocument();
|
||||
|
||||
const label = await screen.findByText(/label/i);
|
||||
expect(label).toBeInTheDocument();
|
||||
|
||||
const action = await screen.findByText(/action/i);
|
||||
expect(action).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Should render the table data', async () => {
|
||||
act(() => {
|
||||
render(<ListAlertRules />);
|
||||
});
|
||||
|
||||
const status = await screen.findByText(/status/i);
|
||||
expect(status).toBeInTheDocument();
|
||||
|
||||
const disabledRow = await screen.findByRole('row', {
|
||||
name: /disabled Test Rule 1 warning details: https:\/\/stagi\.\.\. hello: world region: us \+1 ellipsis/i,
|
||||
});
|
||||
expect(disabledRow).toBeInTheDocument();
|
||||
|
||||
const actionButton = within(disabledRow).getByRole('button', {
|
||||
name: /ellipsis/i,
|
||||
});
|
||||
expect(actionButton).toBeInTheDocument();
|
||||
|
||||
fireEvent.mouseOver(actionButton);
|
||||
|
||||
const enabled = await screen.findByRole('menuitem', {
|
||||
name: /enable/i,
|
||||
});
|
||||
expect(enabled).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Should render enabled for disabled alert in menu', async () => {
|
||||
act(() => {
|
||||
render(<ListAlertRules />);
|
||||
});
|
||||
|
||||
const disabledRow = await screen.findByRole('row', {
|
||||
name: /disabled Test Rule 1 warning details: https:\/\/stagi\.\.\. hello: world region: us \+1 ellipsis/i,
|
||||
});
|
||||
expect(disabledRow).toBeInTheDocument();
|
||||
|
||||
const actionButton = within(disabledRow).getByRole('button', {
|
||||
name: /ellipsis/i,
|
||||
});
|
||||
expect(actionButton).toBeInTheDocument();
|
||||
|
||||
fireEvent.mouseOver(actionButton);
|
||||
|
||||
const enabled = await screen.findByRole('menuitem', {
|
||||
name: /enable/i,
|
||||
});
|
||||
expect(enabled).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Should render disabled for Ok alert in menu', async () => {
|
||||
act(() => {
|
||||
render(<ListAlertRules />);
|
||||
});
|
||||
|
||||
const enabledRow = await screen.findByRole('row', {
|
||||
name: /ok test rule 2 warning - ellipsis/i,
|
||||
});
|
||||
|
||||
expect(enabledRow).toBeInTheDocument();
|
||||
|
||||
const actionButton = within(enabledRow).getByRole('button', {
|
||||
name: /ellipsis/i,
|
||||
});
|
||||
expect(actionButton).toBeInTheDocument();
|
||||
|
||||
fireEvent.mouseOver(actionButton);
|
||||
|
||||
const disabled = await screen.findByRole('menuitem', {
|
||||
name: /disable/i,
|
||||
});
|
||||
expect(disabled).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,68 @@
|
||||
import { render, screen } from 'tests/test-utils';
|
||||
import { Alerts } from 'types/api/alerts/getTriggered';
|
||||
|
||||
import ExapandableRow from './ExapandableRow';
|
||||
|
||||
jest.mock('lib/convertDateToAmAndPm', () => jest.fn(() => '12:00 PM'));
|
||||
jest.mock('lib/getFormatedDate', () => jest.fn(() => '2023-12-05'));
|
||||
|
||||
describe('ExapandableRow component', () => {
|
||||
const allAlerts: Alerts[] = [
|
||||
{
|
||||
id: 1,
|
||||
annotations: { description: 'Description 1', summary: 'Summary 1' },
|
||||
state: 'active',
|
||||
name: 'Alert 1',
|
||||
labels: {
|
||||
alertname: 'Critical Alert',
|
||||
severity: 'critical',
|
||||
tag1: 'value1',
|
||||
tag2: 'value2',
|
||||
},
|
||||
status: { inhibitedBy: [], silencedBy: [], state: 'active' },
|
||||
startsAt: '2023-12-05T11:00:00Z',
|
||||
fingerprint: 'fingerprint1',
|
||||
endsAt: '2023-12-05T12:00:00Z',
|
||||
generatorURL: 'generatorURL1',
|
||||
receivers: [],
|
||||
updatedAt: '2023-12-05T11:30:00Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
annotations: { description: 'Description 2', summary: 'Summary 2' },
|
||||
state: 'inactive',
|
||||
name: 'Alert 2',
|
||||
labels: {
|
||||
alertname: 'Warning Alert',
|
||||
severity: 'warning',
|
||||
tag1: 'value3',
|
||||
tag2: 'value4',
|
||||
tag3: 'value5',
|
||||
},
|
||||
status: { inhibitedBy: [], silencedBy: [], state: 'inactive' },
|
||||
startsAt: '2023-12-05T13:00:00Z',
|
||||
fingerprint: 'fingerprint2',
|
||||
endsAt: '2023-12-05T14:00:00Z',
|
||||
generatorURL: 'generatorURL2',
|
||||
receivers: [],
|
||||
updatedAt: '2023-12-05T13:30:00Z',
|
||||
},
|
||||
];
|
||||
|
||||
test('should render correct content for each alert', () => {
|
||||
render(<ExapandableRow allAlerts={allAlerts} />);
|
||||
|
||||
expect(screen.getByText('Critical Alert')).toBeInTheDocument();
|
||||
expect(screen.getByText('critical')).toBeInTheDocument();
|
||||
|
||||
expect(screen.getByText('Warning Alert')).toBeInTheDocument();
|
||||
expect(screen.getByText('warning')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Should render the unknown status if tag is not corrently mentioned', () => {
|
||||
render(<ExapandableRow allAlerts={allAlerts} />);
|
||||
const unknowStatus = screen.getByText('Unknown Status');
|
||||
expect(unknowStatus).toBeInTheDocument();
|
||||
screen.debug();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
// FilteredTable.test.tsx
|
||||
|
||||
import { render } from 'tests/test-utils';
|
||||
import { Alerts } from 'types/api/alerts/getTriggered';
|
||||
|
||||
import FilteredTable from '.';
|
||||
|
||||
describe('FilteredTable component', () => {
|
||||
const selectedGroup = [{ value: 'group1' }, { value: 'group2' }];
|
||||
const allAlerts: Alerts[] = [
|
||||
{
|
||||
labels: { group1: 'value1', group2: 'value2' },
|
||||
annotations: { description: 'Description 1', summary: 'Summary 1' },
|
||||
state: 'active',
|
||||
name: 'Alert 1',
|
||||
id: 1,
|
||||
endsAt: '2023-12-05T12:00:00Z',
|
||||
fingerprint: 'fingerprint1',
|
||||
generatorURL: 'generatorURL1',
|
||||
receivers: [],
|
||||
startsAt: '2023-12-05T11:00:00Z',
|
||||
status: { inhibitedBy: [], silencedBy: [], state: 'active' },
|
||||
updatedAt: '2023-12-05T11:30:00Z',
|
||||
},
|
||||
];
|
||||
const selectedFilter = [{ value: 'severity:critical' }];
|
||||
|
||||
it('should render table headers', () => {
|
||||
const { getByText } = render(
|
||||
<FilteredTable
|
||||
selectedGroup={selectedGroup}
|
||||
allAlerts={allAlerts}
|
||||
selectedFilter={selectedFilter}
|
||||
/>,
|
||||
);
|
||||
|
||||
// Assert that each header is present
|
||||
expect(getByText('Status')).toBeInTheDocument();
|
||||
expect(getByText('Alert Name')).toBeInTheDocument();
|
||||
expect(getByText('Severity')).toBeInTheDocument();
|
||||
expect(getByText('Firing Since')).toBeInTheDocument();
|
||||
expect(getByText('Tags')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,68 @@
|
||||
import { render, screen } from 'tests/test-utils';
|
||||
import { Alerts } from 'types/api/alerts/getTriggered';
|
||||
|
||||
import TableRowComponent from './TableRow';
|
||||
|
||||
jest.mock('types/api/alerts/getTriggered', () => ({}));
|
||||
|
||||
describe('TableRowComponent component', () => {
|
||||
const tags = ['tag1', 'tag2'];
|
||||
const tagsAlerts: Alerts[] = [
|
||||
{
|
||||
labels: {
|
||||
alertname: 'Critical Alert',
|
||||
severity: 'critical',
|
||||
tag1: 'value1',
|
||||
tag2: 'value2',
|
||||
},
|
||||
annotations: {
|
||||
description: 'Description 1',
|
||||
summary: 'Summary 1',
|
||||
customProperty: 'Custom Value 1',
|
||||
},
|
||||
state: 'active',
|
||||
name: 'Alert 1',
|
||||
id: 1,
|
||||
endsAt: '2023-12-05T12:00:00Z',
|
||||
fingerprint: 'fingerprint1',
|
||||
generatorURL: 'generatorURL1',
|
||||
receivers: [],
|
||||
startsAt: '2023-12-05T11:00:00Z',
|
||||
status: { inhibitedBy: [], silencedBy: [], state: 'active' },
|
||||
updatedAt: '2023-12-05T11:30:00Z',
|
||||
},
|
||||
{
|
||||
labels: {
|
||||
alertname: 'Warning Alert',
|
||||
severity: 'warning',
|
||||
tag1: 'value3',
|
||||
tag2: 'value4',
|
||||
tag3: 'value5',
|
||||
},
|
||||
annotations: {
|
||||
description: 'Description 2',
|
||||
summary: 'Summary 2',
|
||||
customProperty: 'Custom Value 2',
|
||||
},
|
||||
state: 'inactive',
|
||||
name: 'Alert 2',
|
||||
id: 2,
|
||||
endsAt: '2023-12-05T13:00:00Z',
|
||||
fingerprint: 'fingerprint2',
|
||||
generatorURL: 'generatorURL2',
|
||||
receivers: [],
|
||||
startsAt: '2023-12-05T12:30:00Z',
|
||||
status: { inhibitedBy: [], silencedBy: [], state: 'inactive' },
|
||||
updatedAt: '2023-12-05T12:45:00Z',
|
||||
},
|
||||
// Add more test alerts as needed
|
||||
];
|
||||
|
||||
test('should render tags and expandable row when clicked', () => {
|
||||
render(<TableRowComponent tags={tags} tagsAlert={tagsAlerts} />);
|
||||
expect(screen.getByText('tag1')).toBeInTheDocument();
|
||||
expect(screen.getByText('tag2')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// Add more test cases as needed
|
||||
});
|
||||
@@ -0,0 +1,39 @@
|
||||
import { Alerts } from 'types/api/alerts/getTriggered';
|
||||
|
||||
import { Value } from './Filter';
|
||||
import { FilterAlerts } from './utils';
|
||||
|
||||
describe('FilterAlerts function', () => {
|
||||
const alerts: Alerts[] = [
|
||||
{
|
||||
labels: { severity: 'critical', app: 'myApp' },
|
||||
annotations: { description: 'Alert description', summary: 'Alert summary' },
|
||||
state: 'active',
|
||||
name: 'Alert 1',
|
||||
id: 1,
|
||||
endsAt: '2023-12-05T12:00:00Z',
|
||||
fingerprint: 'fingerprint1',
|
||||
generatorURL: 'generatorURL1',
|
||||
receivers: [],
|
||||
startsAt: '2023-12-05T11:00:00Z',
|
||||
status: { inhibitedBy: [], silencedBy: [], state: 'active' },
|
||||
updatedAt: '2023-12-05T11:30:00Z',
|
||||
},
|
||||
];
|
||||
|
||||
const selectedFilter: Value[] = [
|
||||
{ value: 'severity:critical' },
|
||||
{ value: 'app:myApp' },
|
||||
];
|
||||
|
||||
it('should filter alerts based on the selected filter', () => {
|
||||
const filteredAlerts = FilterAlerts(alerts, selectedFilter);
|
||||
expect(filteredAlerts).toHaveLength(1);
|
||||
expect(filteredAlerts[0].fingerprint).toEqual('fingerprint1');
|
||||
});
|
||||
|
||||
it('should return all alerts when no filter is selected', () => {
|
||||
const allAlerts = FilterAlerts(alerts, []);
|
||||
expect(allAlerts).toHaveLength(alerts.length);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,37 @@
|
||||
import { render } from 'tests/test-utils';
|
||||
|
||||
import Severity from './AlertStatus';
|
||||
|
||||
describe('Severity component', () => {
|
||||
it('should render UnProcessed tag for severity "unprocessed"', () => {
|
||||
const { getByText } = render(<Severity severity="unprocessed" />);
|
||||
const tagElement = getByText('UnProcessed');
|
||||
|
||||
expect(tagElement).toBeInTheDocument();
|
||||
expect(tagElement).toHaveClass('ant-tag-green');
|
||||
});
|
||||
|
||||
it('should render Firing tag for severity "active"', () => {
|
||||
const { getByText } = render(<Severity severity="active" />);
|
||||
const tagElement = getByText('Firing');
|
||||
|
||||
expect(tagElement).toBeInTheDocument();
|
||||
expect(tagElement).toHaveClass('ant-tag-red');
|
||||
});
|
||||
|
||||
it('should render Suppressed tag for severity "suppressed"', () => {
|
||||
const { getByText } = render(<Severity severity="suppressed" />);
|
||||
const tagElement = getByText('Suppressed');
|
||||
|
||||
expect(tagElement).toBeInTheDocument();
|
||||
expect(tagElement).toHaveClass('ant-tag-red');
|
||||
});
|
||||
|
||||
it('should render Unknown Status tag for unknown severity', () => {
|
||||
const { getByText } = render(<Severity severity="unknown" />);
|
||||
const tagElement = getByText('Unknown Status');
|
||||
|
||||
expect(tagElement).toBeInTheDocument();
|
||||
expect(tagElement).toHaveClass('ant-tag-default');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,38 @@
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { render, screen } from 'tests/test-utils';
|
||||
|
||||
import TriggeredAlerts from '.';
|
||||
|
||||
describe('TriggeredAlerts', () => {
|
||||
test('Should render the table', async () => {
|
||||
act(() => {
|
||||
render(<TriggeredAlerts />);
|
||||
});
|
||||
|
||||
const status = await screen.findByText('Status');
|
||||
expect(status).toBeInTheDocument();
|
||||
|
||||
const alertName = await screen.findByText('Alert Name');
|
||||
expect(alertName).toBeInTheDocument();
|
||||
|
||||
const severity = await screen.findByText('Severity');
|
||||
expect(severity).toBeInTheDocument();
|
||||
|
||||
const tags = await screen.findByText('Tags');
|
||||
expect(tags).toBeInTheDocument();
|
||||
|
||||
const firedSince = await screen.findByText('Firing Since');
|
||||
expect(firedSince).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// test('Should render the table data in triggeredAlert', async () => {
|
||||
// act(() => {
|
||||
// render(<TriggeredAlerts />);
|
||||
// });
|
||||
|
||||
// const row = await screen.findByRole('row', {
|
||||
// name: /firing above 400ms alertname: above 400ms component: net\/http details: https:\/\/demo\.\.\.\. \+2 warning 11\/30\/2023 10:04:19 am/i,
|
||||
// });
|
||||
// expect(row).toBeInTheDocument();
|
||||
// });
|
||||
});
|
||||
116
frontend/src/lib/logql/tokens.test.ts
Normal file
116
frontend/src/lib/logql/tokens.test.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
import {
|
||||
NumTypeQueryOperators,
|
||||
QueryOperatorsMultiVal,
|
||||
QueryTypes,
|
||||
StringTypeQueryOperators,
|
||||
ValidTypeSequence,
|
||||
ValidTypeValue,
|
||||
} from './tokens';
|
||||
|
||||
describe('ValidTypeValue', () => {
|
||||
test('should return true for valid numeric values with number operators', () => {
|
||||
expect(ValidTypeValue(NumTypeQueryOperators.GTE, '42')).toBe(true);
|
||||
expect(ValidTypeValue(NumTypeQueryOperators.LT, '3.14')).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false for invalid numeric values with number operators', () => {
|
||||
expect(ValidTypeValue(NumTypeQueryOperators.GTE, 'abc')).toBe(false);
|
||||
expect(ValidTypeValue(NumTypeQueryOperators.LT, '12xyz')).toBe(false);
|
||||
});
|
||||
|
||||
test('should return true for string values with string operators', () => {
|
||||
expect(ValidTypeValue(StringTypeQueryOperators.CONTAINS, 'example')).toBe(
|
||||
true,
|
||||
);
|
||||
expect(ValidTypeValue(StringTypeQueryOperators.NCONTAINS, 'test')).toBe(true);
|
||||
});
|
||||
|
||||
test('should return true for any value with other operators', () => {
|
||||
expect(ValidTypeValue('anything', 'whatever')).toBe(true);
|
||||
expect(ValidTypeValue(QueryOperatorsMultiVal.IN, ['1', '2', '3'])).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false if value is array', () => {
|
||||
expect(ValidTypeValue(NumTypeQueryOperators.GTE, ['1', '2', '3'])).toBe(
|
||||
false,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ValidTypeSequence', () => {
|
||||
test('should return true for valid type sequences', () => {
|
||||
expect(
|
||||
ValidTypeSequence(
|
||||
undefined,
|
||||
QueryTypes.QUERY_KEY,
|
||||
QueryTypes.CONDITIONAL_OPERATOR,
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
ValidTypeSequence(
|
||||
QueryTypes.QUERY_KEY,
|
||||
QueryTypes.QUERY_OPERATOR,
|
||||
QueryTypes.QUERY_VALUE,
|
||||
),
|
||||
).toBe(true);
|
||||
expect(
|
||||
ValidTypeSequence(
|
||||
QueryTypes.QUERY_OPERATOR,
|
||||
QueryTypes.QUERY_VALUE,
|
||||
undefined,
|
||||
),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false for invalid type sequences', () => {
|
||||
expect(
|
||||
ValidTypeSequence(
|
||||
undefined,
|
||||
QueryTypes.QUERY_OPERATOR,
|
||||
QueryTypes.QUERY_VALUE,
|
||||
),
|
||||
).toBe(false);
|
||||
expect(
|
||||
ValidTypeSequence(
|
||||
QueryTypes.QUERY_KEY,
|
||||
QueryTypes.QUERY_VALUE,
|
||||
QueryTypes.QUERY_OPERATOR,
|
||||
),
|
||||
).toBe(false);
|
||||
expect(
|
||||
ValidTypeSequence(
|
||||
QueryTypes.QUERY_OPERATOR,
|
||||
QueryTypes.QUERY_KEY,
|
||||
QueryTypes.QUERY_VALUE,
|
||||
),
|
||||
).toBe(false);
|
||||
expect(
|
||||
ValidTypeSequence(
|
||||
QueryTypes.QUERY_VALUE,
|
||||
QueryTypes.QUERY_OPERATOR,
|
||||
undefined,
|
||||
),
|
||||
).toBe(false);
|
||||
expect(
|
||||
ValidTypeSequence(
|
||||
QueryTypes.CONDITIONAL_OPERATOR,
|
||||
QueryTypes.QUERY_OPERATOR,
|
||||
QueryTypes.QUERY_KEY,
|
||||
),
|
||||
).toBe(false);
|
||||
expect(
|
||||
ValidTypeSequence(
|
||||
QueryTypes.CONDITIONAL_OPERATOR,
|
||||
undefined,
|
||||
QueryTypes.QUERY_KEY,
|
||||
),
|
||||
).toBe(false);
|
||||
expect(
|
||||
ValidTypeSequence(
|
||||
QueryTypes.QUERY_KEY,
|
||||
QueryTypes.CONDITIONAL_OPERATOR,
|
||||
undefined,
|
||||
),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
5
frontend/src/mocks-server/__mockdata__/alerts.ts
Normal file
5
frontend/src/mocks-server/__mockdata__/alerts.ts
Normal file
File diff suppressed because one or more lines are too long
163
frontend/src/mocks-server/__mockdata__/rules.ts
Normal file
163
frontend/src/mocks-server/__mockdata__/rules.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
export const rulesSuccessResponse = {
|
||||
status: 'success',
|
||||
data: {
|
||||
rules: [
|
||||
{
|
||||
id: '5',
|
||||
state: 'disabled',
|
||||
alert: 'Test Rule 1',
|
||||
alertType: 'LOGS_BASED_ALERT',
|
||||
ruleType: 'threshold_rule',
|
||||
evalWindow: '1h0m0s',
|
||||
frequency: '1m0s',
|
||||
condition: {
|
||||
compositeQuery: {
|
||||
builderQueries: {
|
||||
A: {
|
||||
queryName: 'A',
|
||||
stepInterval: 60,
|
||||
dataSource: 'metrics',
|
||||
aggregateOperator: 'noop',
|
||||
aggregateAttribute: {
|
||||
key: '',
|
||||
dataType: 'float64',
|
||||
type: '',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
},
|
||||
filters: {
|
||||
op: 'AND',
|
||||
items: null,
|
||||
},
|
||||
expression: 'A',
|
||||
disabled: false,
|
||||
limit: 0,
|
||||
offset: 0,
|
||||
pageSize: 0,
|
||||
reduceTo: 'last',
|
||||
},
|
||||
},
|
||||
chQueries: {
|
||||
A: {
|
||||
query:
|
||||
'select \ntoStartOfInterval(fromUnixTimestamp64Nano(timestamp), INTERVAL 1 MINUTE) AS interval, \ntoFloat64(count()) as value \nFROM signoz_logs.distributed_logs \nWHERE timestamp BETWEEN {{.start_timestamp_nano}} AND {{.end_timestamp_nano}}\n\nGROUP BY interval;\n\n-- available variables:\n-- \t{{.start_timestamp_nano}}\n-- \t{{.end_timestamp_nano}}\n\n-- required columns (or alias):\n-- \tvalue\n-- \tinterval',
|
||||
disabled: false,
|
||||
},
|
||||
},
|
||||
promQueries: {
|
||||
A: {
|
||||
query: '',
|
||||
disabled: false,
|
||||
},
|
||||
},
|
||||
panelType: 'graph',
|
||||
queryType: 'clickhouse_sql',
|
||||
},
|
||||
op: '1',
|
||||
target: 2000,
|
||||
matchType: '1',
|
||||
},
|
||||
labels: {
|
||||
details: 'https://stagingapp.signoz.io/logs',
|
||||
hello: 'world',
|
||||
region: 'us',
|
||||
severity: 'warning',
|
||||
type: 'test',
|
||||
},
|
||||
annotations: {
|
||||
description: 'description',
|
||||
summary: 'summary',
|
||||
},
|
||||
disabled: true,
|
||||
source:
|
||||
'https://stagingapp.signoz.io/alerts/edit?ruleId=5\u0026compositeQuery=%7B%22builder%22%3A%7B%22queryData%22%3A%5B%7B%22dataSource%22%3A%22metrics%22%2C%22queryName%22%3A%22A%22%2C%22aggregateOperator%22%3A%22noop%22%2C%22aggregateAttribute%22%3A%7B%22key%22%3A%22%22%2C%22dataType%22%3A%22float64%22%2C%22type%22%3A%22%22%2C%22isColumn%22%3Atrue%2C%22isJSON%22%3Afalse%7D%2C%22filters%22%3A%7B%22op%22%3A%22AND%22%2C%22items%22%3Anull%7D%2C%22expression%22%3A%22A%22%2C%22disabled%22%3Afalse%2C%22having%22%3A%5B%5D%2C%22stepInterval%22%3A60%2C%22limit%22%3A0%2C%22orderBy%22%3A%5B%5D%2C%22groupBy%22%3A%5B%5D%2C%22legend%22%3A%22%22%2C%22reduceTo%22%3A%22last%22%2C%22offset%22%3A0%2C%22pageSize%22%3A0%7D%5D%2C%22queryFormulas%22%3A%5B%5D%7D%2C%22promql%22%3A%5B%7B%22query%22%3A%22%22%2C%22disabled%22%3Afalse%2C%22name%22%3A%22A%22%7D%5D%2C%22clickhouse_sql%22%3A%5B%7B%22query%22%3A%22select%20%5CntoStartOfInterval(fromUnixTimestamp64Nano(timestamp)%2C%20INTERVAL%201%20MINUTE)%20AS%20interval%2C%20%5CntoFloat64(count())%20as%20value%20%5CnFROM%20signoz_logs.distributed_logs%20%20%5CnWHERE%20timestamp%20BETWEEN%20%7B%7B.start_timestamp_nano%7D%7D%20AND%20%7B%7B.end_timestamp_nano%7D%7D%5Cn%5CnGROUP%20BY%20interval%3B%5Cn%5Cn--%20available%20variables%3A%5Cn--%20%5Ct%7B%7B.start_timestamp_nano%7D%7D%5Cn--%20%5Ct%7B%7B.end_timestamp_nano%7D%7D%5Cn%5Cn--%20required%20columns%20(or%20alias)%3A%5Cn--%20%5Ctvalue%5Cn--%20%5Ctinterval%22%2C%22disabled%22%3Afalse%2C%22name%22%3A%22A%22%7D%5D%2C%22queryType%22%3A%22clickhouse_sql%22%2C%22id%22%3A%22f17cf0cd-f479-4452-aded-e426aeda45ff%22%7D',
|
||||
preferredChannels: ['webhook-site'],
|
||||
createAt: null,
|
||||
createBy: null,
|
||||
updateAt: '2023-10-27T14:03:49.79371099Z',
|
||||
updateBy: 'ankit@signoz.io',
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
state: 'inactive',
|
||||
alert: 'Test Rule 2',
|
||||
alertType: 'METRIC_BASED_ALERT',
|
||||
ruleType: 'threshold_rule',
|
||||
evalWindow: '5m0s',
|
||||
frequency: '1m0s',
|
||||
condition: {
|
||||
compositeQuery: {
|
||||
builderQueries: {
|
||||
A: {
|
||||
queryName: 'A',
|
||||
stepInterval: 60,
|
||||
dataSource: 'metrics',
|
||||
aggregateOperator: 'sum_rate',
|
||||
aggregateAttribute: {
|
||||
key: 'signoz_calls_total',
|
||||
dataType: 'float64',
|
||||
type: '',
|
||||
isColumn: true,
|
||||
isJSON: false,
|
||||
},
|
||||
filters: {
|
||||
op: 'AND',
|
||||
items: [],
|
||||
},
|
||||
groupBy: [
|
||||
{
|
||||
key: 'service_name',
|
||||
dataType: 'string',
|
||||
type: 'tag',
|
||||
isColumn: false,
|
||||
isJSON: false,
|
||||
},
|
||||
],
|
||||
expression: 'A',
|
||||
disabled: false,
|
||||
limit: 0,
|
||||
offset: 0,
|
||||
pageSize: 0,
|
||||
reduceTo: 'sum',
|
||||
},
|
||||
},
|
||||
chQueries: {
|
||||
A: {
|
||||
query: '',
|
||||
disabled: false,
|
||||
},
|
||||
},
|
||||
promQueries: {
|
||||
A: {
|
||||
query: '',
|
||||
disabled: false,
|
||||
},
|
||||
},
|
||||
panelType: 'graph',
|
||||
queryType: 'builder',
|
||||
},
|
||||
op: '1',
|
||||
target: 20,
|
||||
matchType: '1',
|
||||
},
|
||||
labels: {
|
||||
severity: 'warning',
|
||||
},
|
||||
annotations: {
|
||||
description:
|
||||
'This alert is fired when the defined metric (current value: {{$value}}) crosses the threshold ({{$threshold}})',
|
||||
summary:
|
||||
'The rule threshold is set to {{$threshold}}, and the observed metric value is {{$value}}',
|
||||
},
|
||||
disabled: false,
|
||||
source:
|
||||
'http://localhost:3301/alerts/edit?ruleId=6\u0026compositeQuery=%7B%22builder%22%3A%7B%22queryData%22%3A%5B%7B%22dataSource%22%3A%22metrics%22%2C%22queryName%22%3A%22A%22%2C%22aggregateOperator%22%3A%22sum_rate%22%2C%22aggregateAttribute%22%3A%7B%22key%22%3A%22signoz_calls_total%22%2C%22dataType%22%3A%22float64%22%2C%22type%22%3A%22%22%2C%22isColumn%22%3Atrue%7D%2C%22filters%22%3A%7B%22op%22%3A%22AND%22%2C%22items%22%3A%5B%5D%7D%2C%22expression%22%3A%22A%22%2C%22disabled%22%3Afalse%2C%22having%22%3A%5B%5D%2C%22stepInterval%22%3A60%2C%22limit%22%3A0%2C%22orderBy%22%3A%5B%5D%2C%22groupBy%22%3A%5B%7B%22key%22%3A%22service_name%22%2C%22dataType%22%3A%22string%22%2C%22type%22%3A%22tag%22%2C%22isColumn%22%3Afalse%7D%5D%2C%22legend%22%3A%22%22%2C%22reduceTo%22%3A%22sum%22%2C%22offset%22%3A0%2C%22pageSize%22%3A0%7D%5D%2C%22queryFormulas%22%3A%5B%5D%7D%2C%22promql%22%3A%5B%7B%22query%22%3A%22%22%2C%22disabled%22%3Afalse%2C%22name%22%3A%22A%22%7D%5D%2C%22clickhouse_sql%22%3A%5B%7B%22query%22%3A%22%22%2C%22disabled%22%3Afalse%2C%22name%22%3A%22A%22%7D%5D%2C%22queryType%22%3A%22builder%22%2C%22id%22%3A%22c6486149-69b9-4e75-92ab-dde3282e558f%22%7D',
|
||||
preferredChannels: ['Slack-Discord-Compatible', 'Discord-webhook'],
|
||||
createAt: null,
|
||||
createBy: null,
|
||||
updateAt: '2023-10-06T09:48:07.047188664Z',
|
||||
updateBy: null,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -1,8 +1,10 @@
|
||||
import { rest } from 'msw';
|
||||
|
||||
import { alertsSuccessResponse } from './__mockdata__/alerts';
|
||||
import { billingSuccessResponse } from './__mockdata__/billing';
|
||||
import { licensesSuccessResponse } from './__mockdata__/licenses';
|
||||
import { queryRangeSuccessResponse } from './__mockdata__/query_range';
|
||||
import { rulesSuccessResponse } from './__mockdata__/rules';
|
||||
import { serviceSuccessResponse } from './__mockdata__/services';
|
||||
import { topLevelOperationSuccessResponse } from './__mockdata__/top_level_operations';
|
||||
|
||||
@@ -81,4 +83,12 @@ export const handlers = [
|
||||
rest.get('http://localhost/api/v1/billing', (req, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(billingSuccessResponse)),
|
||||
),
|
||||
|
||||
rest.get('http://localhost/api/v1/rules', (req, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(rulesSuccessResponse)),
|
||||
),
|
||||
|
||||
rest.get('http://localhost/api/v1/alerts', (req, res, ctx) =>
|
||||
res(ctx.status(200), ctx.json(alertsSuccessResponse)),
|
||||
),
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user