import { cloneDeep } from 'lodash'; import { DataFrame, FieldType } from '@grafana/data'; import { dataFrameHasLevelLabel, dataFrameHasLokiError, extractLevelLikeLabelFromDataFrame, extractLogParserFromDataFrame, extractLabelKeysFromDataFrame, extractUnwrapLabelKeysFromDataFrame, } from './responseUtils'; import { LabelType } from './types'; const frame: DataFrame = { length: 1, fields: [ { name: 'Time', config: {}, type: FieldType.time, values: [1], }, { name: 'labels', config: {}, type: FieldType.other, values: [{ level: 'info' }], }, { name: 'Line', config: {}, type: FieldType.string, values: ['line1'], }, ], }; const frameWithTypes: DataFrame = { length: 1, fields: [ { name: 'Time', config: {}, type: FieldType.time, values: [1], }, { name: 'labels', config: {}, type: FieldType.other, values: [{ level: 'info', structured: 'foo' }], }, { name: 'Line', config: {}, type: FieldType.string, values: ['line1'], }, { name: 'labelTypes', config: {}, type: FieldType.other, values: [{ level: 'I', structured: 'S' }], }, ], }; const frameWithMultipleLabels: DataFrame = { length: 1, fields: [ { name: 'Time', config: {}, type: FieldType.time, values: [1, 2, 3], }, { name: 'labels', config: {}, type: FieldType.other, values: [ { level: 'info', foo: 'bar' }, { level: 'info', foo: 'baz', new: 'yes' }, { level: 'error', foo: 'baz' }, ], }, { name: 'Line', config: {}, type: FieldType.string, values: ['line1', 'line2', 'line3'], }, ], }; describe('dataFrameHasParsingError', () => { it('handles frame with parsing error', () => { const input = cloneDeep(frame); input.fields[1].values = [{ level: 'info', __error__: 'error' }]; expect(dataFrameHasLokiError(input)).toBe(true); }); it('handles frame without parsing error', () => { const input = cloneDeep(frame); expect(dataFrameHasLokiError(input)).toBe(false); }); }); describe('dataFrameHasLevelLabel', () => { it('returns true if level label is present', () => { const input = cloneDeep(frame); input.fields[1].values = [{ level: 'info' }]; expect(dataFrameHasLevelLabel(input)).toBe(true); }); it('returns false if level label is present', () => { const input = cloneDeep(frame); input.fields[1].values = [{ foo: 'bar' }]; expect(dataFrameHasLevelLabel(input)).toBe(false); }); }); describe('extractLevelLikeLabelFromDataFrame', () => { it('returns label if lvl label is present', () => { const input = cloneDeep(frame); input.fields[1].values = [{ lvl: 'info' }]; expect(extractLevelLikeLabelFromDataFrame(input)).toBe('lvl'); }); it('returns label if level-like label is present', () => { const input = cloneDeep(frame); input.fields[1].values = [{ error_level: 'info' }]; expect(extractLevelLikeLabelFromDataFrame(input)).toBe('error_level'); }); it('returns label if detected_level label is present', () => { const input = cloneDeep(frame); input.fields[1].values = [{ detected_level: 'info' }]; expect(extractLevelLikeLabelFromDataFrame(input)).toBe('detected_level'); }); it('returns undefined if no level-like label is present', () => { const input = cloneDeep(frame); input.fields[1].values = [{ foo: 'info' }]; expect(extractLevelLikeLabelFromDataFrame(input)).toBe(null); }); }); describe('extractLogParserFromDataFrame', () => { it('returns false by default', () => { const input = cloneDeep(frame); expect(extractLogParserFromDataFrame(input)).toEqual({ hasJSON: false, hasLogfmt: false, hasPack: false }); }); it('identifies JSON', () => { const input = cloneDeep(frame); input.fields[2].values = ['{"a":"b"}']; expect(extractLogParserFromDataFrame(input)).toEqual({ hasJSON: true, hasLogfmt: false, hasPack: false }); }); it('identifies logfmt', () => { const input = cloneDeep(frame); input.fields[2].values = ['a=b']; expect(extractLogParserFromDataFrame(input)).toEqual({ hasJSON: false, hasLogfmt: true, hasPack: false }); }); }); describe('extractLabelKeysFromDataFrame', () => { it('returns empty by default', () => { const input = cloneDeep(frame); input.fields[1].values = []; expect(extractLabelKeysFromDataFrame(input)).toEqual([]); }); it('extracts label keys', () => { const input = cloneDeep(frame); expect(extractLabelKeysFromDataFrame(input)).toEqual(['level']); }); it('extracts label keys from all logs', () => { const input = cloneDeep(frameWithMultipleLabels); expect(extractLabelKeysFromDataFrame(input)).toEqual(['level', 'foo', 'new']); }); it('extracts indexed label keys', () => { const input = cloneDeep(frameWithTypes); expect(extractLabelKeysFromDataFrame(input)).toEqual(['level']); }); it('extracts structured metadata label keys', () => { const input = cloneDeep(frameWithTypes); expect(extractLabelKeysFromDataFrame(input, LabelType.StructuredMetadata)).toEqual(['structured']); }); it('does not extract structured metadata label keys from non-typed frame', () => { const input = cloneDeep(frame); expect(extractLabelKeysFromDataFrame(input, LabelType.StructuredMetadata)).toEqual([]); }); }); describe('extractUnwrapLabelKeysFromDataFrame', () => { it('returns empty by default', () => { const input = cloneDeep(frame); input.fields[1].values = []; expect(extractUnwrapLabelKeysFromDataFrame(input)).toEqual([]); }); it('extracts possible unwrap label keys', () => { const input = cloneDeep(frame); input.fields[1].values = [{ number: 13 }]; expect(extractUnwrapLabelKeysFromDataFrame(input)).toEqual(['number']); }); });