Files
dockhand-upstream/tests/zabbix-notifications.test.ts
T
Sergei Nesterkov 7a007bd623 feat(notifications): add Zabbix history.push provider (#1419)
* feat(notifications): add Zabbix history.push provider

* test(notifications): add Zabbix provider tests
2026-08-17 15:24:47 +02:00

173 lines
3.7 KiB
TypeScript

import { describe, expect, spyOn, test } from 'bun:test';
import * as shared from '../src/lib/server/notifications/shared';
import { sendZabbix } from '../src/lib/server/notifications/zabbix';
const successResponse = () =>
new Response(
JSON.stringify({
jsonrpc: '2.0',
result: {
response: 'success',
data: [{ itemid: '12345' }]
},
id: 1
}),
{ status: 200 }
);
describe('Zabbix notifications', () => {
test('sends history.push with correct payload', async () => {
const fetchSpy = spyOn(shared, 'notificationFetch')
.mockResolvedValue(successResponse());
const result = await sendZabbix(
'zabbixs://zabbix.example.com?token=secret-token&host=Dockhand&key=dockhand.event',
{
title: 'Container unhealthy',
message: 'Container test is unhealthy',
type: 'error',
environmentName: 'Docker Test',
eventType: 'container_unhealthy'
}
);
expect(result.success).toBe(true);
expect(fetchSpy).toHaveBeenCalledTimes(1);
const [url, options] = fetchSpy.mock.calls[0];
expect(url.toString()).toBe(
'https://zabbix.example.com/api_jsonrpc.php'
);
const headers = options?.headers as Record<string, string>;
expect(headers.Authorization).toBe('Bearer secret-token');
expect(headers['Content-Type']).toBe('application/json-rpc');
const body = JSON.parse(options?.body as string);
expect(body.method).toBe('history.push');
expect(body.params[0].host).toBe('Dockhand');
expect(body.params[0].key).toBe('dockhand.event');
const event = JSON.parse(body.params[0].value);
expect(event.event_type).toBe('container_unhealthy');
expect(event.title).toBe('Container unhealthy');
expect(event.environment).toBe('Docker Test');
expect(event.type).toBe('error');
fetchSpy.mockRestore();
});
test('converts zabbix scheme to HTTP', async () => {
const fetchSpy = spyOn(shared, 'notificationFetch')
.mockResolvedValue(successResponse());
const result = await sendZabbix(
'zabbix://10.112.8.22/zabbix/api_jsonrpc.php?token=test&host=Dockhand&key=dockhand.event',
{
title: 'Test',
message: 'Test',
type: 'info',
eventType: 'test'
}
);
expect(result.success).toBe(true);
const [url] = fetchSpy.mock.calls[0];
expect(url.toString()).toBe(
'http://10.112.8.22/zabbix/api_jsonrpc.php'
);
fetchSpy.mockRestore();
});
test('returns error for Zabbix API error', async () => {
const fetchSpy = spyOn(shared, 'notificationFetch')
.mockResolvedValue(
new Response(
JSON.stringify({
jsonrpc: '2.0',
error: {
code: -32602,
message: 'Invalid params.',
data: 'Invalid host.'
},
id: 1
}),
{ status: 200 }
)
);
const result = await sendZabbix(
'zabbixs://zabbix.example.com?token=test&host=Dockhand&key=dockhand.event',
{
title: 'Test',
message: 'Test'
}
);
expect(result.success).toBe(false);
expect(result.error).toContain('Zabbix API error');
fetchSpy.mockRestore();
});
test('returns error when history.push rejects item', async () => {
const fetchSpy = spyOn(shared, 'notificationFetch')
.mockResolvedValue(
new Response(
JSON.stringify({
jsonrpc: '2.0',
result: {
response: 'success',
data: [
{
itemid: '12345',
error: 'No permissions to referred object.'
}
]
},
id: 1
}),
{ status: 200 }
)
);
const result = await sendZabbix(
'zabbixs://zabbix.example.com?token=test&host=Dockhand&key=dockhand.event',
{
title: 'Test',
message: 'Test'
}
);
expect(result.success).toBe(false);
expect(result.error).toContain('history.push error');
fetchSpy.mockRestore();
});
test('does not send request without API token', async () => {
const fetchSpy = spyOn(shared, 'notificationFetch');
const result = await sendZabbix(
'zabbixs://zabbix.example.com?host=Dockhand&key=dockhand.event',
{
title: 'Test',
message: 'Test'
}
);
expect(result.success).toBe(false);
expect(result.error).toContain('token');
expect(fetchSpy).not.toHaveBeenCalled();
fetchSpy.mockRestore();
});
});