Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions yarn-project/end-to-end/scripts/run_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ case "$type" in
-e BENCH_OUTPUT \
-e CAPTURE_IVC_FOLDER \
-e LOG_LEVEL \
-e COLLECT_METRICS \
--workdir "$repo_dir/yarn-project/end-to-end" \
aztecprotocol/build:3.0 ./scripts/test_simple.sh $TEST
;;
Expand Down
180 changes: 177 additions & 3 deletions yarn-project/telemetry-client/src/prom_otel_adapter.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { Logger } from '@aztec/foundation/log';
import { Timer } from '@aztec/foundation/timer';

import { jest } from '@jest/globals';

import { OtelGauge } from './prom_otel_adapter.js';
import type { Meter, ObservableGauge } from './telemetry.js';
import { OtelAvgMinMax, OtelGauge, OtelHistogram } from './prom_otel_adapter.js';
import type { Histogram, Meter, ObservableGauge } from './telemetry.js';

describe('OtelGauge', () => {
let mockLogger: Logger;
Expand Down Expand Up @@ -90,7 +91,7 @@ describe('OtelGauge', () => {
['region', 'instance'],
);

expect(() => otelGaugeWithLabels.inc(invalidLabelConfig as any, 1)).toThrowError('Invalid label key: invalid');
expect(() => otelGaugeWithLabels.inc(invalidLabelConfig as any, 1)).toThrow('Invalid label key: invalid');
expect(mockLogger.error).not.toHaveBeenCalled();
});

Expand All @@ -115,3 +116,176 @@ describe('OtelGauge', () => {
expect(mockResult.observe).toHaveBeenCalledWith(5, labelConfig);
});
});

describe('OtelHistogram', () => {
let mockLogger: Logger;
let mockMeter: Meter;
let mockHistogram: Histogram;
let otelHistogram: OtelHistogram<Record<string, never>>;

beforeEach(() => {
mockLogger = { info: jest.fn(), error: jest.fn(), warn: jest.fn(), silent: jest.fn() } as unknown as Logger;
mockHistogram = { record: jest.fn() } as unknown as Histogram;
mockMeter = { createHistogram: jest.fn(() => mockHistogram) } as unknown as Meter;

otelHistogram = new OtelHistogram(mockLogger, mockMeter, 'test_histogram', 'Test histogram');

jest.spyOn(Timer.prototype, 's').mockImplementation(function (this: Timer) {
return 100;
});
});

test('observes value without labels', () => {
otelHistogram.observe(5);
expect(mockHistogram.record).toHaveBeenCalledWith(5);
});

test('observes value with labels', () => {
const labelConfig = { topic: 'tx' };
const otelHistogramWithLabels = new OtelHistogram(
mockLogger,
mockMeter,
'test_histogram_with_labels',
'Test histogram with labels',
[],
['topic'],
);

otelHistogramWithLabels.observe(labelConfig, 10);
expect(mockHistogram.record).toHaveBeenCalledWith(10, labelConfig);
});

test('throws error for invalid labels', () => {
const invalidLabelConfig = { invalid: 'tx' };
const otelHistogramWithLabels = new OtelHistogram(
mockLogger,
mockMeter,
'test_histogram_with_labels',
'Test histogram with labels',
[],
['topic'],
);

expect(() => otelHistogramWithLabels.observe(invalidLabelConfig as any, 5)).toThrow('Invalid label key: invalid');
});

test('starts timer and records duration without labels', () => {
const timer = otelHistogram.startTimer();
timer();

expect(mockHistogram.record).toHaveBeenCalledWith(100);
});

test('starts timer and records duration with labels', () => {
const labelConfig1 = { topic: 'tx' };
const labelConfig2 = { topic: 'block_proposal' };
const otelHistogramWithLabels = new OtelHistogram(
mockLogger,
mockMeter,
'test_histogram_with_labels',
'Test histogram with labels',
[],
['topic'],
);

const timer1 = otelHistogramWithLabels.startTimer(labelConfig1);
timer1();

const timer2 = otelHistogramWithLabels.startTimer(labelConfig2);
timer2();

expect(mockHistogram.record).toHaveBeenCalledWith(100, labelConfig1);
expect(mockHistogram.record).toHaveBeenCalledWith(100, labelConfig2);
});
});

describe('OtelAvgMinMax', () => {
let mockLogger: Logger;
let mockMeter: Meter;
let mockAvgGauge: ObservableGauge;
let mockMinGauge: ObservableGauge;
let mockMaxGauge: ObservableGauge;
let otelAvgMinMax: OtelAvgMinMax<Record<string, never>>;

beforeEach(() => {
mockLogger = { info: jest.fn(), error: jest.fn(), warn: jest.fn() } as unknown as Logger;
mockAvgGauge = { addCallback: jest.fn() } as unknown as ObservableGauge;
mockMinGauge = { addCallback: jest.fn() } as unknown as ObservableGauge;
mockMaxGauge = { addCallback: jest.fn() } as unknown as ObservableGauge;
mockMeter = {
createObservableGauge: jest
.fn()
.mockReturnValueOnce(mockAvgGauge)
.mockReturnValueOnce(mockMinGauge)
.mockReturnValueOnce(mockMaxGauge),
} as unknown as Meter;
});

test('creates three gauges with correct names and descriptions', () => {
otelAvgMinMax = new OtelAvgMinMax(mockLogger, mockMeter, 'test_avgminmax', 'Test AvgMinMax');
expect(mockMeter.createObservableGauge).toHaveBeenCalledWith('test_avgminmax_avg', {
description: 'Test AvgMinMax (average)',
});
expect(mockMeter.createObservableGauge).toHaveBeenCalledWith('test_avgminmax_min', {
description: 'Test AvgMinMax (minimum)',
});
expect(mockMeter.createObservableGauge).toHaveBeenCalledWith('test_avgminmax_max', {
description: 'Test AvgMinMax (maximum)',
});
});

test('handles empty values array', () => {
otelAvgMinMax = new OtelAvgMinMax(mockLogger, mockMeter, 'test_avgminmax', 'Test AvgMinMax');
otelAvgMinMax.set([]);
expect(otelAvgMinMax['currentValues']).toEqual([]);

const mockResult = { observe: jest.fn() };
otelAvgMinMax['observeAvg'](mockResult);
expect(mockResult.observe).not.toHaveBeenCalled();
});

test('calculates aggregations for unlabeled values', () => {
otelAvgMinMax = new OtelAvgMinMax(mockLogger, mockMeter, 'test_avgminmax', 'Test AvgMinMax');
const values = [6, 1, 2];
otelAvgMinMax.set(values);

const mockResult = { observe: jest.fn() };

otelAvgMinMax['observeAvg'](mockResult);
expect(mockResult.observe).toHaveBeenCalledWith(3);

mockResult.observe.mockClear();
otelAvgMinMax['observeMin'](mockResult);
expect(mockResult.observe).toHaveBeenCalledWith(1);

mockResult.observe.mockClear();
otelAvgMinMax['observeMax'](mockResult);
expect(mockResult.observe).toHaveBeenCalledWith(6);
});

test('calculates aggregations for labeled values', () => {
const otelAvgMinMaxWithLabels = new OtelAvgMinMax(
mockLogger,
mockMeter,
'test_avgminmax_with_labels',
'Test AvgMinMax with labels',
['topic'],
);
const labelConfig = { topic: 'tx' };

otelAvgMinMaxWithLabels.set(labelConfig, [6, 1, 2]);

const mockResult = { observe: jest.fn() };

otelAvgMinMaxWithLabels['observeAvg'](mockResult);
expect(mockResult.observe).toHaveBeenCalledWith(3, labelConfig);

mockResult.observe.mockClear();
otelAvgMinMaxWithLabels['observeMin'](mockResult);
expect(mockResult.observe).toHaveBeenCalledWith(1, labelConfig);

mockResult.observe.mockClear();
otelAvgMinMaxWithLabels['observeMax'](mockResult);
expect(mockResult.observe).toHaveBeenCalledWith(6, labelConfig);
});
});
Loading
Loading