Prometheus: QueryEditor fix error when switching from code to builder for undefined aggregation operations (#110179)
* convert stddev to function instead of aggregation * adds missing stdvar, limitK and limit_ratio agg functions * add tests
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
import { getAggregationOperations } from './aggregations';
|
||||
import { QueryBuilderOperation } from './shared/types';
|
||||
import { PromOperationId } from './types';
|
||||
|
||||
describe('getAggregationOperations', () => {
|
||||
it('returns a list containing all aggregation IDs', () => {
|
||||
const ops = getAggregationOperations();
|
||||
const ids = ops.map((o) => o.id);
|
||||
|
||||
expect(ids).toContain(PromOperationId.Sum);
|
||||
expect(ids).toContain(PromOperationId.Avg);
|
||||
expect(ids).toContain(PromOperationId.Min);
|
||||
expect(ids).toContain(PromOperationId.Max);
|
||||
expect(ids).toContain(PromOperationId.Count);
|
||||
expect(ids).toContain(PromOperationId.Group);
|
||||
expect(ids).toContain(PromOperationId.Stddev);
|
||||
expect(ids).toContain(PromOperationId.Stdvar);
|
||||
|
||||
// aggregations with params
|
||||
expect(ids).toContain(PromOperationId.TopK);
|
||||
expect(ids).toContain(PromOperationId.BottomK);
|
||||
expect(ids).toContain(PromOperationId.CountValues);
|
||||
expect(ids).toContain(PromOperationId.Quantile);
|
||||
expect(ids).toContain(PromOperationId.LimitK);
|
||||
expect(ids).toContain(PromOperationId.LimitRatio);
|
||||
|
||||
// over-time range aggregations
|
||||
expect(ids).toContain(PromOperationId.SumOverTime);
|
||||
expect(ids).toContain(PromOperationId.AvgOverTime);
|
||||
expect(ids).toContain(PromOperationId.MinOverTime);
|
||||
expect(ids).toContain(PromOperationId.MaxOverTime);
|
||||
expect(ids).toContain(PromOperationId.CountOverTime);
|
||||
expect(ids).toContain(PromOperationId.LastOverTime);
|
||||
expect(ids).toContain(PromOperationId.PresentOverTime);
|
||||
expect(ids).toContain(PromOperationId.AbsentOverTime);
|
||||
expect(ids).toContain(PromOperationId.StddevOverTime);
|
||||
});
|
||||
|
||||
it('includes over-time range functions with correct renderer behavior', () => {
|
||||
const ops = getAggregationOperations();
|
||||
const sumOverTime = ops.find((o) => o.id === PromOperationId.SumOverTime)!;
|
||||
expect(sumOverTime).toBeDefined();
|
||||
expect(sumOverTime.params.length).toBeGreaterThan(0);
|
||||
|
||||
// call renderer with default param
|
||||
const model: QueryBuilderOperation = { id: sumOverTime.id, params: sumOverTime.defaultParams };
|
||||
const rendered = sumOverTime.renderer(model, sumOverTime, 'metric');
|
||||
expect(rendered).toBe(`${PromOperationId.SumOverTime}(metric[$__interval])`);
|
||||
|
||||
// call renderer with custom param
|
||||
const modelCustom: QueryBuilderOperation = { id: sumOverTime.id, params: ['5m'] };
|
||||
const renderedCustom = sumOverTime.renderer(modelCustom, sumOverTime, 'metric');
|
||||
expect(renderedCustom).toBe(`${PromOperationId.SumOverTime}(metric[5m])`);
|
||||
});
|
||||
});
|
||||
@@ -17,6 +17,8 @@ export function getAggregationOperations(): QueryBuilderOperationDef[] {
|
||||
...createAggregationOperation(PromOperationId.Max),
|
||||
...createAggregationOperation(PromOperationId.Count),
|
||||
...createAggregationOperation(PromOperationId.Group),
|
||||
...createAggregationOperation(PromOperationId.Stddev),
|
||||
...createAggregationOperation(PromOperationId.Stdvar),
|
||||
...createAggregationOperationWithParam(PromOperationId.TopK, {
|
||||
params: [{ name: 'K-value', type: 'number' }],
|
||||
defaultParams: [5],
|
||||
@@ -33,6 +35,14 @@ export function getAggregationOperations(): QueryBuilderOperationDef[] {
|
||||
params: [{ name: 'Value', type: 'number' }],
|
||||
defaultParams: [1],
|
||||
}),
|
||||
...createAggregationOperationWithParam(PromOperationId.LimitK, {
|
||||
params: [{ name: 'K-value', type: 'number' }],
|
||||
defaultParams: [5],
|
||||
}),
|
||||
...createAggregationOperationWithParam(PromOperationId.LimitRatio, {
|
||||
params: [{ name: 'Ratio', type: 'number' }],
|
||||
defaultParams: [1],
|
||||
}),
|
||||
createAggregationOverTime(PromOperationId.SumOverTime),
|
||||
createAggregationOverTime(PromOperationId.AvgOverTime),
|
||||
createAggregationOverTime(PromOperationId.MinOverTime),
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
import { getOperationDefinitions, addOperationWithRangeVector } from './operations';
|
||||
import { QueryBuilderOperation, VisualQueryModeller } from './shared/types';
|
||||
import { PromOperationId, PromVisualQuery } from './types';
|
||||
|
||||
describe('getOperationDefinitions', () => {
|
||||
it('returns a list containing operation IDs', () => {
|
||||
const ops = getOperationDefinitions();
|
||||
const ids = ops.map((o) => o.id);
|
||||
|
||||
expect(ids).toContain(PromOperationId.HistogramQuantile);
|
||||
expect(ids).toContain(PromOperationId.Rate);
|
||||
expect(ids).toContain(PromOperationId.PredictLinear);
|
||||
expect(ids).toContain(PromOperationId.QuantileOverTime);
|
||||
expect(ids).toContain(PromOperationId.LabelJoin);
|
||||
expect(ids).toContain(PromOperationId.Vector);
|
||||
});
|
||||
|
||||
it('range function renderer uses default and custom range vector params', () => {
|
||||
const ops = getOperationDefinitions();
|
||||
const rate = ops.find((o) => o.id === PromOperationId.Rate)!;
|
||||
|
||||
expect(rate).toBeDefined();
|
||||
|
||||
const modelDefault: QueryBuilderOperation = { id: rate.id, params: rate.defaultParams };
|
||||
const renderedDefault = rate.renderer(modelDefault, rate, 'metric');
|
||||
expect(renderedDefault).toBe(`${PromOperationId.Rate}(metric[$__rate_interval])`);
|
||||
|
||||
const modelCustom: QueryBuilderOperation = { id: rate.id, params: ['5m'] };
|
||||
const renderedCustom = rate.renderer(modelCustom, rate, 'metric');
|
||||
expect(renderedCustom).toBe(`${PromOperationId.Rate}(metric[5m])`);
|
||||
});
|
||||
|
||||
it('changeTypeHandler updates operation params when rate/interval default changes', () => {
|
||||
const ops = getOperationDefinitions();
|
||||
const doubleExp = ops.find((o) => o.id === PromOperationId.DoubleExponentialSmoothing)!;
|
||||
expect(doubleExp).toBeDefined();
|
||||
// simulate an operation currently using $__rate_interval
|
||||
const operation: QueryBuilderOperation = { id: doubleExp.id, params: ['$__rate_interval'] };
|
||||
|
||||
// create a new definition that uses $__interval instead
|
||||
const newDef = { ...doubleExp, defaultParams: ['$__interval'] };
|
||||
|
||||
if (doubleExp.changeTypeHandler) {
|
||||
const updated = doubleExp.changeTypeHandler(operation, newDef);
|
||||
expect(updated.params).toEqual(newDef.defaultParams);
|
||||
}
|
||||
});
|
||||
|
||||
it('addOperationWithRangeVector inserts a range op at the front of the query', () => {
|
||||
const ops = getOperationDefinitions();
|
||||
const changes = ops.find((o) => o.id === PromOperationId.Changes)!;
|
||||
const query: PromVisualQuery = { operations: [], metric: 'metric', labels: [] };
|
||||
const modeller = {} as VisualQueryModeller;
|
||||
|
||||
const result = addOperationWithRangeVector(changes, query, modeller);
|
||||
expect(result.operations[0].id).toBe(changes.id);
|
||||
});
|
||||
|
||||
it('vector renderer renders parameter as value', () => {
|
||||
const ops = getOperationDefinitions();
|
||||
const vector = ops.find((o) => o.id === PromOperationId.Vector)!;
|
||||
expect(vector).toBeDefined();
|
||||
|
||||
const model: QueryBuilderOperation = { id: vector.id, params: [42] };
|
||||
const rendered = vector.renderer(model, vector, '');
|
||||
expect(rendered).toBe(`${PromOperationId.Vector}(42)`);
|
||||
});
|
||||
});
|
||||
@@ -258,7 +258,6 @@ export function getOperationDefinitions(): QueryBuilderOperationDef[] {
|
||||
createFunction({ id: PromOperationId.Sort }),
|
||||
createFunction({ id: PromOperationId.SortDesc }),
|
||||
createFunction({ id: PromOperationId.Sqrt }),
|
||||
createFunction({ id: PromOperationId.Stddev }),
|
||||
createFunction({
|
||||
id: PromOperationId.Tan,
|
||||
category: PromVisualQueryOperationCategory.Trigonometric,
|
||||
|
||||
@@ -100,6 +100,8 @@ export enum PromOperationId {
|
||||
LabelReplace = 'label_replace',
|
||||
Last = 'last',
|
||||
LastOverTime = 'last_over_time',
|
||||
LimitK = 'limitk',
|
||||
LimitRatio = 'limit_ratio',
|
||||
Ln = 'ln',
|
||||
Log10 = 'log10',
|
||||
Log2 = 'log2',
|
||||
@@ -128,6 +130,7 @@ export enum PromOperationId {
|
||||
Sqrt = 'sqrt',
|
||||
Stddev = 'stddev',
|
||||
StddevOverTime = 'stddev_over_time',
|
||||
Stdvar = 'stdvar',
|
||||
Sum = 'sum',
|
||||
SumOverTime = 'sum_over_time',
|
||||
Tan = 'tan',
|
||||
|
||||
Reference in New Issue
Block a user