mirror of
https://github.com/ptarmiganlabs/butler-sos.git
synced 2025-12-19 09:47:53 -05:00
refactor(influxdb): Modernized shared InfluxDB code, better sharing of code across InfluxDB versions
This commit is contained in:
@@ -17,12 +17,13 @@ Tests for shared utility functions used across v3 implementations.
|
||||
- `getInfluxDbVersion()` - Returns configured InfluxDB version
|
||||
- `useRefactoredInfluxDb()` - Feature flag checking (true/false/undefined)
|
||||
- `isInfluxDbEnabled()` - Validates InfluxDB initialization
|
||||
- `writeToInfluxV3WithRetry()` - Comprehensive retry logic tests:
|
||||
- `writeToInfluxWithRetry()` - Comprehensive unified retry logic tests for all InfluxDB versions:
|
||||
- Success on first attempt
|
||||
- Single retry on timeout with success
|
||||
- Multiple retries (2 attempts) before success
|
||||
- Max retries exceeded (throws after all attempts)
|
||||
- Non-timeout errors throw immediately without retry
|
||||
- Non-retryable errors throw immediately without retry
|
||||
- Network error detection (ETIMEDOUT, ECONNREFUSED, etc.)
|
||||
- Timeout detection from error.name
|
||||
- Timeout detection from error message content
|
||||
- Timeout detection from constructor.name
|
||||
|
||||
@@ -510,7 +510,7 @@ Butler-SOS:
|
||||
# Items below are mandatory if influxdbConfig.enable=true
|
||||
host: influxdb.mycompany.com # InfluxDB host, hostname, FQDN or IP address
|
||||
port: 8086 # Port where InfluxDBdb is listening, usually 8086
|
||||
version: 1 # Is the InfluxDB instance version 1.x or 2.x? Valid values are 1, 2, or 3
|
||||
version: 2 # Is the InfluxDB instance version 1.x or 2.x? Valid values are 1, 2, or 3
|
||||
v3Config: # Settings for InfluxDB v3.x only, i.e. Butler-SOS.influxdbConfig.version=3
|
||||
database: mydatabase
|
||||
description: Butler SOS metrics
|
||||
|
||||
@@ -26,7 +26,7 @@ jest.unstable_mockModule('../../../globals.js', () => ({
|
||||
// Mock shared utils
|
||||
const mockUtils = {
|
||||
isInfluxDbEnabled: jest.fn(),
|
||||
writeToInfluxV3WithRetry: jest.fn(),
|
||||
writeToInfluxWithRetry: jest.fn(),
|
||||
};
|
||||
|
||||
jest.unstable_mockModule('../shared/utils.js', () => mockUtils);
|
||||
@@ -58,7 +58,7 @@ describe('v3/butler-memory', () => {
|
||||
// Setup default mocks
|
||||
globals.config.get.mockReturnValue('test-db');
|
||||
utils.isInfluxDbEnabled.mockReturnValue(true);
|
||||
utils.writeToInfluxV3WithRetry.mockResolvedValue();
|
||||
utils.writeToInfluxWithRetry.mockResolvedValue();
|
||||
});
|
||||
|
||||
describe('postButlerSOSMemoryUsageToInfluxdbV3', () => {
|
||||
@@ -75,7 +75,7 @@ describe('v3/butler-memory', () => {
|
||||
|
||||
await postButlerSOSMemoryUsageToInfluxdbV3(memory);
|
||||
|
||||
expect(utils.writeToInfluxV3WithRetry).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should successfully write memory usage metrics', async () => {
|
||||
@@ -95,7 +95,7 @@ describe('v3/butler-memory', () => {
|
||||
expect(mockPoint.setFloatField).toHaveBeenCalledWith('heap_total', 200.75);
|
||||
expect(mockPoint.setFloatField).toHaveBeenCalledWith('external', 50.25);
|
||||
expect(mockPoint.setFloatField).toHaveBeenCalledWith('process_memory', 250.5);
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should handle write errors', async () => {
|
||||
@@ -108,7 +108,7 @@ describe('v3/butler-memory', () => {
|
||||
};
|
||||
|
||||
const writeError = new Error('Write failed');
|
||||
utils.writeToInfluxV3WithRetry.mockRejectedValue(writeError);
|
||||
utils.writeToInfluxWithRetry.mockRejectedValue(writeError);
|
||||
|
||||
await postButlerSOSMemoryUsageToInfluxdbV3(memory);
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ jest.unstable_mockModule('../../../globals.js', () => ({
|
||||
// Mock shared utils
|
||||
const mockUtils = {
|
||||
isInfluxDbEnabled: jest.fn(),
|
||||
writeToInfluxV3WithRetry: jest.fn(),
|
||||
writeToInfluxWithRetry: jest.fn(),
|
||||
};
|
||||
|
||||
jest.unstable_mockModule('../shared/utils.js', () => mockUtils);
|
||||
@@ -82,7 +82,7 @@ describe('v3/event-counts', () => {
|
||||
});
|
||||
globals.config.has.mockReturnValue(false);
|
||||
utils.isInfluxDbEnabled.mockReturnValue(true);
|
||||
utils.writeToInfluxV3WithRetry.mockResolvedValue();
|
||||
utils.writeToInfluxWithRetry.mockResolvedValue();
|
||||
});
|
||||
|
||||
describe('storeEventCountInfluxDBV3', () => {
|
||||
@@ -95,7 +95,7 @@ describe('v3/event-counts', () => {
|
||||
expect(globals.logger.verbose).toHaveBeenCalledWith(
|
||||
expect.stringContaining('No events to store')
|
||||
);
|
||||
expect(utils.writeToInfluxV3WithRetry).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should return early when InfluxDB is disabled', async () => {
|
||||
@@ -105,7 +105,7 @@ describe('v3/event-counts', () => {
|
||||
|
||||
await storeEventCountInfluxDBV3();
|
||||
|
||||
expect(utils.writeToInfluxV3WithRetry).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should store log events successfully', async () => {
|
||||
@@ -128,7 +128,7 @@ describe('v3/event-counts', () => {
|
||||
|
||||
await storeEventCountInfluxDBV3();
|
||||
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalledTimes(2);
|
||||
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);
|
||||
@@ -148,7 +148,7 @@ describe('v3/event-counts', () => {
|
||||
|
||||
await storeEventCountInfluxDBV3();
|
||||
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalledTimes(1);
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalledTimes(1);
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('event_type', 'user');
|
||||
expect(mockPoint.setIntegerField).toHaveBeenCalledWith('counter', 15);
|
||||
});
|
||||
@@ -166,7 +166,7 @@ describe('v3/event-counts', () => {
|
||||
|
||||
await storeEventCountInfluxDBV3();
|
||||
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalledTimes(2);
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
test('should apply config tags when available', async () => {
|
||||
@@ -199,7 +199,7 @@ describe('v3/event-counts', () => {
|
||||
globals.udpEvents.getUserEvents.mockResolvedValue([]);
|
||||
|
||||
const writeError = new Error('Write failed');
|
||||
utils.writeToInfluxV3WithRetry.mockRejectedValue(writeError);
|
||||
utils.writeToInfluxWithRetry.mockRejectedValue(writeError);
|
||||
|
||||
await storeEventCountInfluxDBV3();
|
||||
|
||||
@@ -218,7 +218,7 @@ describe('v3/event-counts', () => {
|
||||
expect(globals.logger.verbose).toHaveBeenCalledWith(
|
||||
expect.stringContaining('No events to store')
|
||||
);
|
||||
expect(utils.writeToInfluxV3WithRetry).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should return early when InfluxDB is disabled', async () => {
|
||||
@@ -227,7 +227,7 @@ describe('v3/event-counts', () => {
|
||||
|
||||
await storeRejectedEventCountInfluxDBV3();
|
||||
|
||||
expect(utils.writeToInfluxV3WithRetry).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should store rejected log events successfully', async () => {
|
||||
@@ -248,7 +248,7 @@ describe('v3/event-counts', () => {
|
||||
await storeRejectedEventCountInfluxDBV3();
|
||||
|
||||
// Should have written the rejected event
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalled();
|
||||
expect(globals.logger.debug).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Wrote data to InfluxDB v3')
|
||||
);
|
||||
@@ -266,7 +266,7 @@ describe('v3/event-counts', () => {
|
||||
globals.rejectedEvents.getRejectedLogEvents.mockResolvedValue(logEvents);
|
||||
|
||||
const writeError = new Error('Write failed');
|
||||
utils.writeToInfluxV3WithRetry.mockRejectedValue(writeError);
|
||||
utils.writeToInfluxWithRetry.mockRejectedValue(writeError);
|
||||
|
||||
await storeRejectedEventCountInfluxDBV3();
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ const mockUtils = {
|
||||
processAppDocuments: jest.fn(),
|
||||
isInfluxDbEnabled: jest.fn(),
|
||||
applyTagsToPoint3: jest.fn(),
|
||||
writeToInfluxV3WithRetry: jest.fn(),
|
||||
writeToInfluxWithRetry: jest.fn(),
|
||||
};
|
||||
|
||||
jest.unstable_mockModule('../shared/utils.js', () => mockUtils);
|
||||
@@ -86,7 +86,7 @@ describe('v3/health-metrics', () => {
|
||||
sessionAppNames: ['SessionApp1'],
|
||||
});
|
||||
utils.isInfluxDbEnabled.mockReturnValue(true);
|
||||
utils.writeToInfluxV3WithRetry.mockResolvedValue();
|
||||
utils.writeToInfluxWithRetry.mockResolvedValue();
|
||||
utils.applyTagsToPoint3.mockImplementation(() => {});
|
||||
|
||||
// Setup influxWriteApi
|
||||
@@ -145,7 +145,7 @@ describe('v3/health-metrics', () => {
|
||||
|
||||
await postHealthMetricsToInfluxdbV3('test-server', 'test-host', body, {});
|
||||
|
||||
expect(utils.writeToInfluxV3WithRetry).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should warn and return when influxWriteApi is not initialized', async () => {
|
||||
@@ -157,7 +157,7 @@ describe('v3/health-metrics', () => {
|
||||
expect(globals.logger.warn).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Influxdb write API object not initialized')
|
||||
);
|
||||
expect(utils.writeToInfluxV3WithRetry).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should warn and return when writeApi not found for server', async () => {
|
||||
@@ -168,7 +168,7 @@ describe('v3/health-metrics', () => {
|
||||
expect(globals.logger.warn).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Influxdb write API object not found for host test-host')
|
||||
);
|
||||
expect(utils.writeToInfluxV3WithRetry).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should process and write all health metrics successfully', async () => {
|
||||
@@ -199,7 +199,7 @@ describe('v3/health-metrics', () => {
|
||||
expect(utils.applyTagsToPoint3).toHaveBeenCalledTimes(8);
|
||||
|
||||
// Should write all 8 measurements
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalledTimes(8);
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalledTimes(8);
|
||||
});
|
||||
|
||||
test('should call getFormattedTime with started timestamp', async () => {
|
||||
@@ -228,7 +228,7 @@ describe('v3/health-metrics', () => {
|
||||
test('should handle write errors with error tracking', async () => {
|
||||
const body = createMockBody();
|
||||
const writeError = new Error('Write failed');
|
||||
utils.writeToInfluxV3WithRetry.mockRejectedValue(writeError);
|
||||
utils.writeToInfluxWithRetry.mockRejectedValue(writeError);
|
||||
|
||||
await postHealthMetricsToInfluxdbV3('test-server', 'test-host', body, {});
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ jest.unstable_mockModule('../../../globals.js', () => ({
|
||||
// Mock shared utils
|
||||
const mockUtils = {
|
||||
isInfluxDbEnabled: jest.fn(),
|
||||
writeToInfluxV3WithRetry: jest.fn(),
|
||||
writeToInfluxWithRetry: jest.fn(),
|
||||
};
|
||||
|
||||
jest.unstable_mockModule('../shared/utils.js', () => mockUtils);
|
||||
@@ -64,7 +64,7 @@ describe('v3/log-events', () => {
|
||||
// Setup default mocks
|
||||
globals.config.get.mockReturnValue('test-db');
|
||||
utils.isInfluxDbEnabled.mockReturnValue(true);
|
||||
utils.writeToInfluxV3WithRetry.mockResolvedValue();
|
||||
utils.writeToInfluxWithRetry.mockResolvedValue();
|
||||
});
|
||||
|
||||
describe('postLogEventToInfluxdbV3', () => {
|
||||
@@ -78,7 +78,7 @@ describe('v3/log-events', () => {
|
||||
|
||||
await postLogEventToInfluxdbV3(msg);
|
||||
|
||||
expect(utils.writeToInfluxV3WithRetry).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should warn and return for unknown log event source', async () => {
|
||||
@@ -92,7 +92,7 @@ describe('v3/log-events', () => {
|
||||
expect(globals.logger.warn).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Unknown log event source: unknown-source')
|
||||
);
|
||||
expect(utils.writeToInfluxV3WithRetry).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should successfully write qseow-engine log event', async () => {
|
||||
@@ -110,7 +110,7 @@ describe('v3/log-events', () => {
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('source', 'qseow-engine');
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('level', 'INFO');
|
||||
expect(mockPoint.setStringField).toHaveBeenCalledWith('message', 'Test message');
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should successfully write qseow-proxy log event', async () => {
|
||||
@@ -126,7 +126,7 @@ describe('v3/log-events', () => {
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('host', 'server1');
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('source', 'qseow-proxy');
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('level', 'WARN');
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should successfully write qseow-scheduler log event', async () => {
|
||||
@@ -140,7 +140,7 @@ describe('v3/log-events', () => {
|
||||
await postLogEventToInfluxdbV3(msg);
|
||||
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('source', 'qseow-scheduler');
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should successfully write qseow-repository log event', async () => {
|
||||
@@ -154,7 +154,7 @@ describe('v3/log-events', () => {
|
||||
await postLogEventToInfluxdbV3(msg);
|
||||
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('source', 'qseow-repository');
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should successfully write qseow-qix-perf log event', async () => {
|
||||
@@ -178,7 +178,7 @@ describe('v3/log-events', () => {
|
||||
await postLogEventToInfluxdbV3(msg);
|
||||
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('source', 'qseow-qix-perf');
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should handle write errors', async () => {
|
||||
@@ -190,7 +190,7 @@ describe('v3/log-events', () => {
|
||||
};
|
||||
|
||||
const writeError = new Error('Write failed');
|
||||
utils.writeToInfluxV3WithRetry.mockRejectedValue(writeError);
|
||||
utils.writeToInfluxWithRetry.mockRejectedValue(writeError);
|
||||
|
||||
await postLogEventToInfluxdbV3(msg);
|
||||
|
||||
@@ -221,7 +221,7 @@ describe('v3/log-events', () => {
|
||||
'exception_message',
|
||||
'Exception details'
|
||||
);
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -45,7 +45,7 @@ jest.unstable_mockModule('@influxdata/influxdb3-client', () => ({
|
||||
// Mock shared utils
|
||||
jest.unstable_mockModule('../shared/utils.js', () => ({
|
||||
isInfluxDbEnabled: jest.fn(),
|
||||
writeToInfluxV3WithRetry: jest.fn(),
|
||||
writeToInfluxWithRetry: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('InfluxDB v3 Queue Metrics', () => {
|
||||
@@ -66,7 +66,7 @@ describe('InfluxDB v3 Queue Metrics', () => {
|
||||
|
||||
// Setup default mocks
|
||||
utils.isInfluxDbEnabled.mockReturnValue(true);
|
||||
utils.writeToInfluxV3WithRetry.mockResolvedValue();
|
||||
utils.writeToInfluxWithRetry.mockResolvedValue();
|
||||
});
|
||||
|
||||
describe('postUserEventQueueMetricsToInfluxdbV3', () => {
|
||||
@@ -76,7 +76,7 @@ describe('InfluxDB v3 Queue Metrics', () => {
|
||||
await queueMetrics.postUserEventQueueMetricsToInfluxdbV3();
|
||||
|
||||
expect(Point3).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxV3WithRetry).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should warn when queue manager is not initialized', async () => {
|
||||
@@ -99,7 +99,7 @@ describe('InfluxDB v3 Queue Metrics', () => {
|
||||
await queueMetrics.postUserEventQueueMetricsToInfluxdbV3();
|
||||
|
||||
expect(Point3).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxV3WithRetry).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should successfully write queue metrics', async () => {
|
||||
@@ -150,9 +150,11 @@ describe('InfluxDB v3 Queue Metrics', () => {
|
||||
await queueMetrics.postUserEventQueueMetricsToInfluxdbV3();
|
||||
|
||||
expect(Point3).toHaveBeenCalledWith('user_events_queue');
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalledWith(
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalledWith(
|
||||
expect.any(Function),
|
||||
'User event queue metrics'
|
||||
'User event queue metrics',
|
||||
'v3',
|
||||
'user-events-queue'
|
||||
);
|
||||
expect(globals.logger.verbose).toHaveBeenCalledWith(
|
||||
'USER EVENT QUEUE METRICS INFLUXDB V3: Sent queue metrics data to InfluxDB v3'
|
||||
@@ -189,7 +191,7 @@ describe('InfluxDB v3 Queue Metrics', () => {
|
||||
await queueMetrics.postLogEventQueueMetricsToInfluxdbV3();
|
||||
|
||||
expect(Point3).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxV3WithRetry).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should warn when queue manager is not initialized', async () => {
|
||||
@@ -252,9 +254,11 @@ describe('InfluxDB v3 Queue Metrics', () => {
|
||||
await queueMetrics.postLogEventQueueMetricsToInfluxdbV3();
|
||||
|
||||
expect(Point3).toHaveBeenCalledWith('log_events_queue');
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalledWith(
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalledWith(
|
||||
expect.any(Function),
|
||||
'Log event queue metrics'
|
||||
'Log event queue metrics',
|
||||
'v3',
|
||||
'log-events-queue'
|
||||
);
|
||||
expect(globals.logger.verbose).toHaveBeenCalledWith(
|
||||
'LOG EVENT QUEUE METRICS INFLUXDB V3: Sent queue metrics data to InfluxDB v3'
|
||||
@@ -305,7 +309,7 @@ describe('InfluxDB v3 Queue Metrics', () => {
|
||||
clearMetrics: jest.fn(),
|
||||
};
|
||||
|
||||
utils.writeToInfluxV3WithRetry.mockRejectedValue(new Error('Write failed'));
|
||||
utils.writeToInfluxWithRetry.mockRejectedValue(new Error('Write failed'));
|
||||
|
||||
await queueMetrics.postLogEventQueueMetricsToInfluxdbV3();
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ jest.unstable_mockModule('../../../globals.js', () => ({
|
||||
// Mock shared utils
|
||||
const mockUtils = {
|
||||
isInfluxDbEnabled: jest.fn(),
|
||||
writeToInfluxV3WithRetry: jest.fn(),
|
||||
writeToInfluxWithRetry: jest.fn(),
|
||||
};
|
||||
|
||||
jest.unstable_mockModule('../shared/utils.js', () => mockUtils);
|
||||
@@ -62,7 +62,7 @@ describe('v3/sessions', () => {
|
||||
globals.config.get.mockReturnValue('test-db');
|
||||
globals.influx.write.mockResolvedValue();
|
||||
utils.isInfluxDbEnabled.mockReturnValue(true);
|
||||
utils.writeToInfluxV3WithRetry.mockImplementation(async (fn) => await fn());
|
||||
utils.writeToInfluxWithRetry.mockImplementation(async (fn) => await fn());
|
||||
});
|
||||
|
||||
describe('postProxySessionsToInfluxdbV3', () => {
|
||||
|
||||
@@ -95,7 +95,7 @@ describe('InfluxDB v3 Shared Utils', () => {
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
test('should return false when feature flag is undefined for v1/v2', () => {
|
||||
test('should return true for v1 even when feature flag is undefined (v1 always uses refactored code)', () => {
|
||||
globals.config.get.mockImplementation((key) => {
|
||||
if (key === 'Butler-SOS.influxdbConfig.version') return 1;
|
||||
if (key === 'Butler-SOS.influxdbConfig.useRefactoredCode') return undefined;
|
||||
@@ -104,6 +104,18 @@ describe('InfluxDB v3 Shared Utils', () => {
|
||||
|
||||
const result = utils.useRefactoredInfluxDb();
|
||||
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false when feature flag is undefined for v2', () => {
|
||||
globals.config.get.mockImplementation((key) => {
|
||||
if (key === 'Butler-SOS.influxdbConfig.version') return 2;
|
||||
if (key === 'Butler-SOS.influxdbConfig.useRefactoredCode') return undefined;
|
||||
return undefined;
|
||||
});
|
||||
|
||||
const result = utils.useRefactoredInfluxDb();
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -129,11 +141,11 @@ describe('InfluxDB v3 Shared Utils', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('writeToInfluxV3WithRetry', () => {
|
||||
describe('writeToInfluxWithRetry', () => {
|
||||
test('should successfully write on first attempt', async () => {
|
||||
const writeFn = jest.fn().mockResolvedValue();
|
||||
|
||||
await utils.writeToInfluxV3WithRetry(writeFn, 'Test context');
|
||||
await utils.writeToInfluxWithRetry(writeFn, 'Test context', 'v3', '');
|
||||
|
||||
expect(writeFn).toHaveBeenCalledTimes(1);
|
||||
expect(globals.logger.error).not.toHaveBeenCalled();
|
||||
@@ -145,14 +157,14 @@ describe('InfluxDB v3 Shared Utils', () => {
|
||||
|
||||
const writeFn = jest.fn().mockRejectedValueOnce(timeoutError).mockResolvedValueOnce();
|
||||
|
||||
await utils.writeToInfluxV3WithRetry(writeFn, 'Test context', {
|
||||
await utils.writeToInfluxWithRetry(writeFn, 'Test context', 'v3', '', {
|
||||
maxRetries: 3,
|
||||
initialDelayMs: 10,
|
||||
});
|
||||
|
||||
expect(writeFn).toHaveBeenCalledTimes(2);
|
||||
expect(globals.logger.warn).toHaveBeenCalledWith(
|
||||
expect.stringContaining('INFLUXDB V3 RETRY: Test context - Timeout')
|
||||
expect.stringContaining('INFLUXDB V3 RETRY: Test context - Retryable')
|
||||
);
|
||||
});
|
||||
|
||||
@@ -166,7 +178,7 @@ describe('InfluxDB v3 Shared Utils', () => {
|
||||
.mockRejectedValueOnce(timeoutError)
|
||||
.mockResolvedValueOnce();
|
||||
|
||||
await utils.writeToInfluxV3WithRetry(writeFn, 'Test context', {
|
||||
await utils.writeToInfluxWithRetry(writeFn, 'Test context', 'v3', '', {
|
||||
maxRetries: 3,
|
||||
initialDelayMs: 10,
|
||||
});
|
||||
@@ -183,7 +195,7 @@ describe('InfluxDB v3 Shared Utils', () => {
|
||||
globals.errorTracker = { incrementError: jest.fn().mockResolvedValue() };
|
||||
|
||||
await expect(
|
||||
utils.writeToInfluxV3WithRetry(writeFn, 'Test context', {
|
||||
utils.writeToInfluxWithRetry(writeFn, 'Test context', 'v3', '', {
|
||||
maxRetries: 2,
|
||||
initialDelayMs: 10,
|
||||
})
|
||||
@@ -199,12 +211,13 @@ describe('InfluxDB v3 Shared Utils', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('should throw non-timeout error immediately without retry', async () => {
|
||||
const nonTimeoutError = new Error('Connection refused');
|
||||
const writeFn = jest.fn().mockRejectedValue(nonTimeoutError);
|
||||
test('should throw non-retryable error immediately without retry', async () => {
|
||||
const nonRetryableError = new Error('Connection refused');
|
||||
const writeFn = jest.fn().mockRejectedValue(nonRetryableError);
|
||||
globals.errorTracker = { incrementError: jest.fn().mockResolvedValue() };
|
||||
|
||||
await expect(
|
||||
utils.writeToInfluxV3WithRetry(writeFn, 'Test context', {
|
||||
utils.writeToInfluxWithRetry(writeFn, 'Test context', 'v3', '', {
|
||||
maxRetries: 3,
|
||||
initialDelayMs: 10,
|
||||
})
|
||||
@@ -212,7 +225,7 @@ describe('InfluxDB v3 Shared Utils', () => {
|
||||
|
||||
expect(writeFn).toHaveBeenCalledTimes(1);
|
||||
expect(globals.logger.warn).toHaveBeenCalledWith(
|
||||
expect.stringContaining('INFLUXDB V3 WRITE: Test context - Non-timeout error')
|
||||
expect.stringContaining('INFLUXDB V3 WRITE: Test context - Non-retryable error')
|
||||
);
|
||||
});
|
||||
|
||||
@@ -221,7 +234,7 @@ describe('InfluxDB v3 Shared Utils', () => {
|
||||
|
||||
const writeFn = jest.fn().mockRejectedValueOnce(timeoutError).mockResolvedValueOnce();
|
||||
|
||||
await utils.writeToInfluxV3WithRetry(writeFn, 'Test context', {
|
||||
await utils.writeToInfluxWithRetry(writeFn, 'Test context', 'v3', '', {
|
||||
maxRetries: 3,
|
||||
initialDelayMs: 10,
|
||||
});
|
||||
@@ -237,7 +250,7 @@ describe('InfluxDB v3 Shared Utils', () => {
|
||||
|
||||
const writeFn = jest.fn().mockRejectedValueOnce(timeoutError).mockResolvedValueOnce();
|
||||
|
||||
await utils.writeToInfluxV3WithRetry(writeFn, 'Test context', {
|
||||
await utils.writeToInfluxWithRetry(writeFn, 'Test context', 'v3', '', {
|
||||
maxRetries: 3,
|
||||
initialDelayMs: 10,
|
||||
});
|
||||
|
||||
@@ -30,7 +30,7 @@ jest.unstable_mockModule('../../../globals.js', () => ({
|
||||
// Mock shared utils
|
||||
const mockUtils = {
|
||||
isInfluxDbEnabled: jest.fn(),
|
||||
writeToInfluxV3WithRetry: jest.fn(),
|
||||
writeToInfluxWithRetry: jest.fn(),
|
||||
};
|
||||
|
||||
jest.unstable_mockModule('../shared/utils.js', () => mockUtils);
|
||||
@@ -64,7 +64,7 @@ describe('v3/user-events', () => {
|
||||
// Setup default mocks
|
||||
globals.config.get.mockReturnValue('test-db');
|
||||
utils.isInfluxDbEnabled.mockReturnValue(true);
|
||||
utils.writeToInfluxV3WithRetry.mockResolvedValue();
|
||||
utils.writeToInfluxWithRetry.mockResolvedValue();
|
||||
});
|
||||
|
||||
describe('postUserEventToInfluxdbV3', () => {
|
||||
@@ -81,7 +81,7 @@ describe('v3/user-events', () => {
|
||||
|
||||
await postUserEventToInfluxdbV3(msg);
|
||||
|
||||
expect(utils.writeToInfluxV3WithRetry).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should warn and return early when required fields are missing', async () => {
|
||||
@@ -96,7 +96,7 @@ describe('v3/user-events', () => {
|
||||
expect(globals.logger.warn).toHaveBeenCalledWith(
|
||||
expect.stringContaining('Missing required fields')
|
||||
);
|
||||
expect(utils.writeToInfluxV3WithRetry).not.toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should successfully write user event with all fields', async () => {
|
||||
@@ -117,7 +117,7 @@ describe('v3/user-events', () => {
|
||||
|
||||
await postUserEventToInfluxdbV3(msg);
|
||||
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalled();
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('host', 'server1');
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('event_action', 'OpenApp');
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('userDirectory', 'DOMAIN');
|
||||
@@ -136,7 +136,7 @@ describe('v3/user-events', () => {
|
||||
|
||||
await postUserEventToInfluxdbV3(msg);
|
||||
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalled();
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('host', 'server1');
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('event_action', 'CreateApp');
|
||||
});
|
||||
@@ -152,7 +152,7 @@ describe('v3/user-events', () => {
|
||||
|
||||
await postUserEventToInfluxdbV3(msg);
|
||||
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
test('should handle write errors', async () => {
|
||||
@@ -165,7 +165,7 @@ describe('v3/user-events', () => {
|
||||
};
|
||||
|
||||
const writeError = new Error('Write failed');
|
||||
utils.writeToInfluxV3WithRetry.mockRejectedValue(writeError);
|
||||
utils.writeToInfluxWithRetry.mockRejectedValue(writeError);
|
||||
|
||||
await postUserEventToInfluxdbV3(msg);
|
||||
|
||||
@@ -199,7 +199,7 @@ describe('v3/user-events', () => {
|
||||
|
||||
await postUserEventToInfluxdbV3(msg);
|
||||
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalled();
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('uaBrowserName', 'Chrome');
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('uaBrowserMajorVersion', '96');
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('uaOsName', 'Windows');
|
||||
@@ -219,7 +219,7 @@ describe('v3/user-events', () => {
|
||||
|
||||
await postUserEventToInfluxdbV3(msg);
|
||||
|
||||
expect(utils.writeToInfluxV3WithRetry).toHaveBeenCalled();
|
||||
expect(utils.writeToInfluxWithRetry).toHaveBeenCalled();
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('appId', 'abc-123-def');
|
||||
expect(mockPoint.setStringField).toHaveBeenCalledWith('appId_field', 'abc-123-def');
|
||||
expect(mockPoint.setTag).toHaveBeenCalledWith('appName', 'Sales Dashboard');
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
// This test file has been removed as it only contained skipped placeholder tests.
|
||||
// Note: Complex ES module mocking requirements make these tests difficult.
|
||||
// The v3 health metrics code is functionally tested through integration tests.
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Point as Point3 } from '@influxdata/influxdb3-client';
|
||||
import globals from '../../../globals.js';
|
||||
import { isInfluxDbEnabled, writeToInfluxV3WithRetry } from '../shared/utils.js';
|
||||
import { isInfluxDbEnabled, writeToInfluxWithRetry } from '../shared/utils.js';
|
||||
|
||||
/**
|
||||
* Posts Butler SOS memory usage metrics to InfluxDB v3.
|
||||
@@ -40,9 +40,11 @@ export async function postButlerSOSMemoryUsageToInfluxdbV3(memory) {
|
||||
|
||||
try {
|
||||
// Convert point to line protocol and write directly with retry logic
|
||||
await writeToInfluxV3WithRetry(
|
||||
await writeToInfluxWithRetry(
|
||||
async () => await globals.influx.write(point.toLineProtocol(), database),
|
||||
'Memory usage metrics'
|
||||
'Memory usage metrics',
|
||||
'v3',
|
||||
'' // No specific server context for Butler memory
|
||||
);
|
||||
globals.logger.debug(`MEMORY USAGE V3: Wrote data to InfluxDB v3`);
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Point as Point3 } from '@influxdata/influxdb3-client';
|
||||
import globals from '../../../globals.js';
|
||||
import { isInfluxDbEnabled, writeToInfluxV3WithRetry } from '../shared/utils.js';
|
||||
import { isInfluxDbEnabled, writeToInfluxWithRetry } from '../shared/utils.js';
|
||||
|
||||
/**
|
||||
* Store event count in InfluxDB v3
|
||||
@@ -80,9 +80,11 @@ export async function storeEventCountInfluxDBV3() {
|
||||
point.setTag(key, tags[key]);
|
||||
});
|
||||
|
||||
await writeToInfluxV3WithRetry(
|
||||
await writeToInfluxWithRetry(
|
||||
async () => await globals.influx.write(point.toLineProtocol(), database),
|
||||
'Log event counts'
|
||||
'Log event counts',
|
||||
'v3',
|
||||
'log-events'
|
||||
);
|
||||
globals.logger.debug(`EVENT COUNT INFLUXDB V3: Wrote log event data to InfluxDB v3`);
|
||||
}
|
||||
@@ -127,9 +129,11 @@ export async function storeEventCountInfluxDBV3() {
|
||||
point.setTag(key, tags[key]);
|
||||
});
|
||||
|
||||
await writeToInfluxV3WithRetry(
|
||||
await writeToInfluxWithRetry(
|
||||
async () => await globals.influx.write(point.toLineProtocol(), database),
|
||||
'User event counts'
|
||||
'User event counts',
|
||||
'v3',
|
||||
'user-events'
|
||||
);
|
||||
globals.logger.debug(`EVENT COUNT INFLUXDB V3: Wrote user event data to InfluxDB v3`);
|
||||
}
|
||||
@@ -240,9 +244,11 @@ export async function storeRejectedEventCountInfluxDBV3() {
|
||||
|
||||
// Write to InfluxDB
|
||||
for (const point of points) {
|
||||
await writeToInfluxV3WithRetry(
|
||||
await writeToInfluxWithRetry(
|
||||
async () => await globals.influx.write(point.toLineProtocol(), database),
|
||||
'Rejected event counts'
|
||||
'Rejected event counts',
|
||||
'v3',
|
||||
'rejected-events'
|
||||
);
|
||||
}
|
||||
globals.logger.debug(`REJECT LOG EVENT INFLUXDB V3: Wrote data to InfluxDB v3`);
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
processAppDocuments,
|
||||
isInfluxDbEnabled,
|
||||
applyTagsToPoint3,
|
||||
writeToInfluxV3WithRetry,
|
||||
writeToInfluxWithRetry,
|
||||
} from '../shared/utils.js';
|
||||
|
||||
/**
|
||||
@@ -194,9 +194,11 @@ export async function postHealthMetricsToInfluxdbV3(serverName, host, body, serv
|
||||
for (const point of points) {
|
||||
// Apply server tags to each point
|
||||
applyTagsToPoint3(point, serverTags);
|
||||
await writeToInfluxV3WithRetry(
|
||||
await writeToInfluxWithRetry(
|
||||
async () => await globals.influx.write(point.toLineProtocol(), database),
|
||||
`Health metrics for ${host}`
|
||||
`Health metrics for ${host}`,
|
||||
'v3',
|
||||
serverName
|
||||
);
|
||||
}
|
||||
globals.logger.debug(`HEALTH METRICS V3: Wrote data to InfluxDB v3`);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Point as Point3 } from '@influxdata/influxdb3-client';
|
||||
import globals from '../../../globals.js';
|
||||
import { isInfluxDbEnabled, writeToInfluxV3WithRetry } from '../shared/utils.js';
|
||||
import { isInfluxDbEnabled, writeToInfluxWithRetry } from '../shared/utils.js';
|
||||
|
||||
/**
|
||||
* Post log event to InfluxDB v3
|
||||
@@ -195,9 +195,11 @@ export async function postLogEventToInfluxdbV3(msg) {
|
||||
}
|
||||
}
|
||||
|
||||
await writeToInfluxV3WithRetry(
|
||||
await writeToInfluxWithRetry(
|
||||
async () => await globals.influx.write(point.toLineProtocol(), database),
|
||||
`Log event for ${msg.host}`
|
||||
`Log event for ${msg.host}`,
|
||||
'v3',
|
||||
msg.host
|
||||
);
|
||||
|
||||
globals.logger.debug(`LOG EVENT INFLUXDB V3: Wrote data to InfluxDB v3`);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Point as Point3 } from '@influxdata/influxdb3-client';
|
||||
import globals from '../../../globals.js';
|
||||
import { isInfluxDbEnabled, writeToInfluxV3WithRetry } from '../shared/utils.js';
|
||||
import { isInfluxDbEnabled, writeToInfluxWithRetry } from '../shared/utils.js';
|
||||
|
||||
/**
|
||||
* Store user event queue metrics to InfluxDB v3
|
||||
@@ -77,9 +77,11 @@ export async function postUserEventQueueMetricsToInfluxdbV3() {
|
||||
}
|
||||
}
|
||||
|
||||
await writeToInfluxV3WithRetry(
|
||||
await writeToInfluxWithRetry(
|
||||
async () => await globals.influx.write(point.toLineProtocol(), database),
|
||||
'User event queue metrics'
|
||||
'User event queue metrics',
|
||||
'v3',
|
||||
'user-events-queue'
|
||||
);
|
||||
|
||||
globals.logger.verbose(
|
||||
@@ -168,9 +170,11 @@ export async function postLogEventQueueMetricsToInfluxdbV3() {
|
||||
}
|
||||
}
|
||||
|
||||
await writeToInfluxV3WithRetry(
|
||||
await writeToInfluxWithRetry(
|
||||
async () => await globals.influx.write(point.toLineProtocol(), database),
|
||||
'Log event queue metrics'
|
||||
'Log event queue metrics',
|
||||
'v3',
|
||||
'log-events-queue'
|
||||
);
|
||||
|
||||
globals.logger.verbose(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Point as Point3 } from '@influxdata/influxdb3-client';
|
||||
import globals from '../../../globals.js';
|
||||
import { isInfluxDbEnabled, writeToInfluxV3WithRetry } from '../shared/utils.js';
|
||||
import { isInfluxDbEnabled, writeToInfluxWithRetry } from '../shared/utils.js';
|
||||
|
||||
/**
|
||||
* Posts proxy sessions data to InfluxDB v3.
|
||||
@@ -40,9 +40,11 @@ export async function postProxySessionsToInfluxdbV3(userSessions) {
|
||||
try {
|
||||
if (userSessions.datapointInfluxdb && userSessions.datapointInfluxdb.length > 0) {
|
||||
for (const point of userSessions.datapointInfluxdb) {
|
||||
await writeToInfluxV3WithRetry(
|
||||
await writeToInfluxWithRetry(
|
||||
async () => await globals.influx.write(point.toLineProtocol(), database),
|
||||
`Proxy sessions for ${userSessions.host}/${userSessions.virtualProxy}`
|
||||
`Proxy sessions for ${userSessions.host}/${userSessions.virtualProxy}`,
|
||||
'v3',
|
||||
userSessions.host
|
||||
);
|
||||
}
|
||||
globals.logger.debug(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Point as Point3 } from '@influxdata/influxdb3-client';
|
||||
import globals from '../../../globals.js';
|
||||
import { isInfluxDbEnabled, writeToInfluxV3WithRetry } from '../shared/utils.js';
|
||||
import { isInfluxDbEnabled, writeToInfluxWithRetry } from '../shared/utils.js';
|
||||
|
||||
/**
|
||||
* Sanitize tag values for InfluxDB line protocol.
|
||||
@@ -100,9 +100,11 @@ export async function postUserEventToInfluxdbV3(msg) {
|
||||
// Write to InfluxDB
|
||||
try {
|
||||
// Convert point to line protocol and write directly with retry logic
|
||||
await writeToInfluxV3WithRetry(
|
||||
await writeToInfluxWithRetry(
|
||||
async () => await globals.influx.write(point.toLineProtocol(), database),
|
||||
`User event for ${msg.host}`
|
||||
`User event for ${msg.host}`,
|
||||
'v3',
|
||||
msg.host
|
||||
);
|
||||
globals.logger.debug(`USER EVENT INFLUXDB V3: Wrote data to InfluxDB v3`);
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user