198 lines
5.7 KiB
TypeScript
198 lines
5.7 KiB
TypeScript
import { uniq } from 'lodash';
|
|
|
|
import { TraceqlFilter, TraceqlSearchScope } from '../dataquery.gen';
|
|
import { TempoDatasource } from '../datasource';
|
|
import TempoLanguageProvider from '../language_provider';
|
|
|
|
import {
|
|
filterToQuerySection,
|
|
generateQueryFromAdHocFilters,
|
|
getAllTags,
|
|
getFilteredTags,
|
|
getTagsByScope,
|
|
getUnscopedTags,
|
|
} from './utils';
|
|
|
|
const datasource: TempoDatasource = {
|
|
search: {
|
|
filters: [],
|
|
},
|
|
} as unknown as TempoDatasource;
|
|
const lp = new TempoLanguageProvider(datasource);
|
|
|
|
describe('generateQueryFromAdHocFilters generates the correct query for', () => {
|
|
it('an empty array', () => {
|
|
expect(generateQueryFromAdHocFilters([], lp)).toBe('{}');
|
|
});
|
|
|
|
it('a filter with values', () => {
|
|
expect(generateQueryFromAdHocFilters([{ key: 'footag', operator: '=', value: 'foovalue' }], lp)).toBe(
|
|
'{footag="foovalue"}'
|
|
);
|
|
});
|
|
|
|
it('two filters with values', () => {
|
|
expect(
|
|
generateQueryFromAdHocFilters(
|
|
[
|
|
{ key: 'footag', operator: '=', value: 'foovalue' },
|
|
{ key: 'bartag', operator: '=', value: '0' },
|
|
],
|
|
lp
|
|
)
|
|
).toBe('{footag="foovalue" && bartag=0}');
|
|
});
|
|
|
|
it('a filter with intrinsic values', () => {
|
|
expect(generateQueryFromAdHocFilters([{ key: 'kind', operator: '=', value: 'server' }], lp)).toBe('{kind=server}');
|
|
});
|
|
});
|
|
|
|
describe('gets correct tags', () => {
|
|
const datasource: TempoDatasource = {
|
|
search: {
|
|
filters: [],
|
|
},
|
|
} as unknown as TempoDatasource;
|
|
const lp = new TempoLanguageProvider(datasource);
|
|
|
|
it('for filtered tags when no tags supplied', () => {
|
|
const tags = getFilteredTags(emptyTags, []);
|
|
expect(tags).toEqual([]);
|
|
});
|
|
|
|
it('for filtered tags when API v1 tags supplied', () => {
|
|
const tags = getFilteredTags(v1Tags, []);
|
|
expect(tags).toEqual(['bar', 'foo']);
|
|
});
|
|
|
|
it('for filtered tags when API v1 tags supplied with tags to filter out', () => {
|
|
const tags = getFilteredTags(v1Tags, ['foo']);
|
|
expect(tags).toEqual(['bar']);
|
|
});
|
|
|
|
it('for filtered tags when API v2 tags supplied', () => {
|
|
const tags = getFilteredTags(uniq(getUnscopedTags(v2Tags)), []);
|
|
expect(tags).toEqual(['cluster', 'container', 'db']);
|
|
});
|
|
|
|
it('for filtered tags when API v2 tags supplied with tags to filter out', () => {
|
|
const tags = getFilteredTags(getUnscopedTags(v2Tags), ['cluster']);
|
|
expect(tags).toEqual(['container', 'db']);
|
|
});
|
|
|
|
it('for filtered tags when API v2 tags set', () => {
|
|
lp.setV2Tags(v2Tags);
|
|
const tags = getFilteredTags(uniq(getUnscopedTags(v2Tags)), []);
|
|
expect(tags).toEqual(['cluster', 'container', 'db']);
|
|
});
|
|
|
|
it('for unscoped tags', () => {
|
|
const tags = getUnscopedTags(v2Tags);
|
|
expect(tags).toEqual(['cluster', 'container', 'db']);
|
|
});
|
|
|
|
it('for all tags', () => {
|
|
const tags = getAllTags(v2Tags);
|
|
expect(tags).toEqual(['cluster', 'container', 'db', 'duration', 'kind', 'name', 'status']);
|
|
});
|
|
|
|
it('for tags by resource scope', () => {
|
|
const tags = getTagsByScope(v2Tags, TraceqlSearchScope.Resource);
|
|
expect(tags).toEqual(['cluster', 'container']);
|
|
});
|
|
|
|
it('for tags by span scope', () => {
|
|
const tags = getTagsByScope(v2Tags, TraceqlSearchScope.Span);
|
|
expect(tags).toEqual(['db']);
|
|
});
|
|
});
|
|
|
|
describe('filterToQuerySection returns the correct query section for a filter', () => {
|
|
it('filter with single value', () => {
|
|
const filter: TraceqlFilter = { id: 'abc', tag: 'foo', operator: '=', value: 'bar' };
|
|
const result = filterToQuerySection(filter, [], lp);
|
|
expect(result).toBe('.foo=bar');
|
|
});
|
|
|
|
it('filter with regex operator', () => {
|
|
const filter: TraceqlFilter = { id: 'abc', tag: 'foo', operator: '=~', value: 'bar.*', valueType: 'string' };
|
|
const result = filterToQuerySection(filter, [], lp);
|
|
expect(result).toBe('.foo=~"bar.*"');
|
|
});
|
|
|
|
it('filter with scope', () => {
|
|
const filter: TraceqlFilter = {
|
|
id: 'abc',
|
|
tag: 'foo',
|
|
operator: '=',
|
|
value: 'bar',
|
|
scope: TraceqlSearchScope.Resource,
|
|
};
|
|
const result = filterToQuerySection(filter, [], lp);
|
|
expect(result).toBe('resource.foo=bar');
|
|
});
|
|
|
|
it('filter with intrinsic tag', () => {
|
|
const filter: TraceqlFilter = { id: 'abc', tag: 'duration', operator: '=', value: '100ms' };
|
|
const result = filterToQuerySection(filter, [], lp);
|
|
expect(result).toBe('duration=100ms');
|
|
});
|
|
|
|
it('filter with multiple non-string values and scope', () => {
|
|
const filter: TraceqlFilter = {
|
|
id: 'abc',
|
|
tag: 'foo',
|
|
operator: '=',
|
|
value: ['bar', 'baz'],
|
|
scope: TraceqlSearchScope.Span,
|
|
};
|
|
const result = filterToQuerySection(filter, [], lp);
|
|
expect(result).toBe('(span.foo=bar || span.foo=baz)');
|
|
});
|
|
|
|
it('filter with multiple string values and scope', () => {
|
|
const filter: TraceqlFilter = {
|
|
id: 'abc',
|
|
tag: 'foo',
|
|
operator: '=',
|
|
value: ['bar', 'baz'],
|
|
scope: TraceqlSearchScope.Span,
|
|
valueType: 'string',
|
|
};
|
|
const result = filterToQuerySection(filter, [], lp);
|
|
expect(result).toBe('(span.foo="bar" || span.foo="baz")');
|
|
});
|
|
|
|
it('filter with multiple string values with regex', () => {
|
|
const filter: TraceqlFilter = {
|
|
id: 'abc',
|
|
tag: 'foo',
|
|
operator: '=~',
|
|
value: ['bar', 'baz'],
|
|
scope: TraceqlSearchScope.Span,
|
|
valueType: 'string',
|
|
};
|
|
const result = filterToQuerySection(filter, [], lp);
|
|
expect(result).toBe('span.foo=~"bar|baz"');
|
|
});
|
|
});
|
|
|
|
export const emptyTags = [];
|
|
export const testIntrinsics = ['duration', 'kind', 'name', 'status'];
|
|
export const v1Tags = ['bar', 'foo'];
|
|
export const v2Tags = [
|
|
{
|
|
name: 'resource',
|
|
tags: ['cluster', 'container'],
|
|
},
|
|
{
|
|
name: 'span',
|
|
tags: ['db'],
|
|
},
|
|
{
|
|
name: 'intrinsic',
|
|
tags: testIntrinsics,
|
|
},
|
|
];
|