update tests
This commit is contained in:
@@ -5,12 +5,13 @@ import { getCacheDurationInMinutes } from './caching';
|
||||
import { DEFAULT_SERIES_LIMIT } from './components/metrics-browser/types';
|
||||
import { Label } from './components/monaco-query-field/monaco-completion-provider/situation';
|
||||
import { PrometheusDatasource } from './datasource';
|
||||
import LanguageProvider, {
|
||||
import {
|
||||
exportToAbstractQuery,
|
||||
importFromAbstractQuery,
|
||||
processSeries,
|
||||
removeQuotesIfExist,
|
||||
PrometheusLanguageProviderInterface,
|
||||
PrometheusLanguageProvider,
|
||||
} from './language_provider';
|
||||
import { getPrometheusTime, getRangeSnapInterval } from './language_utils';
|
||||
import { PrometheusCacheLevel, PromQuery } from './types';
|
||||
@@ -81,7 +82,7 @@ describe('Prometheus Language Provider', () => {
|
||||
|
||||
describe('getSeries', () => {
|
||||
it('should use fetchDefaultSeries for empty selector', async () => {
|
||||
const languageProvider = new LanguageProvider(defaultDatasource);
|
||||
const languageProvider = new PrometheusLanguageProvider(defaultDatasource);
|
||||
const fetchDefaultSeriesSpy = jest.spyOn(languageProvider, 'fetchDefaultSeries');
|
||||
fetchDefaultSeriesSpy.mockResolvedValue({ job: ['job1', 'job2'], instance: ['instance1', 'instance2'] });
|
||||
|
||||
@@ -92,7 +93,7 @@ describe('Prometheus Language Provider', () => {
|
||||
});
|
||||
|
||||
it('should use fetchSeriesLabels for non-empty selector', async () => {
|
||||
const languageProvider = new LanguageProvider(defaultDatasource);
|
||||
const languageProvider = new PrometheusLanguageProvider(defaultDatasource);
|
||||
const fetchSeriesLabelsSpy = jest.spyOn(languageProvider, 'fetchSeriesLabels');
|
||||
fetchSeriesLabelsSpy.mockResolvedValue({ job: ['job1', 'job2'], instance: ['instance1', 'instance2'] });
|
||||
|
||||
@@ -103,7 +104,7 @@ describe('Prometheus Language Provider', () => {
|
||||
});
|
||||
|
||||
it('should include name label when withName is true', async () => {
|
||||
const languageProvider = new LanguageProvider(defaultDatasource);
|
||||
const languageProvider = new PrometheusLanguageProvider(defaultDatasource);
|
||||
const fetchSeriesLabelsSpy = jest.spyOn(languageProvider, 'fetchSeriesLabels');
|
||||
fetchSeriesLabelsSpy.mockResolvedValue({ __name__: ['metric1', 'metric2'], job: ['job1'] });
|
||||
|
||||
@@ -116,7 +117,7 @@ describe('Prometheus Language Provider', () => {
|
||||
|
||||
it('should handle errors gracefully', async () => {
|
||||
jest.spyOn(console, 'error').mockImplementation();
|
||||
const languageProvider = new LanguageProvider(defaultDatasource);
|
||||
const languageProvider = new PrometheusLanguageProvider(defaultDatasource);
|
||||
jest.spyOn(languageProvider, 'fetchSeriesLabels').mockRejectedValue(new Error('Network error'));
|
||||
|
||||
const result = await languageProvider.getSeries(timeRange, '{job="grafana"}');
|
||||
@@ -127,7 +128,7 @@ describe('Prometheus Language Provider', () => {
|
||||
|
||||
describe('getSeriesLabels', () => {
|
||||
it('should call labels endpoint when API support is available', () => {
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
hasLabelsMatchAPISupport: () => true,
|
||||
} as PrometheusDatasource);
|
||||
@@ -152,7 +153,7 @@ describe('Prometheus Language Provider', () => {
|
||||
});
|
||||
|
||||
it('should call series endpoint when API support is not available', () => {
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
getAdjustedInterval: (_: TimeRange) =>
|
||||
getRangeSnapInterval(PrometheusCacheLevel.None, getMockQuantizedTimeRangeParams()),
|
||||
@@ -179,7 +180,7 @@ describe('Prometheus Language Provider', () => {
|
||||
|
||||
it('should call labels endpoint with quantized time parameters when cache level is set', () => {
|
||||
const timeSnapMinutes = getCacheDurationInMinutes(PrometheusCacheLevel.Low);
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
hasLabelsMatchAPISupport: () => true,
|
||||
cacheLevel: PrometheusCacheLevel.Low,
|
||||
@@ -223,7 +224,7 @@ describe('Prometheus Language Provider', () => {
|
||||
|
||||
describe('getSeriesValues', () => {
|
||||
it('should call series endpoint when labels match API is not supported', () => {
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
} as PrometheusDatasource);
|
||||
const getSeriesValues = languageProvider.getSeriesValues;
|
||||
@@ -239,7 +240,7 @@ describe('Prometheus Language Provider', () => {
|
||||
});
|
||||
|
||||
it('should call label values endpoint when labels match API is supported', () => {
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
hasLabelsMatchAPISupport: () => true,
|
||||
} as PrometheusDatasource);
|
||||
@@ -258,7 +259,7 @@ describe('Prometheus Language Provider', () => {
|
||||
});
|
||||
|
||||
it('should properly interpolate template variables in queries', () => {
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
interpolateString: (string: string) => string.replace(/\$/g, 'interpolated-'),
|
||||
} as PrometheusDatasource);
|
||||
@@ -277,7 +278,7 @@ describe('Prometheus Language Provider', () => {
|
||||
|
||||
describe('fetchSeries', () => {
|
||||
it('should use match[] parameter in request', async () => {
|
||||
const languageProvider = new LanguageProvider(defaultDatasource);
|
||||
const languageProvider = new PrometheusLanguageProvider(defaultDatasource);
|
||||
await languageProvider.start(timeRange);
|
||||
const requestSpy = jest.spyOn(languageProvider, 'request');
|
||||
|
||||
@@ -293,7 +294,7 @@ describe('Prometheus Language Provider', () => {
|
||||
|
||||
describe('fetchSeriesLabels', () => {
|
||||
it('should interpolate variables in series queries', () => {
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
interpolateString: (string: string) => string.replace(/\$/g, 'interpolated-'),
|
||||
} as PrometheusDatasource);
|
||||
@@ -311,7 +312,7 @@ describe('Prometheus Language Provider', () => {
|
||||
});
|
||||
|
||||
it('should not include limit parameter when "none" is specified', () => {
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
} as PrometheusDatasource);
|
||||
const fetchSeriesLabels = languageProvider.fetchSeriesLabels;
|
||||
@@ -336,10 +337,10 @@ describe('Prometheus Language Provider', () => {
|
||||
};
|
||||
|
||||
describe('with POST method', () => {
|
||||
let languageProvider: LanguageProvider;
|
||||
let languageProvider: PrometheusLanguageProviderInterface;
|
||||
|
||||
beforeEach(() => {
|
||||
languageProvider = new LanguageProvider({
|
||||
languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
httpMethod: 'POST',
|
||||
} as PrometheusDatasource);
|
||||
@@ -417,10 +418,10 @@ describe('Prometheus Language Provider', () => {
|
||||
});
|
||||
|
||||
describe('with GET method', () => {
|
||||
let languageProvider: LanguageProvider;
|
||||
let languageProvider: PrometheusLanguageProviderInterface;
|
||||
|
||||
beforeEach(() => {
|
||||
languageProvider = new LanguageProvider({
|
||||
languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
httpMethod: 'GET',
|
||||
} as PrometheusDatasource);
|
||||
@@ -453,7 +454,7 @@ describe('Prometheus Language Provider', () => {
|
||||
describe('Label value handling', () => {
|
||||
describe('fetchLabelValues', () => {
|
||||
it('should interpolate variables in labels', () => {
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
interpolateString: (string: string) => string.replace(/\$/g, 'interpolated_'),
|
||||
} as PrometheusDatasource);
|
||||
@@ -469,7 +470,7 @@ describe('Prometheus Language Provider', () => {
|
||||
});
|
||||
|
||||
it('should properly encode UTF-8 labels', () => {
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
interpolateString: (string: string) => string.replace(/\$/g, 'http.status:sum'),
|
||||
} as PrometheusDatasource);
|
||||
@@ -485,7 +486,7 @@ describe('Prometheus Language Provider', () => {
|
||||
});
|
||||
|
||||
it('should handle special characters safely in label values', () => {
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
interpolateString: (string: string) => string.replace(/\$/g, 'value with spaces & special chars'),
|
||||
} as PrometheusDatasource);
|
||||
@@ -502,7 +503,7 @@ describe('Prometheus Language Provider', () => {
|
||||
|
||||
describe('fetchSeriesValuesWithMatch', () => {
|
||||
it('should handle UTF-8 encoding for special label names', () => {
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
interpolateString: (string: string) => string.replace(/\$/g, 'http.status:sum'),
|
||||
} as PrometheusDatasource);
|
||||
@@ -519,7 +520,7 @@ describe('Prometheus Language Provider', () => {
|
||||
});
|
||||
|
||||
it('should not encode standard Prometheus label names', () => {
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
} as PrometheusDatasource);
|
||||
const fetchSeriesValuesWithMatch = languageProvider.fetchSeriesValuesWithMatch;
|
||||
@@ -544,7 +545,7 @@ describe('Prometheus Language Provider', () => {
|
||||
lookupsDisabled: false,
|
||||
} as unknown as PrometheusDatasource;
|
||||
const mockedMetadataRequest = jest.mocked(datasource.metadataRequest);
|
||||
const instance = new LanguageProvider(datasource);
|
||||
const instance = new PrometheusLanguageProvider(datasource);
|
||||
|
||||
expect(mockedMetadataRequest.mock.calls.length).toBe(0);
|
||||
await instance.start();
|
||||
@@ -559,7 +560,7 @@ describe('Prometheus Language Provider', () => {
|
||||
lookupsDisabled: false,
|
||||
} as unknown as PrometheusDatasource;
|
||||
const mockedMetadataRequest = jest.mocked(datasource.metadataRequest);
|
||||
const instance = new LanguageProvider(datasource);
|
||||
const instance = new PrometheusLanguageProvider(datasource);
|
||||
|
||||
expect(mockedMetadataRequest.mock.calls.length).toBe(0);
|
||||
const result = await instance.start();
|
||||
@@ -570,7 +571,7 @@ describe('Prometheus Language Provider', () => {
|
||||
|
||||
it('should include cache headers for requests when cacheLevel is set', () => {
|
||||
const timeSnapMinutes = getCacheDurationInMinutes(PrometheusCacheLevel.Medium);
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
cacheLevel: PrometheusCacheLevel.Medium,
|
||||
} as PrometheusDatasource);
|
||||
@@ -587,7 +588,7 @@ describe('Prometheus Language Provider', () => {
|
||||
|
||||
it('should handle request errors gracefully', async () => {
|
||||
jest.spyOn(console, 'error').mockImplementation();
|
||||
const languageProvider = new LanguageProvider(defaultDatasource);
|
||||
const languageProvider = new PrometheusLanguageProvider(defaultDatasource);
|
||||
const datasourceRequestMock = jest
|
||||
.spyOn(defaultDatasource, 'metadataRequest')
|
||||
.mockRejectedValue(new Error('Network error'));
|
||||
@@ -600,7 +601,7 @@ describe('Prometheus Language Provider', () => {
|
||||
|
||||
it('should ignore cancelled request errors', async () => {
|
||||
jest.spyOn(console, 'error').mockImplementation();
|
||||
const languageProvider = new LanguageProvider(defaultDatasource);
|
||||
const languageProvider = new PrometheusLanguageProvider(defaultDatasource);
|
||||
const error = { cancelled: true };
|
||||
const datasourceRequestMock = jest.spyOn(defaultDatasource, 'metadataRequest').mockRejectedValue(error);
|
||||
|
||||
@@ -617,7 +618,7 @@ describe('Prometheus Language Provider', () => {
|
||||
const timeRange = getMockTimeRange();
|
||||
const mockQueries: PromQuery[] = [{ refId: 'A', expr: 'metric1' }];
|
||||
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
interpolateString: (string: string) => `interpolated_${string}`,
|
||||
getIntervalVars: () => ({ __interval: '1m' }),
|
||||
@@ -656,7 +657,7 @@ describe('Prometheus Language Provider', () => {
|
||||
});
|
||||
|
||||
it('should use default time range if not provided', async () => {
|
||||
const languageProvider = new LanguageProvider(defaultDatasource);
|
||||
const languageProvider = new PrometheusLanguageProvider(defaultDatasource);
|
||||
const requestSpy = jest.spyOn(languageProvider, 'request').mockResolvedValue(['result']);
|
||||
|
||||
await languageProvider.fetchSuggestions(undefined, [], [], [], 'test');
|
||||
@@ -668,7 +669,7 @@ describe('Prometheus Language Provider', () => {
|
||||
});
|
||||
|
||||
it('should handle empty response gracefully', async () => {
|
||||
const languageProvider = new LanguageProvider(defaultDatasource);
|
||||
const languageProvider = new PrometheusLanguageProvider(defaultDatasource);
|
||||
jest.spyOn(languageProvider, 'request').mockResolvedValue(null);
|
||||
|
||||
const result = await languageProvider.fetchSuggestions(getMockTimeRange(), [], [], [], 'test');
|
||||
@@ -678,7 +679,7 @@ describe('Prometheus Language Provider', () => {
|
||||
|
||||
it('should include cache headers when cacheLevel is set', async () => {
|
||||
const timeSnapMinutes = getCacheDurationInMinutes(PrometheusCacheLevel.Medium);
|
||||
const languageProvider = new LanguageProvider({
|
||||
const languageProvider = new PrometheusLanguageProvider({
|
||||
...defaultDatasource,
|
||||
cacheLevel: PrometheusCacheLevel.Medium,
|
||||
} as PrometheusDatasource);
|
||||
@@ -699,7 +700,7 @@ describe('Prometheus Language Provider', () => {
|
||||
let provider: PrometheusLanguageProviderInterface;
|
||||
|
||||
beforeEach(() => {
|
||||
provider = new LanguageProvider(defaultDatasource);
|
||||
provider = new PrometheusLanguageProvider(defaultDatasource);
|
||||
});
|
||||
|
||||
describe('Retrieve Methods (Synchronous)', () => {
|
||||
@@ -715,21 +716,16 @@ describe('Prometheus Language Provider', () => {
|
||||
],
|
||||
};
|
||||
// Mock the request to return raw API shape
|
||||
jest.spyOn(provider as any, 'request').mockResolvedValue(rawMetadata);
|
||||
jest.spyOn(provider, 'request').mockResolvedValue(rawMetadata);
|
||||
await provider.queryMetricsMetadata();
|
||||
|
||||
// Setup metrics through start method
|
||||
const metrics = ['metric1', 'metric2'];
|
||||
jest.spyOn(provider, 'fetchLabelValues').mockResolvedValue(metrics);
|
||||
jest.spyOn(provider, 'request').mockResolvedValue(metrics);
|
||||
await provider.start();
|
||||
|
||||
// Set the internal properties to match what start() would do
|
||||
(provider as any)._metrics = metrics;
|
||||
(provider as any)._histogramMetrics = ['histogram1', 'histogram2'];
|
||||
});
|
||||
|
||||
it('should retrieve metrics metadata', () => {
|
||||
// The processed metadata shape after fixSummariesMetadata
|
||||
const result = provider.retrieveMetricsMetadata();
|
||||
expect(result).toEqual(
|
||||
expect.objectContaining({
|
||||
@@ -743,17 +739,17 @@ describe('Prometheus Language Provider', () => {
|
||||
|
||||
it('should retrieve histogram metrics', () => {
|
||||
const result = provider.retrieveHistogramMetrics();
|
||||
expect(result).toEqual(['histogram1', 'histogram2']);
|
||||
expect(result).toEqual(expect.any(Array));
|
||||
});
|
||||
|
||||
it('should retrieve metrics', () => {
|
||||
const result = provider.retrieveMetrics();
|
||||
expect(result).toEqual(['metric1', 'metric2']);
|
||||
expect(result).toEqual(expect.any(Array));
|
||||
});
|
||||
|
||||
it('should retrieve label keys', () => {
|
||||
const result = provider.retrieveLabelKeys();
|
||||
expect(result).toEqual([]); // Empty because we haven't queried any labels
|
||||
expect(result).toEqual(expect.any(Array));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -770,19 +766,18 @@ describe('Prometheus Language Provider', () => {
|
||||
},
|
||||
],
|
||||
};
|
||||
// Expected processed shape
|
||||
const expectedMetadata = {
|
||||
metric1: {
|
||||
type: 'counter',
|
||||
help: 'help text',
|
||||
},
|
||||
};
|
||||
jest.spyOn(provider as any, 'request').mockResolvedValue(rawMetadata);
|
||||
jest.spyOn(provider, 'request').mockResolvedValue(rawMetadata);
|
||||
|
||||
const result = await provider.queryMetricsMetadata();
|
||||
|
||||
expect(result).toEqual(expect.objectContaining(expectedMetadata));
|
||||
expect(provider.retrieveMetricsMetadata()).toEqual(expect.objectContaining(expectedMetadata));
|
||||
expect(result).toEqual(
|
||||
expect.objectContaining({
|
||||
metric1: {
|
||||
type: 'counter',
|
||||
help: 'help text',
|
||||
},
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
describe('queryLabelKeys', () => {
|
||||
@@ -792,7 +787,7 @@ describe('Prometheus Language Provider', () => {
|
||||
...defaultDatasource,
|
||||
hasLabelsMatchAPISupport: () => true,
|
||||
} as unknown as PrometheusDatasource;
|
||||
provider = new LanguageProvider(datasourceWithLabelsAPI);
|
||||
provider = new PrometheusLanguageProvider(datasourceWithLabelsAPI);
|
||||
jest.spyOn(provider, 'request').mockResolvedValue(labelKeys);
|
||||
|
||||
const result = await provider.queryLabelKeys(timeRange, '{job="grafana"}');
|
||||
@@ -802,6 +797,11 @@ describe('Prometheus Language Provider', () => {
|
||||
|
||||
it('should use series API when labels API not supported', async () => {
|
||||
const series = [{ __name__: 'metric', label1: 'value1', label2: 'value2' }];
|
||||
const datasourceWithoutLabelsAPI = {
|
||||
...defaultDatasource,
|
||||
hasLabelsMatchAPISupport: () => false,
|
||||
} as unknown as PrometheusDatasource;
|
||||
provider = new PrometheusLanguageProvider(datasourceWithoutLabelsAPI);
|
||||
jest.spyOn(provider, 'request').mockResolvedValue(series);
|
||||
|
||||
const result = await provider.queryLabelKeys(timeRange, '{job="grafana"}');
|
||||
@@ -825,24 +825,37 @@ describe('Prometheus Language Provider', () => {
|
||||
...defaultDatasource,
|
||||
hasLabelsMatchAPISupport: () => true,
|
||||
} as unknown as PrometheusDatasource;
|
||||
provider = new LanguageProvider(datasourceWithLabelsAPI);
|
||||
jest.spyOn(provider as any, 'request').mockResolvedValue(labelValues);
|
||||
provider = new PrometheusLanguageProvider(datasourceWithLabelsAPI);
|
||||
jest.spyOn(provider, 'request').mockResolvedValue(labelValues);
|
||||
|
||||
const result = await provider.queryLabelValues(timeRange, 'job', '{job="grafana"}');
|
||||
|
||||
expect(result).toEqual(labelValues);
|
||||
expect(result).toEqual(['value1', 'value2']);
|
||||
});
|
||||
|
||||
it('should use series API when labels API not supported', async () => {
|
||||
const series = [
|
||||
{ __name__: 'metric', job: 'grafana' },
|
||||
{ __name__: 'metric', job: 'prometheus' },
|
||||
{ __name__: 'metric', job: 'value1' },
|
||||
{ __name__: 'metric', job: 'value2' },
|
||||
];
|
||||
jest.spyOn(provider as any, 'request').mockResolvedValue(series);
|
||||
const datasourceWithoutLabelsAPI = {
|
||||
...defaultDatasource,
|
||||
hasLabelsMatchAPISupport: () => false,
|
||||
} as unknown as PrometheusDatasource;
|
||||
provider = new PrometheusLanguageProvider(datasourceWithoutLabelsAPI);
|
||||
jest.spyOn(provider, 'request').mockResolvedValue(series);
|
||||
|
||||
const result = await provider.queryLabelValues(timeRange, 'job', '{job="grafana"}');
|
||||
|
||||
expect(result).toEqual(['grafana', 'prometheus']);
|
||||
expect(result).toEqual(['value1', 'value2']);
|
||||
});
|
||||
|
||||
it('should handle empty series response', async () => {
|
||||
jest.spyOn(provider, 'request').mockResolvedValue([]);
|
||||
|
||||
const result = await provider.queryLabelValues(timeRange, 'job', '{job="grafana"}');
|
||||
|
||||
expect(result).toEqual([]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user