Skip to content
229 changes: 214 additions & 15 deletions x-pack/legacy/plugins/alerting/server/alerts_client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,33 @@ import { alertTypeRegistryMock } from './alert_type_registry.mock';
import { TaskStatus } from '../../task_manager/server';
import { IntervalSchedule } from './types';
import { resolvable } from './test_utils';
import { encryptedSavedObjectsMock } from '../../../../plugins/encrypted_saved_objects/server/mocks';

const taskManager = taskManagerMock.create();
const alertTypeRegistry = alertTypeRegistryMock.create();
const savedObjectsClient = savedObjectsClientMock.create();
const encryptedSavedObjects = encryptedSavedObjectsMock.createStart();

const alertsClientParams = {
taskManager,
alertTypeRegistry,
savedObjectsClient,
spaceId: 'default',
namespace: 'default',
getUserName: jest.fn(),
createAPIKey: jest.fn(),
invalidateAPIKey: jest.fn(),
logger: loggingServiceMock.create().get(),
encryptedSavedObjectsPlugin: encryptedSavedObjects,
};

beforeEach(() => {
jest.resetAllMocks();
alertsClientParams.createAPIKey.mockResolvedValue({ created: false });
alertsClientParams.createAPIKey.mockResolvedValue({ apiKeysEnabled: false });
alertsClientParams.invalidateAPIKey.mockResolvedValue({
apiKeysEnabled: true,
result: { error_count: 0 },
});
Comment on lines +38 to +41
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels like we're testing the happy path here, it might be worth adding a couple of tests that checks what happens when these api calls fail (throw an error, etc)

alertsClientParams.getUserName.mockResolvedValue('elastic');
taskManager.runNow.mockResolvedValue({ id: '' });
});
Expand Down Expand Up @@ -725,7 +734,7 @@ describe('create()', () => {
async executor() {},
});
alertsClientParams.createAPIKey.mockResolvedValueOnce({
created: true,
apiKeysEnabled: true,
result: { id: '123', api_key: 'abc' },
});
savedObjectsClient.bulkGet.mockResolvedValueOnce({
Expand Down Expand Up @@ -841,7 +850,7 @@ describe('create()', () => {
describe('enable()', () => {
test('enables an alert', async () => {
const alertsClient = new AlertsClient(alertsClientParams);
savedObjectsClient.get.mockResolvedValueOnce({
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
Expand Down Expand Up @@ -900,7 +909,7 @@ describe('enable()', () => {

test(`doesn't enable already enabled alerts`, async () => {
const alertsClient = new AlertsClient(alertsClientParams);
savedObjectsClient.get.mockResolvedValueOnce({
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
Expand All @@ -918,7 +927,7 @@ describe('enable()', () => {

test('calls the API key function', async () => {
const alertsClient = new AlertsClient(alertsClientParams);
savedObjectsClient.get.mockResolvedValueOnce({
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
Expand All @@ -943,7 +952,7 @@ describe('enable()', () => {
ownerId: null,
});
alertsClientParams.createAPIKey.mockResolvedValueOnce({
created: true,
apiKeysEnabled: true,
result: { id: '123', api_key: 'abc' },
});

Expand Down Expand Up @@ -978,6 +987,41 @@ describe('enable()', () => {
scope: ['alerting'],
});
});

test('swallows error when invalidate API key throws', async () => {
const alertsClient = new AlertsClient(alertsClientParams);
alertsClientParams.invalidateAPIKey.mockRejectedValueOnce(new Error('Fail'));
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
schedule: { interval: '10s' },
alertTypeId: '2',
enabled: false,
apiKey: Buffer.from('123:abc').toString('base64'),
},
version: '123',
references: [],
});
taskManager.schedule.mockResolvedValueOnce({
id: 'task-123',
scheduledAt: new Date(),
attempts: 0,
status: TaskStatus.Idle,
runAt: new Date(),
state: {},
params: {},
taskType: '',
startedAt: null,
retryAt: null,
ownerId: null,
});

await alertsClient.enable({ id: '1' });
expect(alertsClientParams.logger.error).toHaveBeenCalledWith(
'Failed to invalidate API Key: Fail'
);
});
});

describe('disable()', () => {
Expand Down Expand Up @@ -1390,7 +1434,7 @@ describe('find()', () => {
describe('delete()', () => {
test('successfully removes an alert', async () => {
const alertsClient = new AlertsClient(alertsClientParams);
savedObjectsClient.get.mockResolvedValueOnce({
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
Expand Down Expand Up @@ -1437,6 +1481,48 @@ describe('delete()', () => {
]
`);
});

test('swallows error when invalidate API key throws', async () => {
const alertsClient = new AlertsClient(alertsClientParams);
alertsClientParams.invalidateAPIKey.mockRejectedValueOnce(new Error('Fail'));
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
alertTypeId: '123',
schedule: { interval: '10s' },
params: {
bar: true,
},
apiKey: Buffer.from('123:abc').toString('base64'),
scheduledTaskId: 'task-123',
actions: [
{
group: 'default',
actionRef: 'action_0',
params: {
foo: true,
},
},
],
},
references: [
{
name: 'action_0',
type: 'action',
id: '1',
},
],
});
savedObjectsClient.delete.mockResolvedValueOnce({
success: true,
});

await alertsClient.delete({ id: '1' });
expect(alertsClientParams.logger.error).toHaveBeenCalledWith(
'Failed to invalidate API Key: Fail'
);
});
});

describe('update()', () => {
Expand All @@ -1448,7 +1534,7 @@ describe('update()', () => {
actionGroups: ['default'],
async executor() {},
});
savedObjectsClient.get.mockResolvedValueOnce({
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
Expand Down Expand Up @@ -1603,7 +1689,7 @@ describe('update()', () => {
actionGroups: ['default'],
async executor() {},
});
savedObjectsClient.get.mockResolvedValueOnce({
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
Expand Down Expand Up @@ -1786,7 +1872,7 @@ describe('update()', () => {
actionGroups: ['default'],
async executor() {},
});
savedObjectsClient.get.mockResolvedValueOnce({
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
Expand All @@ -1810,7 +1896,7 @@ describe('update()', () => {
],
});
alertsClientParams.createAPIKey.mockResolvedValueOnce({
created: true,
apiKeysEnabled: true,
result: { id: '123', api_key: 'abc' },
});
savedObjectsClient.update.mockResolvedValueOnce({
Expand Down Expand Up @@ -1952,7 +2038,7 @@ describe('update()', () => {
},
async executor() {},
});
savedObjectsClient.get.mockResolvedValueOnce({
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
Expand Down Expand Up @@ -1986,6 +2072,93 @@ describe('update()', () => {
);
});

it('swallows error when invalidate API key throws', async () => {
const alertsClient = new AlertsClient(alertsClientParams);
alertsClientParams.invalidateAPIKey.mockRejectedValueOnce(new Error('Fail'));
alertTypeRegistry.get.mockReturnValueOnce({
id: '123',
name: 'Test',
actionGroups: ['default'],
async executor() {},
});
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
enabled: true,
alertTypeId: '123',
scheduledTaskId: 'task-123',
apiKey: Buffer.from('123:abc').toString('base64'),
},
references: [],
version: '123',
});
savedObjectsClient.bulkGet.mockResolvedValueOnce({
saved_objects: [
{
id: '1',
type: 'action',
attributes: {
actionTypeId: 'test',
},
references: [],
},
],
});
savedObjectsClient.update.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
enabled: true,
schedule: { interval: '10s' },
params: {
bar: true,
},
actions: [
{
group: 'default',
actionRef: 'action_0',
actionTypeId: 'test',
params: {
foo: true,
},
},
],
scheduledTaskId: 'task-123',
},
references: [
{
name: 'action_0',
type: 'action',
id: '1',
},
],
});
await alertsClient.update({
id: '1',
data: {
schedule: { interval: '10s' },
name: 'abc',
tags: ['foo'],
params: {
bar: true,
},
actions: [
{
group: 'default',
id: '1',
params: {
foo: true,
},
},
],
},
});
expect(alertsClientParams.logger.error).toHaveBeenCalledWith(
'Failed to invalidate API Key: Fail'
);
});

describe('updating an alert schedule', () => {
function mockApiCalls(
alertId: string,
Expand All @@ -2012,7 +2185,7 @@ describe('update()', () => {
},
],
});
savedObjectsClient.get.mockResolvedValueOnce({
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: alertId,
type: 'alert',
attributes: {
Expand Down Expand Up @@ -2212,7 +2385,7 @@ describe('update()', () => {
describe('updateApiKey()', () => {
test('updates the API key for the alert', async () => {
const alertsClient = new AlertsClient(alertsClientParams);
savedObjectsClient.get.mockResolvedValueOnce({
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
Expand All @@ -2224,7 +2397,7 @@ describe('updateApiKey()', () => {
references: [],
});
alertsClientParams.createAPIKey.mockResolvedValueOnce({
created: true,
apiKeysEnabled: true,
result: { id: '123', api_key: 'abc' },
});

Expand All @@ -2243,4 +2416,30 @@ describe('updateApiKey()', () => {
{ version: '123' }
);
});

test('swallows error when invalidate API key throws', async () => {
const alertsClient = new AlertsClient(alertsClientParams);
alertsClientParams.invalidateAPIKey.mockRejectedValue(new Error('Fail'));
encryptedSavedObjects.getDecryptedAsInternalUser.mockResolvedValueOnce({
id: '1',
type: 'alert',
attributes: {
schedule: { interval: '10s' },
alertTypeId: '2',
enabled: true,
apiKey: Buffer.from('123:abc').toString('base64'),
},
version: '123',
references: [],
});
alertsClientParams.createAPIKey.mockResolvedValueOnce({
apiKeysEnabled: true,
result: { id: '123', api_key: 'abc' },
});

await alertsClient.updateApiKey({ id: '1' });
expect(alertsClientParams.logger.error).toHaveBeenCalledWith(
'Failed to invalidate API Key: Fail'
);
});
});
Loading