Files
butler-sos/src/lib/influxdb/__tests__/v3-event-counts.test.js

279 lines
10 KiB
JavaScript

import { jest, describe, test, expect, beforeEach } from '@jest/globals';
// Mock globals
const mockGlobals = {
logger: {
info: jest.fn(),
verbose: jest.fn(),
debug: jest.fn(),
error: jest.fn(),
warn: jest.fn(),
},
config: {
get: jest.fn(),
has: jest.fn(),
},
influx: {
write: jest.fn(),
},
options: {
instanceTag: 'test-instance',
},
udpEvents: {
getLogEvents: jest.fn(),
getUserEvents: jest.fn(),
},
rejectedEvents: {
getRejectedLogEvents: jest.fn(),
},
errorTracker: {
incrementError: jest.fn().mockResolvedValue(),
},
getErrorMessage: jest.fn((err) => err.message),
};
jest.unstable_mockModule('../../../globals.js', () => ({
default: mockGlobals,
}));
// Mock shared utils
const mockUtils = {
isInfluxDbEnabled: jest.fn(),
writeToInfluxWithRetry: jest.fn(),
};
jest.unstable_mockModule('../shared/utils.js', () => mockUtils);
// Mock Point3
const mockPoint = {
setTag: jest.fn().mockReturnThis(),
setIntegerField: jest.fn().mockReturnThis(),
setFloatField: jest.fn().mockReturnThis(),
toLineProtocol: jest.fn().mockReturnValue('event_count'),
};
jest.unstable_mockModule('@influxdata/influxdb3-client', () => ({
Point: jest.fn(() => mockPoint),
}));
describe('v3/event-counts', () => {
let storeEventCountInfluxDBV3;
let storeRejectedEventCountInfluxDBV3;
let globals;
let utils;
beforeEach(async () => {
jest.clearAllMocks();
globals = (await import('../../../globals.js')).default;
utils = await import('../shared/utils.js');
const eventCounts = await import('../v3/event-counts.js');
storeEventCountInfluxDBV3 = eventCounts.storeEventCountInfluxDBV3;
storeRejectedEventCountInfluxDBV3 = eventCounts.storeRejectedEventCountInfluxDBV3;
// Setup default mocks
globals.config.get.mockImplementation((key) => {
if (key === 'Butler-SOS.influxdbConfig.v3Config.database') return 'test-db';
if (key === 'Butler-SOS.qlikSenseEvents.eventCount.influxdb.measurementName')
return 'event_count';
if (key === 'Butler-SOS.qlikSenseEvents.rejectedEventCount.influxdb.measurementName')
return 'rejected_event_count';
return null;
});
globals.config.has.mockReturnValue(false);
utils.isInfluxDbEnabled.mockReturnValue(true);
utils.writeToInfluxWithRetry.mockResolvedValue();
});
describe('storeEventCountInfluxDBV3', () => {
test('should return early when no events to store', async () => {
globals.udpEvents.getLogEvents.mockResolvedValue([]);
globals.udpEvents.getUserEvents.mockResolvedValue([]);
await storeEventCountInfluxDBV3();
expect(globals.logger.verbose).toHaveBeenCalledWith(
expect.stringContaining('No events to store')
);
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
});
test('should return early when InfluxDB is disabled', async () => {
utils.isInfluxDbEnabled.mockReturnValue(false);
globals.udpEvents.getLogEvents.mockResolvedValue([{ source: 'test' }]);
globals.udpEvents.getUserEvents.mockResolvedValue([]);
await storeEventCountInfluxDBV3();
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
});
test('should store log events successfully', async () => {
const logEvents = [
{
source: 'qseow-engine',
host: 'server1',
subsystem: 'Engine',
counter: 10,
},
{
source: 'qseow-proxy',
host: 'server2',
subsystem: 'Proxy',
counter: 5,
},
];
globals.udpEvents.getLogEvents.mockResolvedValue(logEvents);
globals.udpEvents.getUserEvents.mockResolvedValue([]);
await storeEventCountInfluxDBV3();
expect(utils.writeToInfluxWithRetry).toHaveBeenCalledTimes(2);
expect(mockPoint.setTag).toHaveBeenCalledWith('event_type', 'log');
expect(mockPoint.setTag).toHaveBeenCalledWith('source', 'qseow-engine');
expect(mockPoint.setIntegerField).toHaveBeenCalledWith('counter', 10);
});
test('should store user events successfully', async () => {
const userEvents = [
{
source: 'user-activity',
host: 'server1',
subsystem: 'N/A',
counter: 15,
},
];
globals.udpEvents.getLogEvents.mockResolvedValue([]);
globals.udpEvents.getUserEvents.mockResolvedValue(userEvents);
await storeEventCountInfluxDBV3();
expect(utils.writeToInfluxWithRetry).toHaveBeenCalledTimes(1);
expect(mockPoint.setTag).toHaveBeenCalledWith('event_type', 'user');
expect(mockPoint.setIntegerField).toHaveBeenCalledWith('counter', 15);
});
test('should store both log and user events', async () => {
const logEvents = [
{ source: 'qseow-engine', host: 'server1', subsystem: 'Engine', counter: 10 },
];
const userEvents = [
{ source: 'user-activity', host: 'server1', subsystem: 'N/A', counter: 5 },
];
globals.udpEvents.getLogEvents.mockResolvedValue(logEvents);
globals.udpEvents.getUserEvents.mockResolvedValue(userEvents);
await storeEventCountInfluxDBV3();
expect(utils.writeToInfluxWithRetry).toHaveBeenCalledTimes(2);
});
test('should apply config tags when available', async () => {
globals.config.has.mockReturnValue(true);
globals.config.get.mockImplementation((key) => {
if (key === 'Butler-SOS.influxdbConfig.v3Config.database') return 'test-db';
if (key === 'Butler-SOS.qlikSenseEvents.eventCount.influxdb.measurementName')
return 'event_count';
if (key === 'Butler-SOS.qlikSenseEvents.eventCount.influxdb.tags')
return [{ name: 'env', value: 'production' }];
return null;
});
const logEvents = [
{ source: 'qseow-engine', host: 'server1', subsystem: 'Engine', counter: 10 },
];
globals.udpEvents.getLogEvents.mockResolvedValue(logEvents);
globals.udpEvents.getUserEvents.mockResolvedValue([]);
await storeEventCountInfluxDBV3();
expect(mockPoint.setTag).toHaveBeenCalledWith('env', 'production');
});
test('should handle write errors', async () => {
const logEvents = [
{ source: 'qseow-engine', host: 'server1', subsystem: 'Engine', counter: 10 },
];
globals.udpEvents.getLogEvents.mockResolvedValue(logEvents);
globals.udpEvents.getUserEvents.mockResolvedValue([]);
const writeError = new Error('Write failed');
utils.writeToInfluxWithRetry.mockRejectedValue(writeError);
await storeEventCountInfluxDBV3();
expect(globals.logger.error).toHaveBeenCalledWith(
expect.stringContaining('Error writing data to InfluxDB')
);
});
});
describe('storeRejectedEventCountInfluxDBV3', () => {
test('should return early when no events to store', async () => {
globals.rejectedEvents.getRejectedLogEvents.mockResolvedValue([]);
await storeRejectedEventCountInfluxDBV3();
expect(globals.logger.verbose).toHaveBeenCalledWith(
expect.stringContaining('No events to store')
);
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
});
test('should return early when InfluxDB is disabled', async () => {
utils.isInfluxDbEnabled.mockReturnValue(false);
globals.rejectedEvents.getRejectedLogEvents.mockResolvedValue([{ source: 'test' }]);
await storeRejectedEventCountInfluxDBV3();
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
});
test('should store rejected log events successfully', async () => {
const logEvents = [
{
source: 'qseow-qix-perf',
objectType: 'Doc',
method: 'GetLayout',
counter: 3,
processTime: 1.5,
appId: 'test-app-123',
appName: 'Test App',
},
];
globals.config.has.mockReturnValue(false); // No custom tags
globals.rejectedEvents.getRejectedLogEvents.mockResolvedValue(logEvents);
await storeRejectedEventCountInfluxDBV3();
// Should have written the rejected event
expect(utils.writeToInfluxWithRetry).toHaveBeenCalled();
expect(globals.logger.debug).toHaveBeenCalledWith(
expect.stringContaining('Wrote data to InfluxDB v3')
);
});
test('should handle write errors for rejected events', async () => {
const logEvents = [
{
source: 'qseow-engine',
host: 'server1',
subsystem: 'Engine',
counter_rejected: 3,
},
];
globals.rejectedEvents.getRejectedLogEvents.mockResolvedValue(logEvents);
const writeError = new Error('Write failed');
utils.writeToInfluxWithRetry.mockRejectedValue(writeError);
await storeRejectedEventCountInfluxDBV3();
expect(globals.logger.error).toHaveBeenCalledWith(
expect.stringContaining('Error writing data to InfluxDB')
);
});
});
});