Skip to content

Commit

Permalink
unit test for thread pool write rejections alert
Browse files Browse the repository at this point in the history
  • Loading branch information
neptunian committed Jun 23, 2021
1 parent 65fe38b commit 4957b68
Showing 1 changed file with 298 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { ThreadPoolWriteRejectionsAlert } from './thread_pool_write_rejections_alert';
import { ALERT_THREAD_POOL_WRITE_REJECTIONS } from '../../common/constants';
import { fetchThreadPoolRejectionStats } from '../lib/alerts/fetch_thread_pool_rejections_stats';
import { fetchClusters } from '../lib/alerts/fetch_clusters';
import { elasticsearchServiceMock } from 'src/core/server/mocks';

const RealDate = Date;

jest.mock('../lib/alerts/fetch_thread_pool_rejections_stats', () => ({
fetchThreadPoolRejectionStats: jest.fn(),
}));
jest.mock('../lib/alerts/fetch_clusters', () => ({
fetchClusters: jest.fn(),
}));

jest.mock('../static_globals', () => ({
Globals: {
app: {
getLogger: () => ({ debug: jest.fn() }),
url: 'http://localhost:5601',
config: {
ui: {
show_license_expiration: true,
ccs: { enabled: true },
metricbeat: { index: 'metricbeat-*' },
container: { elasticsearch: { enabled: false } },
},
},
},
},
}));

describe('ThreadpoolWriteRejectionsAlert', () => {
it('should have defaults', () => {
const alert = new ThreadPoolWriteRejectionsAlert();
expect(alert.alertOptions.id).toBe(ALERT_THREAD_POOL_WRITE_REJECTIONS);
expect(alert.alertOptions.name).toBe(`Thread pool write rejections`);
expect(alert.alertOptions.throttle).toBe('1d');
expect(alert.alertOptions.defaultParams).toStrictEqual({ threshold: 300, duration: '5m' });
expect(alert.alertOptions.actionVariables).toStrictEqual([
{ name: 'node', description: 'The node reporting high thread pool write rejections.' },
{
name: 'internalShortMessage',
description: 'The short internal message generated by Elastic.',
},
{
name: 'internalFullMessage',
description: 'The full internal message generated by Elastic.',
},
{ name: 'state', description: 'The current state of the alert.' },
{ name: 'clusterName', description: 'The cluster to which the node belongs.' },
{ name: 'action', description: 'The recommended action for this alert.' },
{
name: 'actionPlain',
description: 'The recommended action for this alert, without any markdown.',
},
]);
});
describe('execute', () => {
function FakeDate() {}
FakeDate.prototype.valueOf = () => 1;

const clusterUuid = 'abc123';
const clusterName = 'testCluster';
const nodeId = 'esNode1';
const nodeName = 'esName1';
const threadPoolType = 'write';
const rejectionCount = 400;
const stat = [
{
rejectionCount,
type: threadPoolType,
clusterUuid,
nodeId,
nodeName,
ccs: null,
},
];

const replaceState = jest.fn();
const scheduleActions = jest.fn();
const getState = jest.fn();
const executorOptions = {
services: {
scopedClusterClient: elasticsearchServiceMock.createScopedClusterClient(),
alertInstanceFactory: jest.fn().mockImplementation(() => {
return {
replaceState,
scheduleActions,
getState,
};
}),
},
state: {},
};

beforeEach(() => {
// @ts-ignore
Date = FakeDate;
(fetchThreadPoolRejectionStats as jest.Mock).mockImplementation(() => {
return stat;
});
(fetchClusters as jest.Mock).mockImplementation(() => {
return [{ clusterUuid, clusterName }];
});
});

afterEach(() => {
Date = RealDate;
replaceState.mockReset();
scheduleActions.mockReset();
getState.mockReset();
});

it('should fire actions', async () => {
const alert = new ThreadPoolWriteRejectionsAlert();
const type = alert.getAlertType();
await type.executor({
...executorOptions,
params: alert.alertOptions.defaultParams,
} as any);
expect(replaceState).toHaveBeenCalledWith({
alertStates: [
{
ccs: null,
cluster: { clusterUuid, clusterName },
nodeId,
nodeName,
itemLabel: undefined,
meta: {
rejectionCount,
clusterUuid,
type: threadPoolType,
nodeId,
nodeName,
ccs: null,
},
ui: {
isFiring: true,
message: {
text: `Node #start_link${nodeName}#end_link is reporting ${rejectionCount} ${threadPoolType} rejections at #absolute`,
nextSteps: [
{
text: '#start_linkMonitor this node#end_link',
tokens: [
{
startToken: '#start_link',
endToken: '#end_link',
type: 'link',
url: 'elasticsearch/nodes/esNode1/advanced',
},
],
},
{
text: '#start_linkOptimize complex queries#end_link',
tokens: [
{
startToken: '#start_link',
endToken: '#end_link',
type: 'docLink',
partialUrl:
'{elasticWebsiteUrl}blog/advanced-tuning-finding-and-fixing-slow-elasticsearch-queries',
},
],
},
{
text: '#start_linkAdd more nodes#end_link',
tokens: [
{
startToken: '#start_link',
endToken: '#end_link',
type: 'docLink',
partialUrl:
'{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/add-elasticsearch-nodes.html',
},
],
},
{
text: '#start_linkResize your deployment (ECE)#end_link',
tokens: [
{
startToken: '#start_link',
endToken: '#end_link',
type: 'docLink',
partialUrl:
'{elasticWebsiteUrl}guide/en/cloud-enterprise/current/ece-resize-deployment.html',
},
],
},
{
text: '#start_linkThread pool settings#end_link',
tokens: [
{
startToken: '#start_link',
endToken: '#end_link',
type: 'docLink',
partialUrl:
'{elasticWebsiteUrl}guide/en/elasticsearch/reference/{docLinkVersion}/modules-threadpool.html',
},
],
},
],
tokens: [
{
startToken: '#absolute',
type: 'time',
isAbsolute: true,
isRelative: false,
timestamp: 1,
},
{
startToken: '#start_link',
endToken: '#end_link',
type: 'link',
url: `elasticsearch/nodes/${nodeId}`,
},
],
},
severity: 'danger',
triggeredMS: 1,
lastCheckedMS: 0,
},
},
],
});
expect(scheduleActions).toHaveBeenCalledWith('default', {
internalFullMessage: `Thread pool ${threadPoolType} rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`,
internalShortMessage: `Thread pool ${threadPoolType} rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify thread pool ${threadPoolType} rejections for the affected node.`,
node: `${nodeName}`,
action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid}))`,
actionPlain: `Verify thread pool ${threadPoolType} rejections for the affected node.`,
clusterName,
count: 1,
threadPoolType,
state: 'firing',
});
});
it('should not fire actions if under threshold', async () => {
(fetchThreadPoolRejectionStats as jest.Mock).mockImplementation(() => {
return [
{
...stat[0],
rejectionCount: 1,
},
];
});
const alert = new ThreadPoolWriteRejectionsAlert();
const type = alert.getAlertType();
await type.executor({
...executorOptions,
// @ts-ignore
params: alert.alertOptions.defaultParams,
} as any);
expect(replaceState).toHaveBeenCalledWith({
alertStates: [],
});
expect(scheduleActions).not.toHaveBeenCalled();
});

it('should handle ccs', async () => {
const ccs = 'testCluster';
(fetchThreadPoolRejectionStats as jest.Mock).mockImplementation(() => {
return [
{
...stat[0],
ccs,
},
];
});
const alert = new ThreadPoolWriteRejectionsAlert();
const type = alert.getAlertType();
await type.executor({
...executorOptions,
// @ts-ignore
params: alert.alertOptions.defaultParams,
} as any);
const count = 1;
expect(scheduleActions).toHaveBeenCalledWith('default', {
internalFullMessage: `Thread pool ${threadPoolType} rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. [View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/${nodeId}?_g=(cluster_uuid:${clusterUuid},ccs:${ccs}))`,
internalShortMessage: `Thread pool ${threadPoolType} rejections alert is firing for node ${nodeName} in cluster: ${clusterName}. Verify thread pool ${threadPoolType} rejections for the affected node.`,
node: `${nodeName}`,
action: `[View node](http://localhost:5601/app/monitoring#/elasticsearch/nodes/esNode1?_g=(cluster_uuid:abc123,ccs:testCluster))`,
actionPlain: `Verify thread pool ${threadPoolType} rejections for the affected node.`,
clusterName,
count,
state: 'firing',
threadPoolType,
});
});
});
});

0 comments on commit 4957b68

Please sign in to comment.