seraph-agent
Version:
An extremely lightweight, SRE autonomous AI agent for seamless integration with common observability tasks.
162 lines (161 loc) • 5.84 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
jest.mock('worker_threads', () => ({
isMainThread: false,
parentPort: {
on: jest.fn(),
},
workerData: {
config: {
serverApiKey: null,
llm: {
provider: 'gemini',
model: 'gemini-pro',
},
},
},
}));
jest.mock('../alerter');
jest.mock('../llm');
jest.mock('../metrics', () => ({
metrics: {
llmAnalysisLatency: {
startTimer: jest.fn(() => jest.fn()),
},
analysisErrors: {
inc: jest.fn(),
},
alertsTriggered: {
inc: jest.fn(),
},
},
}));
describe('Agent Worker', () => {
const mockAlerterClient = {
sendAlert: jest.fn(),
};
const mockLlmProvider = {
generate: jest.fn(),
};
let consoleLogSpy;
let consoleErrorSpy;
beforeEach(() => {
consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => { });
consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
jest.resetModules();
jest.mock('worker_threads', () => ({
isMainThread: false,
parentPort: {
on: jest.fn(),
postMessage: jest.fn(),
},
workerData: {
config: {
serverApiKey: null,
llm: {
provider: 'gemini',
model: 'gemini-pro',
},
},
},
}));
jest.mock('../alerter');
jest.mock('../llm');
jest.mock('../metrics', () => ({
metrics: {
llmAnalysisLatency: {
startTimer: jest.fn(() => jest.fn()),
},
analysisErrors: {
inc: jest.fn(),
},
alertsTriggered: {
inc: jest.fn(),
},
},
}));
const { AlerterClient } = require('../alerter');
const { createLLMProvider } = require('../llm');
createLLMProvider.mockReturnValue(mockLlmProvider);
AlerterClient.mockReturnValue(mockAlerterClient);
require('../agent');
});
afterEach(() => {
jest.clearAllMocks();
consoleLogSpy.mockRestore();
consoleErrorSpy.mockRestore();
});
it('should analyze a log and send an alert if the decision is "alert"', async () => {
const { parentPort } = require('worker_threads');
const { metrics } = require('../metrics');
const log = 'this is an error log';
const analysis = { decision: 'alert', reason: 'it is an error' };
mockLlmProvider.generate.mockResolvedValue(JSON.stringify(analysis));
if (!parentPort) {
throw new Error('parentPort is null');
}
const messageHandler = parentPort.on.mock.calls[0][1];
await messageHandler(log);
expect(mockLlmProvider.generate).toHaveBeenCalled();
expect(metrics.alertsTriggered.inc).toHaveBeenCalled();
expect(mockAlerterClient.sendAlert).toHaveBeenCalledWith({
source: 'log_analysis',
type: 'anomaly_detected',
details: analysis.reason,
log: log,
});
});
it('should handle errors from the LLM provider', async () => {
const { parentPort } = require('worker_threads');
const { metrics } = require('../metrics');
const log = 'this is a problematic log';
const error = new Error('LLM failed');
mockLlmProvider.generate.mockRejectedValue(error);
if (!parentPort) {
throw new Error('parentPort is null');
}
const messageHandler = parentPort.on.mock.calls[0][1];
await messageHandler(log);
expect(metrics.analysisErrors.inc).toHaveBeenCalled();
expect(mockAlerterClient.sendAlert).toHaveBeenCalledWith({
source: 'log_analysis_error',
type: 'analysis_failed',
details: error.message,
log: log,
});
});
it('should handle malformed JSON from the LLM provider', async () => {
const { parentPort } = require('worker_threads');
const { metrics } = require('../metrics');
const log = 'this is another log';
mockLlmProvider.generate.mockResolvedValue('this is not json');
if (!parentPort) {
throw new Error('parentPort is null');
}
const messageHandler = parentPort.on.mock.calls[0][1];
await messageHandler(log);
expect(metrics.analysisErrors.inc).toHaveBeenCalled();
expect(mockAlerterClient.sendAlert).toHaveBeenCalled();
});
it('should handle markdown-wrapped JSON from the LLM provider', async () => {
const { parentPort } = require('worker_threads');
const { metrics } = require('../metrics');
const log = 'this is a log that will be wrapped';
const analysis = { decision: 'alert', reason: 'it is an error' };
const markdownResponse = '```json\n' + JSON.stringify(analysis, null, 2) + '\n```';
mockLlmProvider.generate.mockResolvedValue(markdownResponse);
if (!parentPort) {
throw new Error('parentPort is null');
}
const messageHandler = parentPort.on.mock.calls[0][1];
await messageHandler(log);
expect(mockLlmProvider.generate).toHaveBeenCalled();
expect(metrics.alertsTriggered.inc).toHaveBeenCalled();
expect(mockAlerterClient.sendAlert).toHaveBeenCalledWith({
source: 'log_analysis',
type: 'anomaly_detected',
details: analysis.reason,
log: log,
});
});
});