From 5c2f823aa702fc6bf085110e72005c334c26d8f9 Mon Sep 17 00:00:00 2001 From: Nick Richmond Date: Fri, 1 Mar 2024 17:34:26 -0500 Subject: [PATCH 01/10] fix: avoid float point precision errors in heatmaps --- .../app/plugins/datasource/prometheus/result_transformer.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/public/app/plugins/datasource/prometheus/result_transformer.ts b/public/app/plugins/datasource/prometheus/result_transformer.ts index 0fbcfe58806f..2e556cb8c38e 100644 --- a/public/app/plugins/datasource/prometheus/result_transformer.ts +++ b/public/app/plugins/datasource/prometheus/result_transformer.ts @@ -377,6 +377,10 @@ function transformToHistogramOverTime(seriesList: DataFrame[]) { for (let j = 0; j < topSeries.values.length; j++) { const bottomPoint = bottomSeries.values[j] || [0]; topSeries.values[j] -= bottomPoint; + + if (topSeries.values[j] < 1e-9) { + topSeries.values[j] = 0; + } } } From 07bbbfc415cf323594d832989b0226f2e707b98c Mon Sep 17 00:00:00 2001 From: Nick Richmond Date: Mon, 4 Mar 2024 13:32:54 -0500 Subject: [PATCH 02/10] refactor: add explicit return type for clarity --- public/app/plugins/datasource/prometheus/result_transformer.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/plugins/datasource/prometheus/result_transformer.ts b/public/app/plugins/datasource/prometheus/result_transformer.ts index 2e556cb8c38e..8111e34cc7eb 100644 --- a/public/app/plugins/datasource/prometheus/result_transformer.ts +++ b/public/app/plugins/datasource/prometheus/result_transformer.ts @@ -359,7 +359,7 @@ function mergeHeatmapFrames(frames: DataFrame[]): DataFrame[] { ]; } -function transformToHistogramOverTime(seriesList: DataFrame[]) { +function transformToHistogramOverTime(seriesList: DataFrame[]): DataFrame[] { /* t1 = timestamp1, t2 = timestamp2 etc. t1 t2 t3 t1 t2 t3 le10 10 10 0 => 10 10 0 From f49b68b0ca8636ff7b15653293bd70a70c05315d Mon Sep 17 00:00:00 2001 From: Nick Richmond Date: Mon, 4 Mar 2024 13:49:06 -0500 Subject: [PATCH 03/10] test: floating point errors in native histograms --- .../prometheus/result_transformer.test.ts | 79 ++++++++++++++++++- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/public/app/plugins/datasource/prometheus/result_transformer.test.ts b/public/app/plugins/datasource/prometheus/result_transformer.test.ts index 62ce599eaa6c..f60a5823bd0d 100644 --- a/public/app/plugins/datasource/prometheus/result_transformer.test.ts +++ b/public/app/plugins/datasource/prometheus/result_transformer.test.ts @@ -1,10 +1,11 @@ import { cacheFieldDisplayNames, createDataFrame, - DataQueryRequest, - DataQueryResponse, FieldType, - PreferredVisualisationType, + type DataFrame, + type DataQueryRequest, + type DataQueryResponse, + type PreferredVisualisationType, } from '@grafana/data'; import { parseSampleValue, sortSeriesByLabel, transformDFToTable, transformV2 } from './result_transformer'; @@ -404,6 +405,7 @@ describe('Prometheus Result Transformer', () => { expect(series.data[0].fields[2].name).toEqual('2'); expect(series.data[0].fields[3].name).toEqual('+Inf'); }); + it('results with heatmap format (with metric name) should be correctly transformed', () => { const options = { targets: [ @@ -925,6 +927,77 @@ describe('Prometheus Result Transformer', () => { expect(traceField).toBeDefined(); expect(traceField!.config.links?.length).toBe(0); }); + + it('should convert values less than 1e-9 to 0', () => { + const options = { + targets: [ + { + format: 'heatmap', + refId: 'A', + }, + ], + } as unknown as DataQueryRequest; + const response = { + state: 'Done', + data: [ + createDataFrame({ + refId: 'A', + fields: [ + { name: 'Time', type: FieldType.time, values: [6, 5, 4] }, + { + name: 'Value', + type: FieldType.number, + values: [10, 10, 0], + labels: { le: '1' }, + }, + ], + }), + createDataFrame({ + refId: 'A', + fields: [ + { name: 'Time', type: FieldType.time, values: [6, 5, 4] }, + { + name: 'Value', + type: FieldType.number, + values: [20, 10, 30], + labels: { le: '2' }, + }, + ], + }), + createDataFrame({ + refId: 'A', + fields: [ + { name: 'Time', type: FieldType.time, values: [6, 5, 4] }, + { + name: 'Value', + type: FieldType.number, + values: [30, 10, 40], + labels: { le: '+Inf' }, + }, + ], + }), + ], + } as unknown as DataQueryResponse & { data: DataFrame[] }; + + // Create a situation where the series subtraction in histogram transformation results in a value less than 1e-9 + response.data[1].fields[1].values[1] += 0.0000000001; + response.data[2].fields[1].values[1] += 0.00000000015; + + const series = transformV2(response, options, {}); + + expect( + series.data + .at(0) + ?.fields.find((field) => field.name === '2') + ?.values.at(1) + ).toBe(0); + expect( + series.data + .at(0) + ?.fields.find((field) => field.name === '+Inf') + ?.values.at(1) + ).toBe(0); + }); }); describe('transformDFToTable', () => { From 2edb9d7475822c78098aad572db47f28992f739b Mon Sep 17 00:00:00 2001 From: Nick Richmond Date: Mon, 4 Mar 2024 13:57:45 -0500 Subject: [PATCH 04/10] test: error handling --- .../prometheus/result_transformer.test.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/public/app/plugins/datasource/prometheus/result_transformer.test.ts b/public/app/plugins/datasource/prometheus/result_transformer.test.ts index f60a5823bd0d..5718ceb2d503 100644 --- a/public/app/plugins/datasource/prometheus/result_transformer.test.ts +++ b/public/app/plugins/datasource/prometheus/result_transformer.test.ts @@ -998,6 +998,27 @@ describe('Prometheus Result Transformer', () => { ?.values.at(1) ).toBe(0); }); + + it('should throw an error if the series does not contain number-type values', () => { + const response = { + state: 'Done', + data: [ + ['10', '10', '0'], + ['20', '10', '30'], + ['20', '10', '35'], + ].map((values) => createDataFrame({ refId: 'A', fields: [{ name: 'Value', type: FieldType.string, values }] })), + } as unknown as DataQueryResponse; + const request = { + targets: [ + { + format: 'heatmap', + refId: 'A', + }, + ], + } as unknown as DataQueryRequest; + + expect(() => transformV2(response, request, {})).toThrow(); + }); }); describe('transformDFToTable', () => { From e385d4c6238afbf1bd79e83af8731c57ca3215ba Mon Sep 17 00:00:00 2001 From: Nick Richmond Date: Mon, 4 Mar 2024 14:28:42 -0500 Subject: [PATCH 05/10] fix: mirror changes in Prometheus library --- .../src/result_transformer.test.ts | 100 +++++++++++++++++- .../src/result_transformer.ts | 6 +- 2 files changed, 102 insertions(+), 4 deletions(-) diff --git a/packages/grafana-prometheus/src/result_transformer.test.ts b/packages/grafana-prometheus/src/result_transformer.test.ts index 62ce599eaa6c..5718ceb2d503 100644 --- a/packages/grafana-prometheus/src/result_transformer.test.ts +++ b/packages/grafana-prometheus/src/result_transformer.test.ts @@ -1,10 +1,11 @@ import { cacheFieldDisplayNames, createDataFrame, - DataQueryRequest, - DataQueryResponse, FieldType, - PreferredVisualisationType, + type DataFrame, + type DataQueryRequest, + type DataQueryResponse, + type PreferredVisualisationType, } from '@grafana/data'; import { parseSampleValue, sortSeriesByLabel, transformDFToTable, transformV2 } from './result_transformer'; @@ -404,6 +405,7 @@ describe('Prometheus Result Transformer', () => { expect(series.data[0].fields[2].name).toEqual('2'); expect(series.data[0].fields[3].name).toEqual('+Inf'); }); + it('results with heatmap format (with metric name) should be correctly transformed', () => { const options = { targets: [ @@ -925,6 +927,98 @@ describe('Prometheus Result Transformer', () => { expect(traceField).toBeDefined(); expect(traceField!.config.links?.length).toBe(0); }); + + it('should convert values less than 1e-9 to 0', () => { + const options = { + targets: [ + { + format: 'heatmap', + refId: 'A', + }, + ], + } as unknown as DataQueryRequest; + const response = { + state: 'Done', + data: [ + createDataFrame({ + refId: 'A', + fields: [ + { name: 'Time', type: FieldType.time, values: [6, 5, 4] }, + { + name: 'Value', + type: FieldType.number, + values: [10, 10, 0], + labels: { le: '1' }, + }, + ], + }), + createDataFrame({ + refId: 'A', + fields: [ + { name: 'Time', type: FieldType.time, values: [6, 5, 4] }, + { + name: 'Value', + type: FieldType.number, + values: [20, 10, 30], + labels: { le: '2' }, + }, + ], + }), + createDataFrame({ + refId: 'A', + fields: [ + { name: 'Time', type: FieldType.time, values: [6, 5, 4] }, + { + name: 'Value', + type: FieldType.number, + values: [30, 10, 40], + labels: { le: '+Inf' }, + }, + ], + }), + ], + } as unknown as DataQueryResponse & { data: DataFrame[] }; + + // Create a situation where the series subtraction in histogram transformation results in a value less than 1e-9 + response.data[1].fields[1].values[1] += 0.0000000001; + response.data[2].fields[1].values[1] += 0.00000000015; + + const series = transformV2(response, options, {}); + + expect( + series.data + .at(0) + ?.fields.find((field) => field.name === '2') + ?.values.at(1) + ).toBe(0); + expect( + series.data + .at(0) + ?.fields.find((field) => field.name === '+Inf') + ?.values.at(1) + ).toBe(0); + }); + + it('should throw an error if the series does not contain number-type values', () => { + const response = { + state: 'Done', + data: [ + ['10', '10', '0'], + ['20', '10', '30'], + ['20', '10', '35'], + ].map((values) => createDataFrame({ refId: 'A', fields: [{ name: 'Value', type: FieldType.string, values }] })), + } as unknown as DataQueryResponse; + const request = { + targets: [ + { + format: 'heatmap', + refId: 'A', + }, + ], + } as unknown as DataQueryRequest; + + expect(() => transformV2(response, request, {})).toThrow(); + }); }); describe('transformDFToTable', () => { diff --git a/packages/grafana-prometheus/src/result_transformer.ts b/packages/grafana-prometheus/src/result_transformer.ts index 0fbcfe58806f..8111e34cc7eb 100644 --- a/packages/grafana-prometheus/src/result_transformer.ts +++ b/packages/grafana-prometheus/src/result_transformer.ts @@ -359,7 +359,7 @@ function mergeHeatmapFrames(frames: DataFrame[]): DataFrame[] { ]; } -function transformToHistogramOverTime(seriesList: DataFrame[]) { +function transformToHistogramOverTime(seriesList: DataFrame[]): DataFrame[] { /* t1 = timestamp1, t2 = timestamp2 etc. t1 t2 t3 t1 t2 t3 le10 10 10 0 => 10 10 0 @@ -377,6 +377,10 @@ function transformToHistogramOverTime(seriesList: DataFrame[]) { for (let j = 0; j < topSeries.values.length; j++) { const bottomPoint = bottomSeries.values[j] || [0]; topSeries.values[j] -= bottomPoint; + + if (topSeries.values[j] < 1e-9) { + topSeries.values[j] = 0; + } } } From 6176cd54e7794ceefe01b3c9250aad4504810e09 Mon Sep 17 00:00:00 2001 From: Nick Richmond Date: Mon, 4 Mar 2024 16:21:35 -0500 Subject: [PATCH 06/10] test: for now, remove extra tests --- .../src/result_transformer.test.ts | 21 ------------------- .../prometheus/result_transformer.test.ts | 21 ------------------- 2 files changed, 42 deletions(-) diff --git a/packages/grafana-prometheus/src/result_transformer.test.ts b/packages/grafana-prometheus/src/result_transformer.test.ts index 5718ceb2d503..f60a5823bd0d 100644 --- a/packages/grafana-prometheus/src/result_transformer.test.ts +++ b/packages/grafana-prometheus/src/result_transformer.test.ts @@ -998,27 +998,6 @@ describe('Prometheus Result Transformer', () => { ?.values.at(1) ).toBe(0); }); - - it('should throw an error if the series does not contain number-type values', () => { - const response = { - state: 'Done', - data: [ - ['10', '10', '0'], - ['20', '10', '30'], - ['20', '10', '35'], - ].map((values) => createDataFrame({ refId: 'A', fields: [{ name: 'Value', type: FieldType.string, values }] })), - } as unknown as DataQueryResponse; - const request = { - targets: [ - { - format: 'heatmap', - refId: 'A', - }, - ], - } as unknown as DataQueryRequest; - - expect(() => transformV2(response, request, {})).toThrow(); - }); }); describe('transformDFToTable', () => { diff --git a/public/app/plugins/datasource/prometheus/result_transformer.test.ts b/public/app/plugins/datasource/prometheus/result_transformer.test.ts index 5718ceb2d503..f60a5823bd0d 100644 --- a/public/app/plugins/datasource/prometheus/result_transformer.test.ts +++ b/public/app/plugins/datasource/prometheus/result_transformer.test.ts @@ -998,27 +998,6 @@ describe('Prometheus Result Transformer', () => { ?.values.at(1) ).toBe(0); }); - - it('should throw an error if the series does not contain number-type values', () => { - const response = { - state: 'Done', - data: [ - ['10', '10', '0'], - ['20', '10', '30'], - ['20', '10', '35'], - ].map((values) => createDataFrame({ refId: 'A', fields: [{ name: 'Value', type: FieldType.string, values }] })), - } as unknown as DataQueryResponse; - const request = { - targets: [ - { - format: 'heatmap', - refId: 'A', - }, - ], - } as unknown as DataQueryRequest; - - expect(() => transformV2(response, request, {})).toThrow(); - }); }); describe('transformDFToTable', () => { From fab9a3a2cf4b06e7730c099d7b37415c70930d95 Mon Sep 17 00:00:00 2001 From: Nick Richmond Date: Mon, 4 Mar 2024 16:37:21 -0500 Subject: [PATCH 07/10] test: error handling --- .../src/result_transformer.test.ts | 29 +++++++++++++++++++ .../prometheus/result_transformer.test.ts | 29 +++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/packages/grafana-prometheus/src/result_transformer.test.ts b/packages/grafana-prometheus/src/result_transformer.test.ts index f60a5823bd0d..5f74800c3967 100644 --- a/packages/grafana-prometheus/src/result_transformer.test.ts +++ b/packages/grafana-prometheus/src/result_transformer.test.ts @@ -998,6 +998,35 @@ describe('Prometheus Result Transformer', () => { ?.values.at(1) ).toBe(0); }); + + it('should throw an error if the series does not contain number-type values', () => { + const response = { + state: 'Done', + data: [ + ['10', '10', '0'], + ['20', '10', '30'], + ['20', '10', '35'], + ].map((values) => + createDataFrame({ + refId: 'A', + fields: [ + { name: 'Time', type: FieldType.time, values: [6, 5, 4] }, + { name: 'Value', type: FieldType.string, values }, + ], + }) + ), + } as unknown as DataQueryResponse; + const request = { + targets: [ + { + format: 'heatmap', + refId: 'A', + }, + ], + } as unknown as DataQueryRequest; + + expect(() => transformV2(response, request, {})).toThrow(); + }); }); describe('transformDFToTable', () => { diff --git a/public/app/plugins/datasource/prometheus/result_transformer.test.ts b/public/app/plugins/datasource/prometheus/result_transformer.test.ts index f60a5823bd0d..5f74800c3967 100644 --- a/public/app/plugins/datasource/prometheus/result_transformer.test.ts +++ b/public/app/plugins/datasource/prometheus/result_transformer.test.ts @@ -998,6 +998,35 @@ describe('Prometheus Result Transformer', () => { ?.values.at(1) ).toBe(0); }); + + it('should throw an error if the series does not contain number-type values', () => { + const response = { + state: 'Done', + data: [ + ['10', '10', '0'], + ['20', '10', '30'], + ['20', '10', '35'], + ].map((values) => + createDataFrame({ + refId: 'A', + fields: [ + { name: 'Time', type: FieldType.time, values: [6, 5, 4] }, + { name: 'Value', type: FieldType.string, values }, + ], + }) + ), + } as unknown as DataQueryResponse; + const request = { + targets: [ + { + format: 'heatmap', + refId: 'A', + }, + ], + } as unknown as DataQueryRequest; + + expect(() => transformV2(response, request, {})).toThrow(); + }); }); describe('transformDFToTable', () => { From 13b348b68bcbcd47c3fe1c769e0f9ed30352829f Mon Sep 17 00:00:00 2001 From: Leon Sorokin Date: Thu, 14 Mar 2024 19:23:19 -0500 Subject: [PATCH 08/10] update to real world test --- .../src/result_transformer.test.ts | 122 ++++++++---------- .../src/result_transformer.ts | 3 +- 2 files changed, 57 insertions(+), 68 deletions(-) diff --git a/packages/grafana-prometheus/src/result_transformer.test.ts b/packages/grafana-prometheus/src/result_transformer.test.ts index 5f74800c3967..4a986071827d 100644 --- a/packages/grafana-prometheus/src/result_transformer.test.ts +++ b/packages/grafana-prometheus/src/result_transformer.test.ts @@ -2,13 +2,18 @@ import { cacheFieldDisplayNames, createDataFrame, FieldType, - type DataFrame, type DataQueryRequest, type DataQueryResponse, type PreferredVisualisationType, } from '@grafana/data'; -import { parseSampleValue, sortSeriesByLabel, transformDFToTable, transformV2 } from './result_transformer'; +import { + parseSampleValue, + sortSeriesByLabel, + transformDFToTable, + transformToHistogramOverTime, + transformV2, +} from './result_transformer'; import { PromQuery } from './types'; jest.mock('@grafana/runtime', () => ({ @@ -929,74 +934,57 @@ describe('Prometheus Result Transformer', () => { }); it('should convert values less than 1e-9 to 0', () => { - const options = { - targets: [ - { - format: 'heatmap', - refId: 'A', - }, - ], - } as unknown as DataQueryRequest; - const response = { - state: 'Done', - data: [ - createDataFrame({ - refId: 'A', - fields: [ - { name: 'Time', type: FieldType.time, values: [6, 5, 4] }, - { - name: 'Value', - type: FieldType.number, - values: [10, 10, 0], - labels: { le: '1' }, - }, - ], - }), - createDataFrame({ - refId: 'A', - fields: [ - { name: 'Time', type: FieldType.time, values: [6, 5, 4] }, - { - name: 'Value', - type: FieldType.number, - values: [20, 10, 30], - labels: { le: '2' }, - }, - ], - }), - createDataFrame({ - refId: 'A', - fields: [ - { name: 'Time', type: FieldType.time, values: [6, 5, 4] }, - { - name: 'Value', - type: FieldType.number, - values: [30, 10, 40], - labels: { le: '+Inf' }, - }, - ], - }), - ], - } as unknown as DataQueryResponse & { data: DataFrame[] }; + // pulled from real response + let bucketValues = [ + [0.22222222222222218, 0.24444444444444444, 0.19999999999999996], // le=0.005 + [0.39999999999999997, 0.44444444444444436, 0.42222222222222217], + [0.3999999999999999, 0.44444444444444436, 0.42222222222222217], + [0.3999999999999999, 0.44444444444444436, 0.42222222222222217], + [0.3999999999999999, 0.44444444444444436, 0.42222222222222217], + [0.3999999999999999, 0.44444444444444436, 0.42222222222222217], + [0.39999999999999997, 0.44444444444444436, 0.42222222222222217], + [0.39999999999999997, 0.44444444444444436, 0.42222222222222217], + [0.3999999999999999, 0.44444444444444436, 0.42222222222222217], + [0.3999999999999999, 0.44444444444444436, 0.42222222222222217], + [0.3999999999999999, 0.44444444444444436, 0.42222222222222217], + [0.4666666666666666, 0.5111111111111111, 0.4888888888888888], + [0.4666666666666666, 0.5111111111111111, 0.4888888888888888], + [0.46666666666666656, 0.5111111111111111, 0.4888888888888888], + [0.46666666666666656, 0.5111111111111111, 0.4888888888888888], // le=+Inf + ]; - // Create a situation where the series subtraction in histogram transformation results in a value less than 1e-9 - response.data[1].fields[1].values[1] += 0.0000000001; - response.data[2].fields[1].values[1] += 0.00000000015; + const frames = bucketValues.map((vals) => + createDataFrame({ + refId: 'A', + fields: [ + { type: FieldType.time, values: [1, 2, 3] }, + { + type: FieldType.number, + values: vals.slice(), + }, + ], + }) + ); - const series = transformV2(response, options, {}); + const fieldValues = transformToHistogramOverTime(frames).map((frame) => frame.fields[1].values); - expect( - series.data - .at(0) - ?.fields.find((field) => field.name === '2') - ?.values.at(1) - ).toBe(0); - expect( - series.data - .at(0) - ?.fields.find((field) => field.name === '+Inf') - ?.values.at(1) - ).toBe(0); + expect(fieldValues).toEqual([ + [0.22222222222222218, 0.24444444444444444, 0.19999999999999996], + [0.17777777777777778, 0.19999999999999993, 0.2222222222222222], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [0.06666666666666671, 0.06666666666666671, 0.06666666666666665], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + ]); }); it('should throw an error if the series does not contain number-type values', () => { diff --git a/packages/grafana-prometheus/src/result_transformer.ts b/packages/grafana-prometheus/src/result_transformer.ts index 8111e34cc7eb..ac93f7955a84 100644 --- a/packages/grafana-prometheus/src/result_transformer.ts +++ b/packages/grafana-prometheus/src/result_transformer.ts @@ -359,7 +359,8 @@ function mergeHeatmapFrames(frames: DataFrame[]): DataFrame[] { ]; } -function transformToHistogramOverTime(seriesList: DataFrame[]): DataFrame[] { +/** @internal */ +export function transformToHistogramOverTime(seriesList: DataFrame[]): DataFrame[] { /* t1 = timestamp1, t2 = timestamp2 etc. t1 t2 t3 t1 t2 t3 le10 10 10 0 => 10 10 0 From be2745f82fdd8394cf4132039c0f28becfb86e76 Mon Sep 17 00:00:00 2001 From: Leon Sorokin Date: Thu, 14 Mar 2024 19:28:10 -0500 Subject: [PATCH 09/10] update other test --- .../prometheus/result_transformer.test.ts | 115 ++++++++---------- 1 file changed, 49 insertions(+), 66 deletions(-) diff --git a/public/app/plugins/datasource/prometheus/result_transformer.test.ts b/public/app/plugins/datasource/prometheus/result_transformer.test.ts index 5f74800c3967..045add80b2cc 100644 --- a/public/app/plugins/datasource/prometheus/result_transformer.test.ts +++ b/public/app/plugins/datasource/prometheus/result_transformer.test.ts @@ -2,11 +2,11 @@ import { cacheFieldDisplayNames, createDataFrame, FieldType, - type DataFrame, type DataQueryRequest, type DataQueryResponse, type PreferredVisualisationType, } from '@grafana/data'; +import { transformToHistogramOverTime } from '@grafana/prometheus/src/result_transformer'; import { parseSampleValue, sortSeriesByLabel, transformDFToTable, transformV2 } from './result_transformer'; import { PromQuery } from './types'; @@ -929,74 +929,57 @@ describe('Prometheus Result Transformer', () => { }); it('should convert values less than 1e-9 to 0', () => { - const options = { - targets: [ - { - format: 'heatmap', - refId: 'A', - }, - ], - } as unknown as DataQueryRequest; - const response = { - state: 'Done', - data: [ - createDataFrame({ - refId: 'A', - fields: [ - { name: 'Time', type: FieldType.time, values: [6, 5, 4] }, - { - name: 'Value', - type: FieldType.number, - values: [10, 10, 0], - labels: { le: '1' }, - }, - ], - }), - createDataFrame({ - refId: 'A', - fields: [ - { name: 'Time', type: FieldType.time, values: [6, 5, 4] }, - { - name: 'Value', - type: FieldType.number, - values: [20, 10, 30], - labels: { le: '2' }, - }, - ], - }), - createDataFrame({ - refId: 'A', - fields: [ - { name: 'Time', type: FieldType.time, values: [6, 5, 4] }, - { - name: 'Value', - type: FieldType.number, - values: [30, 10, 40], - labels: { le: '+Inf' }, - }, - ], - }), - ], - } as unknown as DataQueryResponse & { data: DataFrame[] }; + // pulled from real response + let bucketValues = [ + [0.22222222222222218, 0.24444444444444444, 0.19999999999999996], // le=0.005 + [0.39999999999999997, 0.44444444444444436, 0.42222222222222217], + [0.3999999999999999, 0.44444444444444436, 0.42222222222222217], + [0.3999999999999999, 0.44444444444444436, 0.42222222222222217], + [0.3999999999999999, 0.44444444444444436, 0.42222222222222217], + [0.3999999999999999, 0.44444444444444436, 0.42222222222222217], + [0.39999999999999997, 0.44444444444444436, 0.42222222222222217], + [0.39999999999999997, 0.44444444444444436, 0.42222222222222217], + [0.3999999999999999, 0.44444444444444436, 0.42222222222222217], + [0.3999999999999999, 0.44444444444444436, 0.42222222222222217], + [0.3999999999999999, 0.44444444444444436, 0.42222222222222217], + [0.4666666666666666, 0.5111111111111111, 0.4888888888888888], + [0.4666666666666666, 0.5111111111111111, 0.4888888888888888], + [0.46666666666666656, 0.5111111111111111, 0.4888888888888888], + [0.46666666666666656, 0.5111111111111111, 0.4888888888888888], // le=+Inf + ]; - // Create a situation where the series subtraction in histogram transformation results in a value less than 1e-9 - response.data[1].fields[1].values[1] += 0.0000000001; - response.data[2].fields[1].values[1] += 0.00000000015; + const frames = bucketValues.map((vals) => + createDataFrame({ + refId: 'A', + fields: [ + { type: FieldType.time, values: [1, 2, 3] }, + { + type: FieldType.number, + values: vals.slice(), + }, + ], + }) + ); - const series = transformV2(response, options, {}); + const fieldValues = transformToHistogramOverTime(frames).map((frame) => frame.fields[1].values); - expect( - series.data - .at(0) - ?.fields.find((field) => field.name === '2') - ?.values.at(1) - ).toBe(0); - expect( - series.data - .at(0) - ?.fields.find((field) => field.name === '+Inf') - ?.values.at(1) - ).toBe(0); + expect(fieldValues).toEqual([ + [0.22222222222222218, 0.24444444444444444, 0.19999999999999996], + [0.17777777777777778, 0.19999999999999993, 0.2222222222222222], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + [0.06666666666666671, 0.06666666666666671, 0.06666666666666665], + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + ]); }); it('should throw an error if the series does not contain number-type values', () => { From 184f6be94d15894d041f91ae74085980411680a5 Mon Sep 17 00:00:00 2001 From: Leon Sorokin Date: Thu, 14 Mar 2024 19:33:51 -0500 Subject: [PATCH 10/10] const --- packages/grafana-prometheus/src/result_transformer.test.ts | 2 +- .../plugins/datasource/prometheus/result_transformer.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grafana-prometheus/src/result_transformer.test.ts b/packages/grafana-prometheus/src/result_transformer.test.ts index 4a986071827d..bc2f251767f2 100644 --- a/packages/grafana-prometheus/src/result_transformer.test.ts +++ b/packages/grafana-prometheus/src/result_transformer.test.ts @@ -935,7 +935,7 @@ describe('Prometheus Result Transformer', () => { it('should convert values less than 1e-9 to 0', () => { // pulled from real response - let bucketValues = [ + const bucketValues = [ [0.22222222222222218, 0.24444444444444444, 0.19999999999999996], // le=0.005 [0.39999999999999997, 0.44444444444444436, 0.42222222222222217], [0.3999999999999999, 0.44444444444444436, 0.42222222222222217], diff --git a/public/app/plugins/datasource/prometheus/result_transformer.test.ts b/public/app/plugins/datasource/prometheus/result_transformer.test.ts index 045add80b2cc..93c4d2b37acc 100644 --- a/public/app/plugins/datasource/prometheus/result_transformer.test.ts +++ b/public/app/plugins/datasource/prometheus/result_transformer.test.ts @@ -930,7 +930,7 @@ describe('Prometheus Result Transformer', () => { it('should convert values less than 1e-9 to 0', () => { // pulled from real response - let bucketValues = [ + const bucketValues = [ [0.22222222222222218, 0.24444444444444444, 0.19999999999999996], // le=0.005 [0.39999999999999997, 0.44444444444444436, 0.42222222222222217], [0.3999999999999999, 0.44444444444444436, 0.42222222222222217],